@onekeyfe/hwk-adapter-core 1.1.26-alpha.100 → 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
@@ -20,7 +20,18 @@ declare enum HardwareErrorCode {
20
20
  WrongApp = 5540,
21
21
  DeviceMismatch = 5560,
22
22
  BridgeNotFound = 5550,
23
- TransportNotAvailable = 5551
23
+ TransportNotAvailable = 5551,
24
+ /** 0x6a80 Invalid data — observed on blindSignTransactionFallback when the
25
+ * user has not enabled Blind signing on the device. */
26
+ EvmBlindSigningRequired = 7001,
27
+ /** 0x6984 Plugin not installed */
28
+ EvmClearSignPluginMissing = 7002,
29
+ /** 0x6a84 Insufficient memory (typical on Nano S with large calldata) */
30
+ EvmDataTooLarge = 7003,
31
+ /** 0x6501 TransactionType not supported (app too old for EIP-1559 / blob / 7702) */
32
+ EvmTxTypeNotSupported = 7004,
33
+ /** 0x911c Command code not supported — app predates current SDK */
34
+ AppTooOld = 7005
24
35
  }
25
36
 
26
37
  interface Success<T> {
@@ -32,11 +43,12 @@ interface Failure {
32
43
  payload: {
33
44
  error: string;
34
45
  code: HardwareErrorCode;
46
+ appName?: string;
35
47
  };
36
48
  }
37
49
  type Response<T> = Success<T> | Failure;
38
50
  declare function success<T>(payload: T): Success<T>;
39
- declare function failure(code: HardwareErrorCode, error: string): Failure;
51
+ declare function failure(code: HardwareErrorCode, error: string, appName?: string): Failure;
40
52
 
41
53
  type VendorType = 'trezor' | 'ledger' | 'keystone' | 'keystoneqr';
42
54
  type ConnectionType = 'usb' | 'ble' | 'qr';
@@ -212,6 +224,8 @@ interface BtcSignTxParams {
212
224
  coin: string;
213
225
  locktime?: number;
214
226
  version?: number;
227
+ /** Account-level derivation path (e.g. "84'/0'/0'") for wallet template. */
228
+ path?: string;
215
229
  }
216
230
  interface BtcTxInput {
217
231
  path: string;
@@ -248,6 +262,15 @@ interface BtcSignedTx {
248
262
  txid?: string;
249
263
  signedPsbt?: string;
250
264
  }
265
+ interface BtcSignPsbtParams {
266
+ psbt: string;
267
+ coin?: string;
268
+ /** Account-level derivation path (e.g. "84'/0'/0'") for wallet template. */
269
+ path?: string;
270
+ }
271
+ interface BtcSignedPsbt {
272
+ signedPsbt: string;
273
+ }
251
274
  interface BtcSignMsgParams {
252
275
  path: string;
253
276
  message: string;
@@ -262,6 +285,7 @@ interface IBtcMethods {
262
285
  btcGetAddresses(connectId: string, deviceId: string, params: BtcGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<BtcAddress[]>>;
263
286
  btcGetPublicKey(connectId: string, deviceId: string, params: BtcGetPublicKeyParams): Promise<Response<BtcPublicKey>>;
264
287
  btcSignTransaction(connectId: string, deviceId: string, params: BtcSignTxParams): Promise<Response<BtcSignedTx>>;
288
+ btcSignPsbt(connectId: string, deviceId: string, params: BtcSignPsbtParams): Promise<Response<BtcSignedPsbt>>;
265
289
  btcSignMessage(connectId: string, deviceId: string, params: BtcSignMsgParams): Promise<Response<BtcSignature>>;
266
290
  btcGetMasterFingerprint(connectId: string, deviceId: string): Promise<Response<{
267
291
  masterFingerprint: string;
@@ -425,8 +449,39 @@ declare const UI_RESPONSE: {
425
449
  readonly RECEIVE_PASSPHRASE_ON_DEVICE: "receive-passphrase-on-device";
426
450
  readonly RECEIVE_QR_RESPONSE: "receive-qr-response";
427
451
  readonly RECEIVE_SELECT_DEVICE: "receive-select-device";
452
+ readonly RECEIVE_DEVICE_CONNECT: "receive-device-connect";
428
453
  readonly CANCEL: "cancel";
429
454
  };
455
+ type UiResponseEvent = {
456
+ type: typeof UI_RESPONSE.RECEIVE_PIN;
457
+ payload: string;
458
+ } | {
459
+ type: typeof UI_RESPONSE.RECEIVE_PASSPHRASE;
460
+ payload: {
461
+ value: string;
462
+ passphraseOnDevice?: boolean;
463
+ save?: boolean;
464
+ };
465
+ } | {
466
+ type: typeof UI_RESPONSE.RECEIVE_PASSPHRASE_ON_DEVICE;
467
+ payload?: undefined;
468
+ } | {
469
+ type: typeof UI_RESPONSE.RECEIVE_QR_RESPONSE;
470
+ payload: QrResponseData;
471
+ } | {
472
+ type: typeof UI_RESPONSE.RECEIVE_SELECT_DEVICE;
473
+ payload: {
474
+ sdkConnectId: string;
475
+ };
476
+ } | {
477
+ type: typeof UI_RESPONSE.RECEIVE_DEVICE_CONNECT;
478
+ payload: {
479
+ confirmed: boolean;
480
+ };
481
+ } | {
482
+ type: typeof UI_RESPONSE.CANCEL;
483
+ payload?: undefined;
484
+ };
430
485
 
431
486
  /** Events generated by SDK internal detection (not from hardware directly). */
432
487
  declare const SDK: {
@@ -637,15 +692,13 @@ interface HardwareEventMap {
637
692
  };
638
693
  }
639
694
  /**
640
- * UI handler for interactive request-response flows.
641
- * Adapters call these when they need user input (PIN, passphrase, QR scan).
642
- * Pure notifications (button confirm, progress) go through events instead.
695
+ * Same-process callbacks for prompts and OS-level permission.
696
+ * Cross-process flows use events + `uiResponse` + `UiRequestRegistry` instead.
643
697
  */
644
698
  interface IUiHandler {
645
699
  onPinRequest(device: DeviceInfo): Promise<string>;
646
700
  onPassphraseRequest(device: DeviceInfo): Promise<string | PassphraseResponse>;
647
701
  onQrDisplay(device: DeviceInfo, data: QrDisplayData): Promise<QrResponseData>;
648
- onSelectDevice(devices: DeviceInfo[]): Promise<string>;
649
702
  /**
650
703
  * Check if device access permission is already granted.
651
704
  * Returns { granted, context? }.
@@ -692,12 +745,8 @@ interface IHardwareWallet<TConfig = unknown> extends IEvmMethods, IBtcMethods, I
692
745
  getDeviceInfo(connectId: string, deviceId: string): Promise<Response<DeviceInfo>>;
693
746
  getSupportedChains(): ChainCapability[];
694
747
  cancel(connectId: string): void;
695
- /**
696
- * Respond to a ui-request-device-connect event.
697
- * Call with 'confirm' after the user connects/unlocks the device to retry,
698
- * or 'cancel' to abort the operation.
699
- */
700
- deviceConnectResponse(type: 'confirm' | 'cancel'): void;
748
+ /** Respond to any pending `ui-request-*`. */
749
+ uiResponse(response: UiResponseEvent): void;
701
750
  /**
702
751
  * Derive a chain-specific fingerprint for the connected device.
703
752
  *
@@ -886,10 +935,7 @@ interface IConnector {
886
935
  call(sessionId: string, method: string, params: unknown): Promise<unknown>;
887
936
  cancel(sessionId: string): Promise<void>;
888
937
  /** Send a UI response (e.g. PIN, passphrase) to the device. */
889
- uiResponse(response: {
890
- type: string;
891
- payload: unknown;
892
- }): void;
938
+ uiResponse(response: UiResponseEvent): void;
893
939
  on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
894
940
  off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
895
941
  reset(): void;
@@ -918,10 +964,7 @@ interface IHardwareBridge {
918
964
  }): Promise<void>;
919
965
  uiResponse(params: {
920
966
  vendor: VendorType;
921
- response: {
922
- type: string;
923
- payload: unknown;
924
- };
967
+ response: UiResponseEvent;
925
968
  }): void;
926
969
  reset(params: {
927
970
  vendor: VendorType;
@@ -975,6 +1018,27 @@ declare class TypedEventEmitter<TMap extends Record<string, any> = Record<string
975
1018
  removeAllListeners(): void;
976
1019
  }
977
1020
 
1021
+ /** 10 min — every UI request is human-in-the-loop; bias toward "wait long". */
1022
+ declare const UI_REQUEST_DEFAULT_TIMEOUT_MS = 600000;
1023
+ declare const UI_REQUEST_PREEMPTED_TAG = "UiRequestPreempted";
1024
+ declare const UI_REQUEST_CANCELLED_TAG = "UiRequestCancelled";
1025
+ declare const UI_REQUEST_TIMEOUT_TAG = "UiRequestTimeout";
1026
+ /**
1027
+ * Per-type single-slot registry for adapter-level UI requests. A new `wait`
1028
+ * of the same type preempts (rejects) the prior one. Unknown response types
1029
+ * are dropped silently so the public `uiResponse` entry never throws.
1030
+ */
1031
+ declare class UiRequestRegistry {
1032
+ private pending;
1033
+ wait<T = unknown>(requestType: string, options?: {
1034
+ timeoutMs?: number;
1035
+ }): Promise<T>;
1036
+ resolve(responseType: string, payload: unknown): void;
1037
+ cancel(requestType?: string): void;
1038
+ reset(): void;
1039
+ hasPending(requestType: string): boolean;
1040
+ }
1041
+
978
1042
  /**
979
1043
  * Compare two semver strings (e.g. "2.1.0" vs "2.3.1").
980
1044
  * Returns -1 if a < b, 0 if equal, 1 if a > b.
@@ -1007,4 +1071,4 @@ declare function batchCall<TParam, TResult>(params: TParam[], callFn: (p: TParam
1007
1071
  total: number;
1008
1072
  }) => void): Promise<Response<TResult[]>>;
1009
1073
 
1010
- export { type ActiveJobInfo, type BtcAddress, type BtcGetAddressParams, type BtcGetPublicKeyParams, type BtcPublicKey, type BtcRefTransaction, type BtcSignMsgParams, type BtcSignTxParams, type BtcSignature, 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 DeviceTarget, EConnectorInteraction, type EIP712Domain, type EvmAddress, type EvmGetAddressParams, type EvmGetPublicKeyParams, type EvmPublicKey, 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 IUiBridge, type IUiHandler, 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 SolGetPublicKeyParams, type SolPublicKey, 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_RESPONSE, type UiRequestEvent, type VendorType, batchCall, bytesToHex, compareSemver, createBridgedConnector, deriveDeviceFingerprint, enrichErrorMessage, ensure0x, failure, hexToBytes, padHex64, stripHex, success };
1074
+ 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 DeviceTarget, EConnectorInteraction, type EIP712Domain, type EvmAddress, type EvmGetAddressParams, type EvmGetPublicKeyParams, type EvmPublicKey, 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 IUiBridge, type IUiHandler, 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 SolGetPublicKeyParams, type SolPublicKey, 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 };
package/dist/index.d.ts CHANGED
@@ -20,7 +20,18 @@ declare enum HardwareErrorCode {
20
20
  WrongApp = 5540,
21
21
  DeviceMismatch = 5560,
22
22
  BridgeNotFound = 5550,
23
- TransportNotAvailable = 5551
23
+ TransportNotAvailable = 5551,
24
+ /** 0x6a80 Invalid data — observed on blindSignTransactionFallback when the
25
+ * user has not enabled Blind signing on the device. */
26
+ EvmBlindSigningRequired = 7001,
27
+ /** 0x6984 Plugin not installed */
28
+ EvmClearSignPluginMissing = 7002,
29
+ /** 0x6a84 Insufficient memory (typical on Nano S with large calldata) */
30
+ EvmDataTooLarge = 7003,
31
+ /** 0x6501 TransactionType not supported (app too old for EIP-1559 / blob / 7702) */
32
+ EvmTxTypeNotSupported = 7004,
33
+ /** 0x911c Command code not supported — app predates current SDK */
34
+ AppTooOld = 7005
24
35
  }
25
36
 
26
37
  interface Success<T> {
@@ -32,11 +43,12 @@ interface Failure {
32
43
  payload: {
33
44
  error: string;
34
45
  code: HardwareErrorCode;
46
+ appName?: string;
35
47
  };
36
48
  }
37
49
  type Response<T> = Success<T> | Failure;
38
50
  declare function success<T>(payload: T): Success<T>;
39
- declare function failure(code: HardwareErrorCode, error: string): Failure;
51
+ declare function failure(code: HardwareErrorCode, error: string, appName?: string): Failure;
40
52
 
41
53
  type VendorType = 'trezor' | 'ledger' | 'keystone' | 'keystoneqr';
42
54
  type ConnectionType = 'usb' | 'ble' | 'qr';
@@ -212,6 +224,8 @@ interface BtcSignTxParams {
212
224
  coin: string;
213
225
  locktime?: number;
214
226
  version?: number;
227
+ /** Account-level derivation path (e.g. "84'/0'/0'") for wallet template. */
228
+ path?: string;
215
229
  }
216
230
  interface BtcTxInput {
217
231
  path: string;
@@ -248,6 +262,15 @@ interface BtcSignedTx {
248
262
  txid?: string;
249
263
  signedPsbt?: string;
250
264
  }
265
+ interface BtcSignPsbtParams {
266
+ psbt: string;
267
+ coin?: string;
268
+ /** Account-level derivation path (e.g. "84'/0'/0'") for wallet template. */
269
+ path?: string;
270
+ }
271
+ interface BtcSignedPsbt {
272
+ signedPsbt: string;
273
+ }
251
274
  interface BtcSignMsgParams {
252
275
  path: string;
253
276
  message: string;
@@ -262,6 +285,7 @@ interface IBtcMethods {
262
285
  btcGetAddresses(connectId: string, deviceId: string, params: BtcGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<BtcAddress[]>>;
263
286
  btcGetPublicKey(connectId: string, deviceId: string, params: BtcGetPublicKeyParams): Promise<Response<BtcPublicKey>>;
264
287
  btcSignTransaction(connectId: string, deviceId: string, params: BtcSignTxParams): Promise<Response<BtcSignedTx>>;
288
+ btcSignPsbt(connectId: string, deviceId: string, params: BtcSignPsbtParams): Promise<Response<BtcSignedPsbt>>;
265
289
  btcSignMessage(connectId: string, deviceId: string, params: BtcSignMsgParams): Promise<Response<BtcSignature>>;
266
290
  btcGetMasterFingerprint(connectId: string, deviceId: string): Promise<Response<{
267
291
  masterFingerprint: string;
@@ -425,8 +449,39 @@ declare const UI_RESPONSE: {
425
449
  readonly RECEIVE_PASSPHRASE_ON_DEVICE: "receive-passphrase-on-device";
426
450
  readonly RECEIVE_QR_RESPONSE: "receive-qr-response";
427
451
  readonly RECEIVE_SELECT_DEVICE: "receive-select-device";
452
+ readonly RECEIVE_DEVICE_CONNECT: "receive-device-connect";
428
453
  readonly CANCEL: "cancel";
429
454
  };
455
+ type UiResponseEvent = {
456
+ type: typeof UI_RESPONSE.RECEIVE_PIN;
457
+ payload: string;
458
+ } | {
459
+ type: typeof UI_RESPONSE.RECEIVE_PASSPHRASE;
460
+ payload: {
461
+ value: string;
462
+ passphraseOnDevice?: boolean;
463
+ save?: boolean;
464
+ };
465
+ } | {
466
+ type: typeof UI_RESPONSE.RECEIVE_PASSPHRASE_ON_DEVICE;
467
+ payload?: undefined;
468
+ } | {
469
+ type: typeof UI_RESPONSE.RECEIVE_QR_RESPONSE;
470
+ payload: QrResponseData;
471
+ } | {
472
+ type: typeof UI_RESPONSE.RECEIVE_SELECT_DEVICE;
473
+ payload: {
474
+ sdkConnectId: string;
475
+ };
476
+ } | {
477
+ type: typeof UI_RESPONSE.RECEIVE_DEVICE_CONNECT;
478
+ payload: {
479
+ confirmed: boolean;
480
+ };
481
+ } | {
482
+ type: typeof UI_RESPONSE.CANCEL;
483
+ payload?: undefined;
484
+ };
430
485
 
431
486
  /** Events generated by SDK internal detection (not from hardware directly). */
432
487
  declare const SDK: {
@@ -637,15 +692,13 @@ interface HardwareEventMap {
637
692
  };
638
693
  }
639
694
  /**
640
- * UI handler for interactive request-response flows.
641
- * Adapters call these when they need user input (PIN, passphrase, QR scan).
642
- * Pure notifications (button confirm, progress) go through events instead.
695
+ * Same-process callbacks for prompts and OS-level permission.
696
+ * Cross-process flows use events + `uiResponse` + `UiRequestRegistry` instead.
643
697
  */
644
698
  interface IUiHandler {
645
699
  onPinRequest(device: DeviceInfo): Promise<string>;
646
700
  onPassphraseRequest(device: DeviceInfo): Promise<string | PassphraseResponse>;
647
701
  onQrDisplay(device: DeviceInfo, data: QrDisplayData): Promise<QrResponseData>;
648
- onSelectDevice(devices: DeviceInfo[]): Promise<string>;
649
702
  /**
650
703
  * Check if device access permission is already granted.
651
704
  * Returns { granted, context? }.
@@ -692,12 +745,8 @@ interface IHardwareWallet<TConfig = unknown> extends IEvmMethods, IBtcMethods, I
692
745
  getDeviceInfo(connectId: string, deviceId: string): Promise<Response<DeviceInfo>>;
693
746
  getSupportedChains(): ChainCapability[];
694
747
  cancel(connectId: string): void;
695
- /**
696
- * Respond to a ui-request-device-connect event.
697
- * Call with 'confirm' after the user connects/unlocks the device to retry,
698
- * or 'cancel' to abort the operation.
699
- */
700
- deviceConnectResponse(type: 'confirm' | 'cancel'): void;
748
+ /** Respond to any pending `ui-request-*`. */
749
+ uiResponse(response: UiResponseEvent): void;
701
750
  /**
702
751
  * Derive a chain-specific fingerprint for the connected device.
703
752
  *
@@ -886,10 +935,7 @@ interface IConnector {
886
935
  call(sessionId: string, method: string, params: unknown): Promise<unknown>;
887
936
  cancel(sessionId: string): Promise<void>;
888
937
  /** Send a UI response (e.g. PIN, passphrase) to the device. */
889
- uiResponse(response: {
890
- type: string;
891
- payload: unknown;
892
- }): void;
938
+ uiResponse(response: UiResponseEvent): void;
893
939
  on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
894
940
  off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
895
941
  reset(): void;
@@ -918,10 +964,7 @@ interface IHardwareBridge {
918
964
  }): Promise<void>;
919
965
  uiResponse(params: {
920
966
  vendor: VendorType;
921
- response: {
922
- type: string;
923
- payload: unknown;
924
- };
967
+ response: UiResponseEvent;
925
968
  }): void;
926
969
  reset(params: {
927
970
  vendor: VendorType;
@@ -975,6 +1018,27 @@ declare class TypedEventEmitter<TMap extends Record<string, any> = Record<string
975
1018
  removeAllListeners(): void;
976
1019
  }
977
1020
 
1021
+ /** 10 min — every UI request is human-in-the-loop; bias toward "wait long". */
1022
+ declare const UI_REQUEST_DEFAULT_TIMEOUT_MS = 600000;
1023
+ declare const UI_REQUEST_PREEMPTED_TAG = "UiRequestPreempted";
1024
+ declare const UI_REQUEST_CANCELLED_TAG = "UiRequestCancelled";
1025
+ declare const UI_REQUEST_TIMEOUT_TAG = "UiRequestTimeout";
1026
+ /**
1027
+ * Per-type single-slot registry for adapter-level UI requests. A new `wait`
1028
+ * of the same type preempts (rejects) the prior one. Unknown response types
1029
+ * are dropped silently so the public `uiResponse` entry never throws.
1030
+ */
1031
+ declare class UiRequestRegistry {
1032
+ private pending;
1033
+ wait<T = unknown>(requestType: string, options?: {
1034
+ timeoutMs?: number;
1035
+ }): Promise<T>;
1036
+ resolve(responseType: string, payload: unknown): void;
1037
+ cancel(requestType?: string): void;
1038
+ reset(): void;
1039
+ hasPending(requestType: string): boolean;
1040
+ }
1041
+
978
1042
  /**
979
1043
  * Compare two semver strings (e.g. "2.1.0" vs "2.3.1").
980
1044
  * Returns -1 if a < b, 0 if equal, 1 if a > b.
@@ -1007,4 +1071,4 @@ declare function batchCall<TParam, TResult>(params: TParam[], callFn: (p: TParam
1007
1071
  total: number;
1008
1072
  }) => void): Promise<Response<TResult[]>>;
1009
1073
 
1010
- export { type ActiveJobInfo, type BtcAddress, type BtcGetAddressParams, type BtcGetPublicKeyParams, type BtcPublicKey, type BtcRefTransaction, type BtcSignMsgParams, type BtcSignTxParams, type BtcSignature, 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 DeviceTarget, EConnectorInteraction, type EIP712Domain, type EvmAddress, type EvmGetAddressParams, type EvmGetPublicKeyParams, type EvmPublicKey, 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 IUiBridge, type IUiHandler, 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 SolGetPublicKeyParams, type SolPublicKey, 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_RESPONSE, type UiRequestEvent, type VendorType, batchCall, bytesToHex, compareSemver, createBridgedConnector, deriveDeviceFingerprint, enrichErrorMessage, ensure0x, failure, hexToBytes, padHex64, stripHex, success };
1074
+ 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 DeviceTarget, EConnectorInteraction, type EIP712Domain, type EvmAddress, type EvmGetAddressParams, type EvmGetPublicKeyParams, type EvmPublicKey, 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 IUiBridge, type IUiHandler, 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 SolGetPublicKeyParams, type SolPublicKey, 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 };
package/dist/index.js CHANGED
@@ -30,7 +30,12 @@ __export(index_exports, {
30
30
  TypedEventEmitter: () => TypedEventEmitter,
31
31
  UI_EVENT: () => UI_EVENT,
32
32
  UI_REQUEST: () => UI_REQUEST,
33
+ UI_REQUEST_CANCELLED_TAG: () => UI_REQUEST_CANCELLED_TAG,
34
+ UI_REQUEST_DEFAULT_TIMEOUT_MS: () => UI_REQUEST_DEFAULT_TIMEOUT_MS,
35
+ UI_REQUEST_PREEMPTED_TAG: () => UI_REQUEST_PREEMPTED_TAG,
36
+ UI_REQUEST_TIMEOUT_TAG: () => UI_REQUEST_TIMEOUT_TAG,
33
37
  UI_RESPONSE: () => UI_RESPONSE,
38
+ UiRequestRegistry: () => UiRequestRegistry,
34
39
  batchCall: () => batchCall,
35
40
  bytesToHex: () => bytesToHex,
36
41
  compareSemver: () => compareSemver,
@@ -70,6 +75,11 @@ var HardwareErrorCode = /* @__PURE__ */ ((HardwareErrorCode2) => {
70
75
  HardwareErrorCode2[HardwareErrorCode2["DeviceMismatch"] = 5560] = "DeviceMismatch";
71
76
  HardwareErrorCode2[HardwareErrorCode2["BridgeNotFound"] = 5550] = "BridgeNotFound";
72
77
  HardwareErrorCode2[HardwareErrorCode2["TransportNotAvailable"] = 5551] = "TransportNotAvailable";
78
+ HardwareErrorCode2[HardwareErrorCode2["EvmBlindSigningRequired"] = 7001] = "EvmBlindSigningRequired";
79
+ HardwareErrorCode2[HardwareErrorCode2["EvmClearSignPluginMissing"] = 7002] = "EvmClearSignPluginMissing";
80
+ HardwareErrorCode2[HardwareErrorCode2["EvmDataTooLarge"] = 7003] = "EvmDataTooLarge";
81
+ HardwareErrorCode2[HardwareErrorCode2["EvmTxTypeNotSupported"] = 7004] = "EvmTxTypeNotSupported";
82
+ HardwareErrorCode2[HardwareErrorCode2["AppTooOld"] = 7005] = "AppTooOld";
73
83
  return HardwareErrorCode2;
74
84
  })(HardwareErrorCode || {});
75
85
 
@@ -77,8 +87,8 @@ var HardwareErrorCode = /* @__PURE__ */ ((HardwareErrorCode2) => {
77
87
  function success(payload) {
78
88
  return { success: true, payload };
79
89
  }
80
- function failure(code, error) {
81
- return { success: false, payload: { error, code } };
90
+ function failure(code, error, appName) {
91
+ return { success: false, payload: { error, code, appName } };
82
92
  }
83
93
 
84
94
  // src/types/fingerprint.ts
@@ -140,6 +150,7 @@ var UI_RESPONSE = {
140
150
  RECEIVE_PASSPHRASE_ON_DEVICE: "receive-passphrase-on-device",
141
151
  RECEIVE_QR_RESPONSE: "receive-qr-response",
142
152
  RECEIVE_SELECT_DEVICE: "receive-select-device",
153
+ RECEIVE_DEVICE_CONNECT: "receive-device-connect",
143
154
  CANCEL: "cancel"
144
155
  };
145
156
 
@@ -338,6 +349,102 @@ var TypedEventEmitter = class {
338
349
  }
339
350
  };
340
351
 
352
+ // src/utils/UiRequestRegistry.ts
353
+ var UI_REQUEST_DEFAULT_TIMEOUT_MS = 6e5;
354
+ var RESPONSE_TO_REQUEST = {
355
+ [UI_RESPONSE.RECEIVE_PIN]: UI_REQUEST.REQUEST_PIN,
356
+ [UI_RESPONSE.RECEIVE_PASSPHRASE]: UI_REQUEST.REQUEST_PASSPHRASE,
357
+ [UI_RESPONSE.RECEIVE_PASSPHRASE_ON_DEVICE]: UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE,
358
+ [UI_RESPONSE.RECEIVE_SELECT_DEVICE]: UI_REQUEST.REQUEST_SELECT_DEVICE,
359
+ [UI_RESPONSE.RECEIVE_DEVICE_CONNECT]: UI_REQUEST.REQUEST_DEVICE_CONNECT
360
+ // RECEIVE_QR_RESPONSE maps to QR_DISPLAY or QR_SCAN — resolved dynamically below.
361
+ };
362
+ var UI_REQUEST_PREEMPTED_TAG = "UiRequestPreempted";
363
+ var UI_REQUEST_CANCELLED_TAG = "UiRequestCancelled";
364
+ var UI_REQUEST_TIMEOUT_TAG = "UiRequestTimeout";
365
+ var UiRequestRegistry = class {
366
+ constructor() {
367
+ this.pending = /* @__PURE__ */ new Map();
368
+ }
369
+ wait(requestType, options) {
370
+ const existing = this.pending.get(requestType);
371
+ if (existing) {
372
+ clearTimeout(existing.timer);
373
+ this.pending.delete(requestType);
374
+ existing.reject(
375
+ Object.assign(
376
+ new Error(`UI request '${requestType}' was superseded by a new request`),
377
+ { _tag: UI_REQUEST_PREEMPTED_TAG }
378
+ )
379
+ );
380
+ }
381
+ const timeoutMs = options?.timeoutMs ?? UI_REQUEST_DEFAULT_TIMEOUT_MS;
382
+ return new Promise((resolve, reject) => {
383
+ const timer = setTimeout(() => {
384
+ if (this.pending.get(requestType)?.timer === timer) {
385
+ this.pending.delete(requestType);
386
+ reject(
387
+ Object.assign(
388
+ new Error(`UI request '${requestType}' timed out after ${timeoutMs}ms`),
389
+ { _tag: UI_REQUEST_TIMEOUT_TAG }
390
+ )
391
+ );
392
+ }
393
+ }, timeoutMs);
394
+ this.pending.set(requestType, {
395
+ resolve,
396
+ reject,
397
+ timer
398
+ });
399
+ });
400
+ }
401
+ resolve(responseType, payload) {
402
+ let requestType = RESPONSE_TO_REQUEST[responseType];
403
+ if (responseType === UI_RESPONSE.RECEIVE_QR_RESPONSE) {
404
+ if (this.pending.has(UI_REQUEST.REQUEST_QR_DISPLAY)) {
405
+ requestType = UI_REQUEST.REQUEST_QR_DISPLAY;
406
+ } else if (this.pending.has(UI_REQUEST.REQUEST_QR_SCAN)) {
407
+ requestType = UI_REQUEST.REQUEST_QR_SCAN;
408
+ }
409
+ }
410
+ if (!requestType) return;
411
+ const entry = this.pending.get(requestType);
412
+ if (!entry) return;
413
+ clearTimeout(entry.timer);
414
+ this.pending.delete(requestType);
415
+ entry.resolve(payload);
416
+ }
417
+ cancel(requestType) {
418
+ if (requestType) {
419
+ const entry = this.pending.get(requestType);
420
+ if (!entry) return;
421
+ clearTimeout(entry.timer);
422
+ this.pending.delete(requestType);
423
+ entry.reject(
424
+ Object.assign(new Error(`UI request '${requestType}' was cancelled`), {
425
+ _tag: UI_REQUEST_CANCELLED_TAG
426
+ })
427
+ );
428
+ return;
429
+ }
430
+ for (const [type, entry] of this.pending) {
431
+ clearTimeout(entry.timer);
432
+ entry.reject(
433
+ Object.assign(new Error(`UI request '${type}' was cancelled`), {
434
+ _tag: UI_REQUEST_CANCELLED_TAG
435
+ })
436
+ );
437
+ }
438
+ this.pending.clear();
439
+ }
440
+ reset() {
441
+ this.cancel();
442
+ }
443
+ hasPending(requestType) {
444
+ return this.pending.has(requestType);
445
+ }
446
+ };
447
+
341
448
  // src/utils/semver.ts
342
449
  function compareSemver(a, b) {
343
450
  const pa = a.split(".").map(Number);
@@ -400,6 +507,16 @@ function enrichErrorMessage(code, originalMessage) {
400
507
  return `${originalMessage}. The device may need to be set up first.`;
401
508
  case 9 /* OperationTimeout */:
402
509
  return `${originalMessage}. The operation timed out. Please try again.`;
510
+ case 7001 /* EvmBlindSigningRequired */:
511
+ return "Please enable Blind signing on your Ledger: open the Ethereum app \u2192 Settings \u2192 Blind signing \u2192 Enabled, then try again.";
512
+ case 7002 /* EvmClearSignPluginMissing */:
513
+ return "Required Ledger plugin is not installed. Please install the matching plugin on Ledger Live, then try again.";
514
+ case 7003 /* EvmDataTooLarge */:
515
+ return "Transaction data is too large for your Ledger device. Try a simpler transaction or use a Ledger with more memory.";
516
+ case 7004 /* EvmTxTypeNotSupported */:
517
+ return "Transaction type is not supported by your Ledger Ethereum app. Please update the app to the latest version.";
518
+ case 7005 /* AppTooOld */:
519
+ return "Your Ledger app is out of date. Please update it via Ledger Live.";
403
520
  default:
404
521
  return originalMessage;
405
522
  }
@@ -430,7 +547,12 @@ async function batchCall(params, callFn, onProgress) {
430
547
  TypedEventEmitter,
431
548
  UI_EVENT,
432
549
  UI_REQUEST,
550
+ UI_REQUEST_CANCELLED_TAG,
551
+ UI_REQUEST_DEFAULT_TIMEOUT_MS,
552
+ UI_REQUEST_PREEMPTED_TAG,
553
+ UI_REQUEST_TIMEOUT_TAG,
433
554
  UI_RESPONSE,
555
+ UiRequestRegistry,
434
556
  batchCall,
435
557
  bytesToHex,
436
558
  compareSemver,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types/errors.ts","../src/types/response.ts","../src/types/fingerprint.ts","../src/events/device.ts","../src/events/ui-request.ts","../src/events/sdk.ts","../src/utils/DeviceJobQueue.ts","../src/types/connector.ts","../src/utils/TypedEventEmitter.ts","../src/utils/semver.ts","../src/utils/hex.ts","../src/utils/errorMessages.ts","../src/utils/batchCall.ts"],"sourcesContent":["export { HardwareErrorCode } from './types/errors';\n\nexport type { Success, Failure, Response } from './types/response';\nexport { success, failure } from './types/response';\n\nexport type {\n VendorType,\n ConnectionType,\n TransportType,\n DeviceInfo,\n DeviceTarget,\n DeviceCapabilities,\n} from './types/device';\n\nexport type {\n EvmGetAddressParams,\n EvmAddress,\n EvmGetPublicKeyParams,\n EvmPublicKey,\n EvmSignTxParams,\n EvmSignedTx,\n EvmSignMsgParams,\n EvmSignTypedDataParams,\n EvmSignTypedDataFull,\n EvmSignTypedDataHash,\n EIP712Domain,\n EvmSignature,\n ProgressCallback,\n IEvmMethods,\n} from './types/chain-evm';\n\nexport type {\n BtcGetAddressParams,\n BtcAddress,\n BtcGetPublicKeyParams,\n BtcPublicKey,\n BtcSignTxParams,\n BtcTxInput,\n BtcTxOutput,\n BtcRefTransaction,\n BtcSignedTx,\n BtcSignMsgParams,\n BtcSignature,\n IBtcMethods,\n} from './types/chain-btc';\n\nexport type {\n SolGetAddressParams,\n SolAddress,\n SolGetPublicKeyParams,\n SolPublicKey,\n SolSignTxParams,\n SolSignedTx,\n SolSignMsgParams,\n SolSignature,\n ISolMethods,\n} from './types/chain-sol';\n\nexport type {\n TronGetAddressParams,\n TronAddress,\n TronSignTxParams,\n TronSignedTx,\n TronSignMsgParams,\n TronSignature,\n ITronMethods,\n} from './types/chain-tron';\n\nexport type { QrDisplayData, QrResponseData } from './types/qr';\n\nexport type { ChainForFingerprint } from './types/fingerprint';\nexport { CHAIN_FINGERPRINT_PATHS, deriveDeviceFingerprint } from './types/fingerprint';\n\nexport type {\n IHardwareWallet,\n IUiHandler,\n PassphraseResponse,\n ChainCapability,\n DeviceEvent,\n UiRequestEvent,\n SdkEvent,\n HardwareEvent,\n HardwareEventMap,\n DeviceEventListener,\n} from './types/wallet';\n\nexport { DEVICE_EVENT, DEVICE } from './events/device';\nexport { UI_EVENT, UI_REQUEST, UI_RESPONSE } from './events/ui-request';\nexport { SDK } from './events/sdk';\n\nexport type {\n DeviceDescriptor,\n DeviceConnectEvent,\n DeviceDisconnectEvent,\n DeviceChangeEvent,\n} from './types/transport';\n\nexport { DeviceJobQueue } from './utils/DeviceJobQueue';\nexport type {\n Interruptibility,\n PreemptionDecision,\n JobOptions,\n ActiveJobInfo,\n PreemptionEvent,\n} from './utils/DeviceJobQueue';\nexport type { IUiBridge } from './types/ui-bridge';\n\nexport type {\n ConnectorDevice,\n ConnectorSession,\n ConnectorEventType,\n ConnectorEventMap,\n IConnector,\n IHardwareBridge,\n} from './types/connector';\nexport { createBridgedConnector, EConnectorInteraction } from './types/connector';\n\nexport { TypedEventEmitter } from './utils/TypedEventEmitter';\nexport { compareSemver } from './utils/semver';\nexport { ensure0x, stripHex, padHex64, hexToBytes, bytesToHex } from './utils/hex';\nexport { enrichErrorMessage } from './utils/errorMessages';\nexport { batchCall } from './utils/batchCall';\n","export enum HardwareErrorCode {\n UnknownError = 0,\n DeviceNotFound = 1,\n DeviceDisconnected = 2,\n UserRejected = 3,\n DeviceBusy = 4,\n FirmwareUpdateRequired = 5,\n AppNotOpen = 6,\n InvalidParams = 7,\n TransportError = 8,\n OperationTimeout = 9,\n MethodNotSupported = 10,\n\n // PIN / Passphrase\n PinInvalid = 5520,\n PinCancelled = 5521,\n PassphraseRejected = 5522,\n\n // Device state\n DeviceLocked = 5530,\n DeviceNotInitialized = 5531,\n DeviceInBootloader = 5532,\n FirmwareTooOld = 5533,\n\n // Ledger specific\n WrongApp = 5540,\n\n // Device identity\n DeviceMismatch = 5560,\n\n // Transport\n BridgeNotFound = 5550,\n TransportNotAvailable = 5551,\n}\n","import { HardwareErrorCode } from './errors';\n\nexport interface Success<T> {\n success: true;\n payload: T;\n}\n\nexport interface Failure {\n success: false;\n payload: {\n error: string;\n code: HardwareErrorCode;\n };\n}\n\nexport type Response<T> = Success<T> | Failure;\n\nexport function success<T>(payload: T): Success<T> {\n return { success: true, payload };\n}\n\nexport function failure(code: HardwareErrorCode, error: string): Failure {\n return { success: false, payload: { error, code } };\n}\n","/**\n * Chain fingerprint utilities for device identity verification.\n *\n * Ledger devices have ephemeral IDs that change every session.\n * To verify that the same seed/device is connected, we derive an address\n * at a fixed path (account 0, index 0) and hash it into a stable \"chain fingerprint\".\n */\n\n/**\n * Fixed derivation paths used to generate chain fingerprints.\n * Uses standard index 0 — Ledger firmware shows device confirmation for\n * non-standard paths (e.g., index=100), which would interrupt wallet creation.\n * The address is hashed into a 16-char fingerprint, not exposed directly.\n * - EVM: cointype 60 (Ledger ETH App only supports 60)\n * - BTC: cointype 1 (testnet)\n * - SOL: cointype 501, standard 3-level hardened\n */\nexport const CHAIN_FINGERPRINT_PATHS: Record<ChainForFingerprint, string> = {\n evm: \"m/44'/60'/0'/0/0\",\n // BTC: account-level path (3 levels), mainnet cointype 0.\n // Cointype 1 (testnet) is rejected by some Ledger BTC App configurations.\n btc: \"m/44'/0'/0'\",\n sol: \"m/44'/501'/0'\",\n tron: \"m/44'/195'/0'/0/0\",\n};\n\nexport type ChainForFingerprint = 'evm' | 'btc' | 'sol' | 'tron';\n\n/**\n * Hash an address string into a 16-character hex fingerprint.\n *\n * Uses a simple non-cryptographic hash (FNV-1a based) to avoid\n * pulling in a SHA-256 dependency. This is NOT used for security —\n * only for device identity matching.\n */\nexport function deriveDeviceFingerprint(address: string): string {\n // FNV-1a 64-bit constants (split into two 32-bit halves for JS)\n let h1 = 0x811c9dc5;\n let h2 = 0x01000193;\n\n for (let i = 0; i < address.length; i++) {\n const c = address.charCodeAt(i);\n h1 = Math.imul(h1 ^ c, h2);\n h2 = Math.imul(h2 ^ (c >>> 4), 0x01000193);\n }\n\n // Mix the two halves for better distribution\n h1 = Math.imul(h1 ^ (h1 >>> 16), 0x45d9f3b);\n h2 = Math.imul(h2 ^ (h2 >>> 16), 0x45d9f3b);\n\n const hex1 = (h1 >>> 0).toString(16).padStart(8, '0');\n const hex2 = (h2 >>> 0).toString(16).padStart(8, '0');\n\n return `${hex1}${hex2}`;\n}\n","export const DEVICE_EVENT = 'DEVICE_EVENT';\n\n/** Events originating from the hardware device. */\nexport const DEVICE = {\n CONNECT: 'device-connect',\n DISCONNECT: 'device-disconnect',\n CHANGED: 'device-changed',\n ACQUIRE: 'device-acquire',\n RELEASE: 'device-release',\n FEATURES: 'features',\n SUPPORT_FEATURES: 'support_features',\n} as const;\n","export const UI_EVENT = 'UI_EVENT';\n\nexport const UI_REQUEST = {\n REQUEST_PIN: 'ui-request-pin',\n REQUEST_PASSPHRASE: 'ui-request-passphrase',\n REQUEST_PASSPHRASE_ON_DEVICE: 'ui-request-passphrase-on-device',\n REQUEST_BUTTON: 'ui-request-button',\n REQUEST_QR_DISPLAY: 'ui-request-qr-display',\n REQUEST_QR_SCAN: 'ui-request-qr-scan',\n REQUEST_DEVICE_PERMISSION: 'ui-request-device-permission',\n REQUEST_SELECT_DEVICE: 'ui-request-select-device',\n REQUEST_DEVICE_CONNECT: 'ui-request-device-connect',\n CLOSE_UI_WINDOW: 'ui-close',\n DEVICE_PROGRESS: 'ui-device_progress',\n FIRMWARE_PROGRESS: 'ui-firmware-progress',\n FIRMWARE_TIP: 'ui-firmware-tip',\n} as const;\n\nexport const UI_RESPONSE = {\n RECEIVE_PIN: 'receive-pin',\n RECEIVE_PASSPHRASE: 'receive-passphrase',\n RECEIVE_PASSPHRASE_ON_DEVICE: 'receive-passphrase-on-device',\n RECEIVE_QR_RESPONSE: 'receive-qr-response',\n RECEIVE_SELECT_DEVICE: 'receive-select-device',\n CANCEL: 'cancel',\n} as const;\n","/** Events generated by SDK internal detection (not from hardware directly). */\nexport const SDK = {\n DEVICE_STUCK: 'device-stuck',\n DEVICE_UNRESPONSIVE: 'device-unresponsive',\n DEVICE_RECOVERED: 'device-recovered',\n DEVICE_INTERACTION: 'device-interaction',\n} as const;\n","/**\n * Per-device serial job queue with preemption support and stuck recovery.\n * Ensures that only one operation runs at a time per device, with intelligent\n * handling of conflicting operations.\n */\n\nexport type Interruptibility = 'none' | 'safe' | 'confirm';\n\nexport type PreemptionDecision = 'cancel-current' | 'wait' | 'reject-new';\n\nexport interface JobOptions {\n interruptibility?: Interruptibility;\n label?: string;\n}\n\nexport interface ActiveJobInfo {\n label?: string;\n interruptibility: Interruptibility;\n startedAt: number;\n}\n\nexport interface PreemptionEvent {\n deviceId: string;\n currentJob: ActiveJobInfo;\n newJob: { label?: string; interruptibility: Interruptibility };\n}\n\ninterface ActiveJob {\n options: Required<Pick<JobOptions, 'interruptibility'>> & Pick<JobOptions, 'label'>;\n abortController: AbortController;\n startedAt: number;\n}\n\nexport class DeviceJobQueue {\n private readonly _queues = new Map<string, Promise<unknown>>();\n private readonly _active = new Map<string, ActiveJob>();\n\n /**\n * Called when a new job conflicts with an active 'confirm'-level job.\n * UI should show a dialog and return the user's decision.\n * If not set, defaults to 'wait' (queue behind current job).\n */\n onPreemptionRequest?: (event: PreemptionEvent) => Promise<PreemptionDecision>;\n\n /**\n * Enqueue a job for a specific device.\n * If a job is already running for this device, behavior depends on interruptibility:\n * - 'none': new job queues silently (no preemption possible)\n * - 'safe': current job is auto-cancelled, new job runs immediately after\n * - 'confirm': onPreemptionRequest is called to ask user\n */\n async enqueue<T>(\n deviceId: string,\n job: (signal: AbortSignal) => Promise<T>,\n options: JobOptions = {}\n ): Promise<T> {\n const interruptibility = options.interruptibility ?? 'confirm';\n const active = this._active.get(deviceId);\n\n if (active) {\n switch (active.options.interruptibility) {\n case 'none':\n // Cannot interrupt, just queue behind\n break;\n case 'safe':\n // Auto-cancel current safe operation\n active.abortController.abort(new Error('Preempted by new operation'));\n break;\n case 'confirm': {\n if (this.onPreemptionRequest) {\n const decision = await this.onPreemptionRequest({\n deviceId,\n currentJob: {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n },\n newJob: {\n label: options.label,\n interruptibility,\n },\n });\n switch (decision) {\n case 'cancel-current':\n active.abortController.abort(new Error('Cancelled by user via preemption'));\n break;\n case 'reject-new':\n throw Object.assign(\n new Error(`Device busy: ${active.options.label ?? 'unknown operation'}`),\n { hardwareErrorCode: 'DEVICE_BUSY' }\n );\n case 'wait':\n break;\n }\n }\n break;\n }\n }\n }\n\n const ac = new AbortController();\n const prev = this._queues.get(deviceId) ?? Promise.resolve();\n\n const next = prev\n .catch(() => {})\n .then(async () => {\n this._active.set(deviceId, {\n options: { interruptibility, label: options.label },\n abortController: ac,\n startedAt: Date.now(),\n });\n try {\n return await job(ac.signal);\n } finally {\n this._active.delete(deviceId);\n }\n });\n\n const tail = next.catch(() => {});\n this._queues.set(deviceId, tail);\n tail.then(() => {\n if (this._queues.get(deviceId) === tail) {\n this._queues.delete(deviceId);\n }\n });\n return next;\n }\n\n /** Manually cancel the active job on a device. Returns false if job is non-interruptible. */\n cancelActive(deviceId: string): boolean {\n const active = this._active.get(deviceId);\n if (!active) return false;\n if (active.options.interruptibility === 'none') return false;\n active.abortController.abort(new Error('Manually cancelled'));\n return true;\n }\n\n /** Force cancel regardless of interruptibility. Use for device stuck recovery. */\n forceCancelActive(deviceId: string): boolean {\n const active = this._active.get(deviceId);\n if (!active) return false;\n active.abortController.abort(new Error('Force cancelled for recovery'));\n return true;\n }\n\n /** Get info about the currently active job for a device, or null if idle. */\n getActiveJob(deviceId: string): ActiveJobInfo | null {\n const active = this._active.get(deviceId);\n if (!active) return null;\n return {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n };\n }\n\n clear(): void {\n // Abort all active jobs\n for (const active of this._active.values()) {\n active.abortController.abort(new Error('Queue cleared'));\n }\n this._active.clear();\n this._queues.clear();\n }\n}\n","import type { DeviceCapabilities, DeviceInfo, VendorType } from './device';\n\n// =====================================================================\n// Connector types — transport-level abstraction for device communication\n// =====================================================================\n\n/**\n * Minimal device info returned during discovery (searchDevices).\n * At scan time, full DeviceInfo fields like firmwareVersion are not yet available.\n */\nexport interface ConnectorDevice {\n connectId: string;\n deviceId: string;\n name: string;\n model?: string;\n\n /** Device capabilities — available from scan time */\n capabilities?: DeviceCapabilities;\n}\n\nexport interface ConnectorSession {\n sessionId: string;\n deviceInfo: DeviceInfo;\n}\n\nexport type ConnectorEventType = 'device-connect' | 'device-disconnect' | 'ui-request' | 'ui-event';\n\n/**\n * Interaction event types emitted via 'ui-event'.\n * These map to user-facing prompts (confirm on device, open app, etc.).\n */\nexport enum EConnectorInteraction {\n /** Device requires user to open a specific app */\n ConfirmOpenApp = 'confirm-open-app',\n /** Device requires user to unlock */\n UnlockDevice = 'unlock-device',\n /** Device needs user to confirm on device (sign, verify, etc.) */\n ConfirmOnDevice = 'confirm-on-device',\n /** Previous interaction completed — clear UI prompt */\n InteractionComplete = 'interaction-complete',\n}\n\nexport type ConnectorUiEvent =\n | { type: EConnectorInteraction.ConfirmOpenApp; payload: { sessionId: string } }\n | { type: EConnectorInteraction.UnlockDevice; payload: { sessionId: string } }\n | { type: EConnectorInteraction.ConfirmOnDevice; payload: { sessionId: string } }\n | { type: EConnectorInteraction.InteractionComplete; payload: { sessionId: string } };\n\nexport interface ConnectorEventMap {\n 'device-connect': { device: ConnectorDevice };\n 'device-disconnect': { connectId: string };\n 'ui-request': { type: string; payload?: unknown };\n 'ui-event': ConnectorUiEvent;\n}\n\nexport interface IConnector {\n searchDevices(): Promise<ConnectorDevice[]>;\n connect(deviceId?: string): Promise<ConnectorSession>;\n disconnect(sessionId: string): Promise<void>;\n call(sessionId: string, method: string, params: unknown): Promise<unknown>;\n cancel(sessionId: string): Promise<void>;\n\n /** Send a UI response (e.g. PIN, passphrase) to the device. */\n uiResponse(response: { type: string; payload: unknown }): void;\n\n on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;\n off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;\n\n reset(): void;\n}\n\n// =====================================================================\n// Hardware bridge — generic forwarding interface for cross-boundary IConnector\n//\n// The same shape works across any process / context boundary that needs to\n// expose a multi-vendor backend behind a single-vendor IConnector facade:\n// - Electron (renderer ↔ preload/main via contextBridge)\n// - Browser Extension (popup/content ↔ background/offscreen via chrome.runtime)\n// - React Native (JS ↔ native module via NativeModules)\n// - Web Worker / iframe (postMessage)\n//\n// Each method takes a `vendor` discriminator so a single bridge implementation\n// can multiplex across vendors (ledger, trezor, ...).\n// =====================================================================\n\nexport interface IHardwareBridge {\n searchDevices(params: { vendor: VendorType }): Promise<ConnectorDevice[]>;\n connect(params: { vendor: VendorType; deviceId?: string }): Promise<ConnectorSession>;\n disconnect(params: { vendor: VendorType; sessionId: string }): Promise<void>;\n call(params: {\n vendor: VendorType;\n sessionId: string;\n method: string;\n callParams: unknown;\n }): Promise<unknown>;\n cancel(params: { vendor: VendorType; sessionId: string }): Promise<void>;\n uiResponse(params: { vendor: VendorType; response: { type: string; payload: unknown } }): void;\n reset(params: { vendor: VendorType }): void;\n\n /** Register an event handler for connector events forwarded across the bridge. */\n onEvent(\n params: { vendor: VendorType },\n handler: (event: { type: ConnectorEventType; data: unknown }) => void\n ): void;\n\n /** Unregister a previously registered event handler. */\n offEvent(\n params: { vendor: VendorType },\n handler: (event: { type: ConnectorEventType; data: unknown }) => void\n ): void;\n}\n\n/**\n * Adapt an IHardwareBridge (multi-vendor backend) into a single-vendor IConnector.\n * Every IConnector method becomes a transparent forward to bridge.<method>({ vendor, ... }).\n * Events are forwarded via bridge.onEvent / offEvent.\n *\n * Use this anywhere the actual hardware lives behind a process / context boundary\n * (Electron main, extension background, native module, worker, iframe).\n */\nexport function createBridgedConnector(\n vendor: VendorType,\n bridge: IHardwareBridge\n): IConnector {\n // Map from typed IConnector handlers to the bridge handler so we can\n // unregister them correctly via off().\n const handlerMap = new Map<\n (data: ConnectorEventMap[ConnectorEventType]) => void,\n (event: { type: ConnectorEventType; data: unknown }) => void\n >();\n\n return {\n searchDevices: () => bridge.searchDevices({ vendor }),\n connect: deviceId => bridge.connect({ vendor, deviceId }),\n disconnect: sessionId => bridge.disconnect({ vendor, sessionId }),\n call: (sessionId, method, callParams) => bridge.call({ vendor, sessionId, method, callParams }),\n cancel: sessionId => bridge.cancel({ vendor, sessionId }),\n uiResponse: response => bridge.uiResponse({ vendor, response }),\n on: (event, handler) => {\n const bridgeHandler = (e: { type: ConnectorEventType; data: unknown }) => {\n if (e.type === event) {\n handler(e.data as ConnectorEventMap[typeof event]);\n }\n };\n handlerMap.set(\n handler as (data: ConnectorEventMap[ConnectorEventType]) => void,\n bridgeHandler\n );\n bridge.onEvent({ vendor }, bridgeHandler);\n },\n off: (_event, handler) => {\n const bridgeHandler = handlerMap.get(\n handler as (data: ConnectorEventMap[ConnectorEventType]) => void\n );\n if (bridgeHandler) {\n bridge.offEvent({ vendor }, bridgeHandler);\n handlerMap.delete(handler as (data: ConnectorEventMap[ConnectorEventType]) => void);\n }\n },\n reset: () => bridge.reset({ vendor }),\n };\n}\n","/**\n * Minimal typed event emitter using Map<string, Set<listener>>.\n * Each adapter uses this for device events (connect, disconnect, pin, etc.).\n *\n * TMap is a record mapping event name strings to their payload types.\n * Example:\n * type MyEvents = { 'connect': { id: string }; 'disconnect': { id: string } };\n * const emitter = new TypedEventEmitter<MyEvents>();\n * emitter.on('connect', (data) => { data.id }); // data is { id: string }\n *\n * For backward compatibility, TMap defaults to Record<string, any> so that\n * existing code using `new TypedEventEmitter<SomeUnionType>()` still compiles.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class TypedEventEmitter<TMap extends Record<string, any> = Record<string, any>> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly _listeners = new Map<string, Set<(event: any) => void>>();\n\n on<K extends keyof TMap & string>(event: K, listener: (event: TMap[K]) => void): void;\n on(event: string, listener: (event: any) => void): void;\n on(event: string, listener: (event: any) => void): void {\n let set = this._listeners.get(event);\n if (!set) {\n set = new Set();\n this._listeners.set(event, set);\n }\n set.add(listener);\n }\n\n off<K extends keyof TMap & string>(event: K, listener: (event: TMap[K]) => void): void;\n off(event: string, listener: (event: any) => void): void;\n off(event: string, listener: (event: any) => void): void {\n const set = this._listeners.get(event);\n if (set) {\n set.delete(listener);\n if (set.size === 0) this._listeners.delete(event);\n }\n }\n\n emit<K extends keyof TMap & string>(event: K, data: TMap[K]): void;\n emit(event: string, data: unknown): void;\n emit(event: string, data: unknown): void {\n const set = this._listeners.get(event);\n if (set) {\n for (const listener of set) listener(data);\n }\n }\n\n removeAllListeners(): void {\n this._listeners.clear();\n }\n}\n","/**\n * Compare two semver strings (e.g. \"2.1.0\" vs \"2.3.1\").\n * Returns -1 if a < b, 0 if equal, 1 if a > b.\n */\nexport function compareSemver(a: string, b: string): number {\n const pa = a.split('.').map(Number);\n const pb = b.split('.').map(Number);\n for (let i = 0; i < 3; i++) {\n const va = pa[i] ?? 0;\n const vb = pb[i] ?? 0;\n if (va < vb) return -1;\n if (va > vb) return 1;\n }\n return 0;\n}\n","/** Ensure hex string has 0x prefix */\nexport function ensure0x(hex: string): string {\n return hex.startsWith('0x') ? hex : `0x${hex}`;\n}\n\n/** Strip 0x prefix from hex string */\nexport function stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Pad hex to 64 chars (32 bytes) with 0x prefix */\nexport function padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n/** Convert a hex string (with or without 0x prefix) to a Uint8Array. */\nexport function hexToBytes(hex: string): Uint8Array {\n const clean = stripHex(hex);\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/** Convert a Uint8Array to a hex string (no 0x prefix). */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n}\n","import { HardwareErrorCode } from '../types/errors';\n\n/**\n * Enrich a hardware error message with actionable recovery hints.\n * Shared across adapters (Ledger, Trezor, etc.).\n */\nexport function enrichErrorMessage(code: HardwareErrorCode, originalMessage: string): string {\n switch (code) {\n case HardwareErrorCode.PinInvalid:\n return `${originalMessage}. Please re-enter your PIN.`;\n case HardwareErrorCode.PinCancelled:\n return `${originalMessage}. PIN entry was cancelled.`;\n case HardwareErrorCode.DeviceBusy:\n return `${originalMessage}. The device is in use by another application. Close other wallet apps and try again.`;\n case HardwareErrorCode.DeviceDisconnected:\n return `${originalMessage}. Please reconnect the device and try again.`;\n case HardwareErrorCode.DeviceLocked:\n return `${originalMessage}. Please unlock your device and try again.`;\n case HardwareErrorCode.UserRejected:\n return `${originalMessage}. The request was rejected on the device.`;\n case HardwareErrorCode.WrongApp:\n return `${originalMessage}. Please open the correct app on your device.`;\n case HardwareErrorCode.AppNotOpen:\n return `${originalMessage}. The required app is not installed on the device.`;\n case HardwareErrorCode.TransportNotAvailable:\n return `${originalMessage}. Ensure the device bridge/transport is available and running.`;\n case HardwareErrorCode.FirmwareTooOld:\n return `${originalMessage}. Please update your device firmware.`;\n case HardwareErrorCode.DeviceNotInitialized:\n return `${originalMessage}. The device may need to be set up first.`;\n case HardwareErrorCode.OperationTimeout:\n return `${originalMessage}. The operation timed out. Please try again.`;\n default:\n return originalMessage;\n }\n}\n","import type { Response } from '../types/response';\n\n/**\n * Generic batch call with progress reporting.\n * If any single call fails, returns the failure immediately.\n */\nexport async function batchCall<TParam, TResult>(\n params: TParam[],\n callFn: (p: TParam) => Promise<Response<TResult>>,\n onProgress?: (progress: { index: number; total: number }) => void\n): Promise<Response<TResult[]>> {\n const results: TResult[] = [];\n for (let i = 0; i < params.length; i++) {\n const result = await callFn(params[i]);\n if (!result.success) {\n return result;\n }\n results.push(result.payload);\n onProgress?.({ index: i, total: params.length });\n }\n return { success: true, payload: results };\n}\n"],"mappings":"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","names":["HardwareErrorCode","EConnectorInteraction"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types/errors.ts","../src/types/response.ts","../src/types/fingerprint.ts","../src/events/device.ts","../src/events/ui-request.ts","../src/events/sdk.ts","../src/utils/DeviceJobQueue.ts","../src/types/connector.ts","../src/utils/TypedEventEmitter.ts","../src/utils/UiRequestRegistry.ts","../src/utils/semver.ts","../src/utils/hex.ts","../src/utils/errorMessages.ts","../src/utils/batchCall.ts"],"sourcesContent":["export { HardwareErrorCode } from './types/errors';\n\nexport type { Success, Failure, Response } from './types/response';\nexport { success, failure } from './types/response';\n\nexport type {\n VendorType,\n ConnectionType,\n TransportType,\n DeviceInfo,\n DeviceTarget,\n DeviceCapabilities,\n} from './types/device';\n\nexport type {\n EvmGetAddressParams,\n EvmAddress,\n EvmGetPublicKeyParams,\n EvmPublicKey,\n EvmSignTxParams,\n EvmSignedTx,\n EvmSignMsgParams,\n EvmSignTypedDataParams,\n EvmSignTypedDataFull,\n EvmSignTypedDataHash,\n EIP712Domain,\n EvmSignature,\n ProgressCallback,\n IEvmMethods,\n} from './types/chain-evm';\n\nexport type {\n BtcGetAddressParams,\n BtcAddress,\n BtcGetPublicKeyParams,\n BtcPublicKey,\n BtcSignTxParams,\n BtcTxInput,\n BtcTxOutput,\n BtcRefTransaction,\n BtcSignedTx,\n BtcSignPsbtParams,\n BtcSignedPsbt,\n BtcSignMsgParams,\n BtcSignature,\n IBtcMethods,\n} from './types/chain-btc';\n\nexport type {\n SolGetAddressParams,\n SolAddress,\n SolGetPublicKeyParams,\n SolPublicKey,\n SolSignTxParams,\n SolSignedTx,\n SolSignMsgParams,\n SolSignature,\n ISolMethods,\n} from './types/chain-sol';\n\nexport type {\n TronGetAddressParams,\n TronAddress,\n TronSignTxParams,\n TronSignedTx,\n TronSignMsgParams,\n TronSignature,\n ITronMethods,\n} from './types/chain-tron';\n\nexport type { QrDisplayData, QrResponseData } from './types/qr';\n\nexport type { ChainForFingerprint } from './types/fingerprint';\nexport { CHAIN_FINGERPRINT_PATHS, deriveDeviceFingerprint } from './types/fingerprint';\n\nexport type {\n IHardwareWallet,\n IUiHandler,\n PassphraseResponse,\n ChainCapability,\n DeviceEvent,\n UiRequestEvent,\n SdkEvent,\n HardwareEvent,\n HardwareEventMap,\n DeviceEventListener,\n} from './types/wallet';\n\nexport { DEVICE_EVENT, DEVICE } from './events/device';\nexport { UI_EVENT, UI_REQUEST, UI_RESPONSE } from './events/ui-request';\nexport type { UiResponseEvent } from './events/ui-request';\nexport { SDK } from './events/sdk';\n\nexport type {\n DeviceDescriptor,\n DeviceConnectEvent,\n DeviceDisconnectEvent,\n DeviceChangeEvent,\n} from './types/transport';\n\nexport { DeviceJobQueue } from './utils/DeviceJobQueue';\nexport type {\n Interruptibility,\n PreemptionDecision,\n JobOptions,\n ActiveJobInfo,\n PreemptionEvent,\n} from './utils/DeviceJobQueue';\nexport type { IUiBridge } from './types/ui-bridge';\n\nexport type {\n ConnectorDevice,\n ConnectorSession,\n ConnectorEventType,\n ConnectorEventMap,\n IConnector,\n IHardwareBridge,\n} from './types/connector';\nexport { createBridgedConnector, EConnectorInteraction } from './types/connector';\n\nexport { TypedEventEmitter } from './utils/TypedEventEmitter';\nexport {\n UiRequestRegistry,\n UI_REQUEST_DEFAULT_TIMEOUT_MS,\n UI_REQUEST_PREEMPTED_TAG,\n UI_REQUEST_CANCELLED_TAG,\n UI_REQUEST_TIMEOUT_TAG,\n} from './utils/UiRequestRegistry';\nexport { compareSemver } from './utils/semver';\nexport { ensure0x, stripHex, padHex64, hexToBytes, bytesToHex } from './utils/hex';\nexport { enrichErrorMessage } from './utils/errorMessages';\nexport { batchCall } from './utils/batchCall';\n","export enum HardwareErrorCode {\n UnknownError = 0,\n DeviceNotFound = 1,\n DeviceDisconnected = 2,\n UserRejected = 3,\n DeviceBusy = 4,\n FirmwareUpdateRequired = 5,\n AppNotOpen = 6,\n InvalidParams = 7,\n TransportError = 8,\n OperationTimeout = 9,\n MethodNotSupported = 10,\n\n // PIN / Passphrase\n PinInvalid = 5520,\n PinCancelled = 5521,\n PassphraseRejected = 5522,\n\n // Device state\n DeviceLocked = 5530,\n DeviceNotInitialized = 5531,\n DeviceInBootloader = 5532,\n FirmwareTooOld = 5533,\n\n // Ledger specific\n WrongApp = 5540,\n\n // Device identity\n DeviceMismatch = 5560,\n\n // Transport\n BridgeNotFound = 5550,\n TransportNotAvailable = 5551,\n\n // --- EVM (Ledger Ethereum App) APDU-specific errors ---\n /** 0x6a80 Invalid data — observed on blindSignTransactionFallback when the\n * user has not enabled Blind signing on the device. */\n EvmBlindSigningRequired = 7001,\n /** 0x6984 Plugin not installed */\n EvmClearSignPluginMissing = 7002,\n /** 0x6a84 Insufficient memory (typical on Nano S with large calldata) */\n EvmDataTooLarge = 7003,\n /** 0x6501 TransactionType not supported (app too old for EIP-1559 / blob / 7702) */\n EvmTxTypeNotSupported = 7004,\n /** 0x911c Command code not supported — app predates current SDK */\n AppTooOld = 7005,\n}\n","import { HardwareErrorCode } from './errors';\n\nexport interface Success<T> {\n success: true;\n payload: T;\n}\n\nexport interface Failure {\n success: false;\n payload: {\n error: string;\n code: HardwareErrorCode;\n appName?: string;\n };\n}\n\nexport type Response<T> = Success<T> | Failure;\n\nexport function success<T>(payload: T): Success<T> {\n return { success: true, payload };\n}\n\nexport function failure(code: HardwareErrorCode, error: string, appName?: string): Failure {\n return { success: false, payload: { error, code, appName } };\n}\n","/**\n * Chain fingerprint utilities for device identity verification.\n *\n * Ledger devices have ephemeral IDs that change every session.\n * To verify that the same seed/device is connected, we derive an address\n * at a fixed path (account 0, index 0) and hash it into a stable \"chain fingerprint\".\n */\n\n/**\n * Fixed derivation paths used to generate chain fingerprints.\n * Uses standard index 0 — Ledger firmware shows device confirmation for\n * non-standard paths (e.g., index=100), which would interrupt wallet creation.\n * The address is hashed into a 16-char fingerprint, not exposed directly.\n * - EVM: cointype 60 (Ledger ETH App only supports 60)\n * - BTC: cointype 1 (testnet)\n * - SOL: cointype 501, standard 3-level hardened\n */\nexport const CHAIN_FINGERPRINT_PATHS: Record<ChainForFingerprint, string> = {\n evm: \"m/44'/60'/0'/0/0\",\n // BTC: account-level path (3 levels), mainnet cointype 0.\n // Cointype 1 (testnet) is rejected by some Ledger BTC App configurations.\n btc: \"m/44'/0'/0'\",\n sol: \"m/44'/501'/0'\",\n tron: \"m/44'/195'/0'/0/0\",\n};\n\nexport type ChainForFingerprint = 'evm' | 'btc' | 'sol' | 'tron';\n\n/**\n * Hash an address string into a 16-character hex fingerprint.\n *\n * Uses a simple non-cryptographic hash (FNV-1a based) to avoid\n * pulling in a SHA-256 dependency. This is NOT used for security —\n * only for device identity matching.\n */\nexport function deriveDeviceFingerprint(address: string): string {\n // FNV-1a 64-bit constants (split into two 32-bit halves for JS)\n let h1 = 0x811c9dc5;\n let h2 = 0x01000193;\n\n for (let i = 0; i < address.length; i++) {\n const c = address.charCodeAt(i);\n h1 = Math.imul(h1 ^ c, h2);\n h2 = Math.imul(h2 ^ (c >>> 4), 0x01000193);\n }\n\n // Mix the two halves for better distribution\n h1 = Math.imul(h1 ^ (h1 >>> 16), 0x45d9f3b);\n h2 = Math.imul(h2 ^ (h2 >>> 16), 0x45d9f3b);\n\n const hex1 = (h1 >>> 0).toString(16).padStart(8, '0');\n const hex2 = (h2 >>> 0).toString(16).padStart(8, '0');\n\n return `${hex1}${hex2}`;\n}\n","export const DEVICE_EVENT = 'DEVICE_EVENT';\n\n/** Events originating from the hardware device. */\nexport const DEVICE = {\n CONNECT: 'device-connect',\n DISCONNECT: 'device-disconnect',\n CHANGED: 'device-changed',\n ACQUIRE: 'device-acquire',\n RELEASE: 'device-release',\n FEATURES: 'features',\n SUPPORT_FEATURES: 'support_features',\n} as const;\n","import type { QrResponseData } from '../types/qr';\n\nexport const UI_EVENT = 'UI_EVENT';\n\nexport const UI_REQUEST = {\n REQUEST_PIN: 'ui-request-pin',\n REQUEST_PASSPHRASE: 'ui-request-passphrase',\n REQUEST_PASSPHRASE_ON_DEVICE: 'ui-request-passphrase-on-device',\n REQUEST_BUTTON: 'ui-request-button',\n REQUEST_QR_DISPLAY: 'ui-request-qr-display',\n REQUEST_QR_SCAN: 'ui-request-qr-scan',\n REQUEST_DEVICE_PERMISSION: 'ui-request-device-permission',\n REQUEST_SELECT_DEVICE: 'ui-request-select-device',\n REQUEST_DEVICE_CONNECT: 'ui-request-device-connect',\n CLOSE_UI_WINDOW: 'ui-close',\n DEVICE_PROGRESS: 'ui-device_progress',\n FIRMWARE_PROGRESS: 'ui-firmware-progress',\n FIRMWARE_TIP: 'ui-firmware-tip',\n} as const;\n\nexport const UI_RESPONSE = {\n RECEIVE_PIN: 'receive-pin',\n RECEIVE_PASSPHRASE: 'receive-passphrase',\n RECEIVE_PASSPHRASE_ON_DEVICE: 'receive-passphrase-on-device',\n RECEIVE_QR_RESPONSE: 'receive-qr-response',\n RECEIVE_SELECT_DEVICE: 'receive-select-device',\n RECEIVE_DEVICE_CONNECT: 'receive-device-connect',\n CANCEL: 'cancel',\n} as const;\n\nexport type UiResponseEvent =\n | {\n type: typeof UI_RESPONSE.RECEIVE_PIN;\n payload: string;\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_PASSPHRASE;\n payload: {\n value: string;\n passphraseOnDevice?: boolean;\n save?: boolean;\n };\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_PASSPHRASE_ON_DEVICE;\n payload?: undefined;\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_QR_RESPONSE;\n payload: QrResponseData;\n }\n | {\n // sdkConnectId echoes one of the DeviceInfo.connectId values emitted in\n // the REQUEST_SELECT_DEVICE event's `devices` list. Scope is the current\n // search session; may be ephemeral (e.g. Ledger USB DMK UUID).\n type: typeof UI_RESPONSE.RECEIVE_SELECT_DEVICE;\n payload: { sdkConnectId: string };\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_DEVICE_CONNECT;\n payload: { confirmed: boolean };\n }\n | {\n type: typeof UI_RESPONSE.CANCEL;\n payload?: undefined;\n };\n","/** Events generated by SDK internal detection (not from hardware directly). */\nexport const SDK = {\n DEVICE_STUCK: 'device-stuck',\n DEVICE_UNRESPONSIVE: 'device-unresponsive',\n DEVICE_RECOVERED: 'device-recovered',\n DEVICE_INTERACTION: 'device-interaction',\n} as const;\n","/**\n * Per-device serial job queue with preemption support and stuck recovery.\n * Ensures that only one operation runs at a time per device, with intelligent\n * handling of conflicting operations.\n */\n\nexport type Interruptibility = 'none' | 'safe' | 'confirm';\n\nexport type PreemptionDecision = 'cancel-current' | 'wait' | 'reject-new';\n\nexport interface JobOptions {\n interruptibility?: Interruptibility;\n label?: string;\n}\n\nexport interface ActiveJobInfo {\n label?: string;\n interruptibility: Interruptibility;\n startedAt: number;\n}\n\nexport interface PreemptionEvent {\n deviceId: string;\n currentJob: ActiveJobInfo;\n newJob: { label?: string; interruptibility: Interruptibility };\n}\n\ninterface ActiveJob {\n options: Required<Pick<JobOptions, 'interruptibility'>> & Pick<JobOptions, 'label'>;\n abortController: AbortController;\n startedAt: number;\n}\n\nexport class DeviceJobQueue {\n private readonly _queues = new Map<string, Promise<unknown>>();\n private readonly _active = new Map<string, ActiveJob>();\n\n /**\n * Called when a new job conflicts with an active 'confirm'-level job.\n * UI should show a dialog and return the user's decision.\n * If not set, defaults to 'wait' (queue behind current job).\n */\n onPreemptionRequest?: (event: PreemptionEvent) => Promise<PreemptionDecision>;\n\n /**\n * Enqueue a job for a specific device.\n * If a job is already running for this device, behavior depends on interruptibility:\n * - 'none': new job queues silently (no preemption possible)\n * - 'safe': current job is auto-cancelled, new job runs immediately after\n * - 'confirm': onPreemptionRequest is called to ask user\n */\n async enqueue<T>(\n deviceId: string,\n job: (signal: AbortSignal) => Promise<T>,\n options: JobOptions = {}\n ): Promise<T> {\n const interruptibility = options.interruptibility ?? 'confirm';\n const active = this._active.get(deviceId);\n\n if (active) {\n switch (active.options.interruptibility) {\n case 'none':\n // Cannot interrupt, just queue behind\n break;\n case 'safe':\n // Auto-cancel current safe operation\n active.abortController.abort(new Error('Preempted by new operation'));\n break;\n case 'confirm': {\n if (this.onPreemptionRequest) {\n const decision = await this.onPreemptionRequest({\n deviceId,\n currentJob: {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n },\n newJob: {\n label: options.label,\n interruptibility,\n },\n });\n switch (decision) {\n case 'cancel-current':\n active.abortController.abort(new Error('Cancelled by user via preemption'));\n break;\n case 'reject-new':\n throw Object.assign(\n new Error(`Device busy: ${active.options.label ?? 'unknown operation'}`),\n { hardwareErrorCode: 'DEVICE_BUSY' }\n );\n case 'wait':\n break;\n }\n }\n break;\n }\n }\n }\n\n const ac = new AbortController();\n const prev = this._queues.get(deviceId) ?? Promise.resolve();\n\n const next = prev\n .catch(() => {})\n .then(async () => {\n this._active.set(deviceId, {\n options: { interruptibility, label: options.label },\n abortController: ac,\n startedAt: Date.now(),\n });\n try {\n return await job(ac.signal);\n } finally {\n this._active.delete(deviceId);\n }\n });\n\n const tail = next.catch(() => {});\n this._queues.set(deviceId, tail);\n tail.then(() => {\n if (this._queues.get(deviceId) === tail) {\n this._queues.delete(deviceId);\n }\n });\n return next;\n }\n\n /** Manually cancel the active job on a device. Returns false if job is non-interruptible. */\n cancelActive(deviceId: string): boolean {\n const active = this._active.get(deviceId);\n if (!active) return false;\n if (active.options.interruptibility === 'none') return false;\n active.abortController.abort(new Error('Manually cancelled'));\n return true;\n }\n\n /** Force cancel regardless of interruptibility. Use for device stuck recovery. */\n forceCancelActive(deviceId: string): boolean {\n const active = this._active.get(deviceId);\n if (!active) return false;\n active.abortController.abort(new Error('Force cancelled for recovery'));\n return true;\n }\n\n /** Get info about the currently active job for a device, or null if idle. */\n getActiveJob(deviceId: string): ActiveJobInfo | null {\n const active = this._active.get(deviceId);\n if (!active) return null;\n return {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n };\n }\n\n clear(): void {\n // Abort all active jobs\n for (const active of this._active.values()) {\n active.abortController.abort(new Error('Queue cleared'));\n }\n this._active.clear();\n this._queues.clear();\n }\n}\n","import type { DeviceCapabilities, DeviceInfo, VendorType } from './device';\nimport type { UiResponseEvent } from '../events/ui-request';\n\n// =====================================================================\n// Connector types — transport-level abstraction for device communication\n// =====================================================================\n\n/**\n * Minimal device info returned during discovery (searchDevices).\n * At scan time, full DeviceInfo fields like firmwareVersion are not yet available.\n */\nexport interface ConnectorDevice {\n connectId: string;\n deviceId: string;\n name: string;\n model?: string;\n\n /** Device capabilities — available from scan time */\n capabilities?: DeviceCapabilities;\n}\n\nexport interface ConnectorSession {\n sessionId: string;\n deviceInfo: DeviceInfo;\n}\n\nexport type ConnectorEventType = 'device-connect' | 'device-disconnect' | 'ui-request' | 'ui-event';\n\n/**\n * Interaction event types emitted via 'ui-event'.\n * These map to user-facing prompts (confirm on device, open app, etc.).\n */\nexport enum EConnectorInteraction {\n /** Device requires user to open a specific app */\n ConfirmOpenApp = 'confirm-open-app',\n /** Device requires user to unlock */\n UnlockDevice = 'unlock-device',\n /** Device needs user to confirm on device (sign, verify, etc.) */\n ConfirmOnDevice = 'confirm-on-device',\n /** Previous interaction completed — clear UI prompt */\n InteractionComplete = 'interaction-complete',\n}\n\nexport type ConnectorUiEvent =\n | { type: EConnectorInteraction.ConfirmOpenApp; payload: { sessionId: string } }\n | { type: EConnectorInteraction.UnlockDevice; payload: { sessionId: string } }\n | { type: EConnectorInteraction.ConfirmOnDevice; payload: { sessionId: string } }\n | { type: EConnectorInteraction.InteractionComplete; payload: { sessionId: string } };\n\nexport interface ConnectorEventMap {\n 'device-connect': { device: ConnectorDevice };\n 'device-disconnect': { connectId: string };\n 'ui-request': { type: string; payload?: unknown };\n 'ui-event': ConnectorUiEvent;\n}\n\nexport interface IConnector {\n searchDevices(): Promise<ConnectorDevice[]>;\n connect(deviceId?: string): Promise<ConnectorSession>;\n disconnect(sessionId: string): Promise<void>;\n call(sessionId: string, method: string, params: unknown): Promise<unknown>;\n cancel(sessionId: string): Promise<void>;\n\n /** Send a UI response (e.g. PIN, passphrase) to the device. */\n uiResponse(response: UiResponseEvent): void;\n\n on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;\n off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;\n\n reset(): void;\n}\n\n// =====================================================================\n// Hardware bridge — generic forwarding interface for cross-boundary IConnector\n//\n// The same shape works across any process / context boundary that needs to\n// expose a multi-vendor backend behind a single-vendor IConnector facade:\n// - Electron (renderer ↔ preload/main via contextBridge)\n// - Browser Extension (popup/content ↔ background/offscreen via chrome.runtime)\n// - React Native (JS ↔ native module via NativeModules)\n// - Web Worker / iframe (postMessage)\n//\n// Each method takes a `vendor` discriminator so a single bridge implementation\n// can multiplex across vendors (ledger, trezor, ...).\n// =====================================================================\n\nexport interface IHardwareBridge {\n searchDevices(params: { vendor: VendorType }): Promise<ConnectorDevice[]>;\n connect(params: { vendor: VendorType; deviceId?: string }): Promise<ConnectorSession>;\n disconnect(params: { vendor: VendorType; sessionId: string }): Promise<void>;\n call(params: {\n vendor: VendorType;\n sessionId: string;\n method: string;\n callParams: unknown;\n }): Promise<unknown>;\n cancel(params: { vendor: VendorType; sessionId: string }): Promise<void>;\n uiResponse(params: { vendor: VendorType; response: UiResponseEvent }): void;\n reset(params: { vendor: VendorType }): void;\n\n /** Register an event handler for connector events forwarded across the bridge. */\n onEvent(\n params: { vendor: VendorType },\n handler: (event: { type: ConnectorEventType; data: unknown }) => void\n ): void;\n\n /** Unregister a previously registered event handler. */\n offEvent(\n params: { vendor: VendorType },\n handler: (event: { type: ConnectorEventType; data: unknown }) => void\n ): void;\n}\n\n/**\n * Adapt an IHardwareBridge (multi-vendor backend) into a single-vendor IConnector.\n * Every IConnector method becomes a transparent forward to bridge.<method>({ vendor, ... }).\n * Events are forwarded via bridge.onEvent / offEvent.\n *\n * Use this anywhere the actual hardware lives behind a process / context boundary\n * (Electron main, extension background, native module, worker, iframe).\n */\nexport function createBridgedConnector(\n vendor: VendorType,\n bridge: IHardwareBridge\n): IConnector {\n // Map from typed IConnector handlers to the bridge handler so we can\n // unregister them correctly via off().\n const handlerMap = new Map<\n (data: ConnectorEventMap[ConnectorEventType]) => void,\n (event: { type: ConnectorEventType; data: unknown }) => void\n >();\n\n return {\n searchDevices: () => bridge.searchDevices({ vendor }),\n connect: deviceId => bridge.connect({ vendor, deviceId }),\n disconnect: sessionId => bridge.disconnect({ vendor, sessionId }),\n call: (sessionId, method, callParams) => bridge.call({ vendor, sessionId, method, callParams }),\n cancel: sessionId => bridge.cancel({ vendor, sessionId }),\n uiResponse: response => bridge.uiResponse({ vendor, response }),\n on: (event, handler) => {\n const bridgeHandler = (e: { type: ConnectorEventType; data: unknown }) => {\n if (e.type === event) {\n handler(e.data as ConnectorEventMap[typeof event]);\n }\n };\n handlerMap.set(\n handler as (data: ConnectorEventMap[ConnectorEventType]) => void,\n bridgeHandler\n );\n bridge.onEvent({ vendor }, bridgeHandler);\n },\n off: (_event, handler) => {\n const bridgeHandler = handlerMap.get(\n handler as (data: ConnectorEventMap[ConnectorEventType]) => void\n );\n if (bridgeHandler) {\n bridge.offEvent({ vendor }, bridgeHandler);\n handlerMap.delete(handler as (data: ConnectorEventMap[ConnectorEventType]) => void);\n }\n },\n reset: () => bridge.reset({ vendor }),\n };\n}\n","/**\n * Minimal typed event emitter using Map<string, Set<listener>>.\n * Each adapter uses this for device events (connect, disconnect, pin, etc.).\n *\n * TMap is a record mapping event name strings to their payload types.\n * Example:\n * type MyEvents = { 'connect': { id: string }; 'disconnect': { id: string } };\n * const emitter = new TypedEventEmitter<MyEvents>();\n * emitter.on('connect', (data) => { data.id }); // data is { id: string }\n *\n * For backward compatibility, TMap defaults to Record<string, any> so that\n * existing code using `new TypedEventEmitter<SomeUnionType>()` still compiles.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class TypedEventEmitter<TMap extends Record<string, any> = Record<string, any>> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly _listeners = new Map<string, Set<(event: any) => void>>();\n\n on<K extends keyof TMap & string>(event: K, listener: (event: TMap[K]) => void): void;\n on(event: string, listener: (event: any) => void): void;\n on(event: string, listener: (event: any) => void): void {\n let set = this._listeners.get(event);\n if (!set) {\n set = new Set();\n this._listeners.set(event, set);\n }\n set.add(listener);\n }\n\n off<K extends keyof TMap & string>(event: K, listener: (event: TMap[K]) => void): void;\n off(event: string, listener: (event: any) => void): void;\n off(event: string, listener: (event: any) => void): void {\n const set = this._listeners.get(event);\n if (set) {\n set.delete(listener);\n if (set.size === 0) this._listeners.delete(event);\n }\n }\n\n emit<K extends keyof TMap & string>(event: K, data: TMap[K]): void;\n emit(event: string, data: unknown): void;\n emit(event: string, data: unknown): void {\n const set = this._listeners.get(event);\n if (set) {\n for (const listener of set) listener(data);\n }\n }\n\n removeAllListeners(): void {\n this._listeners.clear();\n }\n}\n","import { UI_REQUEST, UI_RESPONSE } from '../events/ui-request';\n\n/** 10 min — every UI request is human-in-the-loop; bias toward \"wait long\". */\nexport const UI_REQUEST_DEFAULT_TIMEOUT_MS = 600_000;\n\nconst RESPONSE_TO_REQUEST: Record<string, string> = {\n [UI_RESPONSE.RECEIVE_PIN]: UI_REQUEST.REQUEST_PIN,\n [UI_RESPONSE.RECEIVE_PASSPHRASE]: UI_REQUEST.REQUEST_PASSPHRASE,\n [UI_RESPONSE.RECEIVE_PASSPHRASE_ON_DEVICE]: UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE,\n [UI_RESPONSE.RECEIVE_SELECT_DEVICE]: UI_REQUEST.REQUEST_SELECT_DEVICE,\n [UI_RESPONSE.RECEIVE_DEVICE_CONNECT]: UI_REQUEST.REQUEST_DEVICE_CONNECT,\n // RECEIVE_QR_RESPONSE maps to QR_DISPLAY or QR_SCAN — resolved dynamically below.\n};\n\nexport const UI_REQUEST_PREEMPTED_TAG = 'UiRequestPreempted';\nexport const UI_REQUEST_CANCELLED_TAG = 'UiRequestCancelled';\nexport const UI_REQUEST_TIMEOUT_TAG = 'UiRequestTimeout';\n\ntype PendingEntry = {\n resolve: (payload: unknown) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\n/**\n * Per-type single-slot registry for adapter-level UI requests. A new `wait`\n * of the same type preempts (rejects) the prior one. Unknown response types\n * are dropped silently so the public `uiResponse` entry never throws.\n */\nexport class UiRequestRegistry {\n private pending = new Map<string, PendingEntry>();\n\n wait<T = unknown>(\n requestType: string,\n options?: { timeoutMs?: number }\n ): Promise<T> {\n const existing = this.pending.get(requestType);\n if (existing) {\n clearTimeout(existing.timer);\n this.pending.delete(requestType);\n existing.reject(\n Object.assign(\n new Error(`UI request '${requestType}' was superseded by a new request`),\n { _tag: UI_REQUEST_PREEMPTED_TAG }\n )\n );\n }\n\n const timeoutMs = options?.timeoutMs ?? UI_REQUEST_DEFAULT_TIMEOUT_MS;\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n if (this.pending.get(requestType)?.timer === timer) {\n this.pending.delete(requestType);\n reject(\n Object.assign(\n new Error(`UI request '${requestType}' timed out after ${timeoutMs}ms`),\n { _tag: UI_REQUEST_TIMEOUT_TAG }\n )\n );\n }\n }, timeoutMs);\n\n this.pending.set(requestType, {\n resolve: resolve as (payload: unknown) => void,\n reject,\n timer,\n });\n });\n }\n\n resolve(responseType: string, payload: unknown): void {\n let requestType = RESPONSE_TO_REQUEST[responseType];\n if (responseType === UI_RESPONSE.RECEIVE_QR_RESPONSE) {\n if (this.pending.has(UI_REQUEST.REQUEST_QR_DISPLAY)) {\n requestType = UI_REQUEST.REQUEST_QR_DISPLAY;\n } else if (this.pending.has(UI_REQUEST.REQUEST_QR_SCAN)) {\n requestType = UI_REQUEST.REQUEST_QR_SCAN;\n }\n }\n if (!requestType) return;\n\n const entry = this.pending.get(requestType);\n if (!entry) return;\n\n clearTimeout(entry.timer);\n this.pending.delete(requestType);\n entry.resolve(payload);\n }\n\n cancel(requestType?: string): void {\n if (requestType) {\n const entry = this.pending.get(requestType);\n if (!entry) return;\n clearTimeout(entry.timer);\n this.pending.delete(requestType);\n entry.reject(\n Object.assign(new Error(`UI request '${requestType}' was cancelled`), {\n _tag: UI_REQUEST_CANCELLED_TAG,\n })\n );\n return;\n }\n\n for (const [type, entry] of this.pending) {\n clearTimeout(entry.timer);\n entry.reject(\n Object.assign(new Error(`UI request '${type}' was cancelled`), {\n _tag: UI_REQUEST_CANCELLED_TAG,\n })\n );\n }\n this.pending.clear();\n }\n\n reset(): void {\n this.cancel();\n }\n\n hasPending(requestType: string): boolean {\n return this.pending.has(requestType);\n }\n}\n","/**\n * Compare two semver strings (e.g. \"2.1.0\" vs \"2.3.1\").\n * Returns -1 if a < b, 0 if equal, 1 if a > b.\n */\nexport function compareSemver(a: string, b: string): number {\n const pa = a.split('.').map(Number);\n const pb = b.split('.').map(Number);\n for (let i = 0; i < 3; i++) {\n const va = pa[i] ?? 0;\n const vb = pb[i] ?? 0;\n if (va < vb) return -1;\n if (va > vb) return 1;\n }\n return 0;\n}\n","/** Ensure hex string has 0x prefix */\nexport function ensure0x(hex: string): string {\n return hex.startsWith('0x') ? hex : `0x${hex}`;\n}\n\n/** Strip 0x prefix from hex string */\nexport function stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Pad hex to 64 chars (32 bytes) with 0x prefix */\nexport function padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n/** Convert a hex string (with or without 0x prefix) to a Uint8Array. */\nexport function hexToBytes(hex: string): Uint8Array {\n const clean = stripHex(hex);\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/** Convert a Uint8Array to a hex string (no 0x prefix). */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n}\n","import { HardwareErrorCode } from '../types/errors';\n\n/**\n * Enrich a hardware error message with actionable recovery hints.\n * Shared across adapters (Ledger, Trezor, etc.).\n */\nexport function enrichErrorMessage(code: HardwareErrorCode, originalMessage: string): string {\n switch (code) {\n case HardwareErrorCode.PinInvalid:\n return `${originalMessage}. Please re-enter your PIN.`;\n case HardwareErrorCode.PinCancelled:\n return `${originalMessage}. PIN entry was cancelled.`;\n case HardwareErrorCode.DeviceBusy:\n return `${originalMessage}. The device is in use by another application. Close other wallet apps and try again.`;\n case HardwareErrorCode.DeviceDisconnected:\n return `${originalMessage}. Please reconnect the device and try again.`;\n case HardwareErrorCode.DeviceLocked:\n return `${originalMessage}. Please unlock your device and try again.`;\n case HardwareErrorCode.UserRejected:\n return `${originalMessage}. The request was rejected on the device.`;\n case HardwareErrorCode.WrongApp:\n return `${originalMessage}. Please open the correct app on your device.`;\n case HardwareErrorCode.AppNotOpen:\n return `${originalMessage}. The required app is not installed on the device.`;\n case HardwareErrorCode.TransportNotAvailable:\n return `${originalMessage}. Ensure the device bridge/transport is available and running.`;\n case HardwareErrorCode.FirmwareTooOld:\n return `${originalMessage}. Please update your device firmware.`;\n case HardwareErrorCode.DeviceNotInitialized:\n return `${originalMessage}. The device may need to be set up first.`;\n case HardwareErrorCode.OperationTimeout:\n return `${originalMessage}. The operation timed out. Please try again.`;\n case HardwareErrorCode.EvmBlindSigningRequired:\n return 'Please enable Blind signing on your Ledger: open the Ethereum app → Settings → Blind signing → Enabled, then try again.';\n case HardwareErrorCode.EvmClearSignPluginMissing:\n return 'Required Ledger plugin is not installed. Please install the matching plugin on Ledger Live, then try again.';\n case HardwareErrorCode.EvmDataTooLarge:\n return 'Transaction data is too large for your Ledger device. Try a simpler transaction or use a Ledger with more memory.';\n case HardwareErrorCode.EvmTxTypeNotSupported:\n return 'Transaction type is not supported by your Ledger Ethereum app. Please update the app to the latest version.';\n case HardwareErrorCode.AppTooOld:\n return 'Your Ledger app is out of date. Please update it via Ledger Live.';\n default:\n return originalMessage;\n }\n}\n","import type { Response } from '../types/response';\n\n/**\n * Generic batch call with progress reporting.\n * If any single call fails, returns the failure immediately.\n */\nexport async function batchCall<TParam, TResult>(\n params: TParam[],\n callFn: (p: TParam) => Promise<Response<TResult>>,\n onProgress?: (progress: { index: number; total: number }) => void\n): Promise<Response<TResult[]>> {\n const results: TResult[] = [];\n for (let i = 0; i < params.length; i++) {\n const result = await callFn(params[i]);\n if (!result.success) {\n return result;\n }\n results.push(result.payload);\n onProgress?.({ index: i, total: params.length });\n }\n return { success: true, payload: results };\n}\n"],"mappings":"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","names":["HardwareErrorCode","EConnectorInteraction"]}
package/dist/index.mjs CHANGED
@@ -22,6 +22,11 @@ var HardwareErrorCode = /* @__PURE__ */ ((HardwareErrorCode2) => {
22
22
  HardwareErrorCode2[HardwareErrorCode2["DeviceMismatch"] = 5560] = "DeviceMismatch";
23
23
  HardwareErrorCode2[HardwareErrorCode2["BridgeNotFound"] = 5550] = "BridgeNotFound";
24
24
  HardwareErrorCode2[HardwareErrorCode2["TransportNotAvailable"] = 5551] = "TransportNotAvailable";
25
+ HardwareErrorCode2[HardwareErrorCode2["EvmBlindSigningRequired"] = 7001] = "EvmBlindSigningRequired";
26
+ HardwareErrorCode2[HardwareErrorCode2["EvmClearSignPluginMissing"] = 7002] = "EvmClearSignPluginMissing";
27
+ HardwareErrorCode2[HardwareErrorCode2["EvmDataTooLarge"] = 7003] = "EvmDataTooLarge";
28
+ HardwareErrorCode2[HardwareErrorCode2["EvmTxTypeNotSupported"] = 7004] = "EvmTxTypeNotSupported";
29
+ HardwareErrorCode2[HardwareErrorCode2["AppTooOld"] = 7005] = "AppTooOld";
25
30
  return HardwareErrorCode2;
26
31
  })(HardwareErrorCode || {});
27
32
 
@@ -29,8 +34,8 @@ var HardwareErrorCode = /* @__PURE__ */ ((HardwareErrorCode2) => {
29
34
  function success(payload) {
30
35
  return { success: true, payload };
31
36
  }
32
- function failure(code, error) {
33
- return { success: false, payload: { error, code } };
37
+ function failure(code, error, appName) {
38
+ return { success: false, payload: { error, code, appName } };
34
39
  }
35
40
 
36
41
  // src/types/fingerprint.ts
@@ -92,6 +97,7 @@ var UI_RESPONSE = {
92
97
  RECEIVE_PASSPHRASE_ON_DEVICE: "receive-passphrase-on-device",
93
98
  RECEIVE_QR_RESPONSE: "receive-qr-response",
94
99
  RECEIVE_SELECT_DEVICE: "receive-select-device",
100
+ RECEIVE_DEVICE_CONNECT: "receive-device-connect",
95
101
  CANCEL: "cancel"
96
102
  };
97
103
 
@@ -290,6 +296,102 @@ var TypedEventEmitter = class {
290
296
  }
291
297
  };
292
298
 
299
+ // src/utils/UiRequestRegistry.ts
300
+ var UI_REQUEST_DEFAULT_TIMEOUT_MS = 6e5;
301
+ var RESPONSE_TO_REQUEST = {
302
+ [UI_RESPONSE.RECEIVE_PIN]: UI_REQUEST.REQUEST_PIN,
303
+ [UI_RESPONSE.RECEIVE_PASSPHRASE]: UI_REQUEST.REQUEST_PASSPHRASE,
304
+ [UI_RESPONSE.RECEIVE_PASSPHRASE_ON_DEVICE]: UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE,
305
+ [UI_RESPONSE.RECEIVE_SELECT_DEVICE]: UI_REQUEST.REQUEST_SELECT_DEVICE,
306
+ [UI_RESPONSE.RECEIVE_DEVICE_CONNECT]: UI_REQUEST.REQUEST_DEVICE_CONNECT
307
+ // RECEIVE_QR_RESPONSE maps to QR_DISPLAY or QR_SCAN — resolved dynamically below.
308
+ };
309
+ var UI_REQUEST_PREEMPTED_TAG = "UiRequestPreempted";
310
+ var UI_REQUEST_CANCELLED_TAG = "UiRequestCancelled";
311
+ var UI_REQUEST_TIMEOUT_TAG = "UiRequestTimeout";
312
+ var UiRequestRegistry = class {
313
+ constructor() {
314
+ this.pending = /* @__PURE__ */ new Map();
315
+ }
316
+ wait(requestType, options) {
317
+ const existing = this.pending.get(requestType);
318
+ if (existing) {
319
+ clearTimeout(existing.timer);
320
+ this.pending.delete(requestType);
321
+ existing.reject(
322
+ Object.assign(
323
+ new Error(`UI request '${requestType}' was superseded by a new request`),
324
+ { _tag: UI_REQUEST_PREEMPTED_TAG }
325
+ )
326
+ );
327
+ }
328
+ const timeoutMs = options?.timeoutMs ?? UI_REQUEST_DEFAULT_TIMEOUT_MS;
329
+ return new Promise((resolve, reject) => {
330
+ const timer = setTimeout(() => {
331
+ if (this.pending.get(requestType)?.timer === timer) {
332
+ this.pending.delete(requestType);
333
+ reject(
334
+ Object.assign(
335
+ new Error(`UI request '${requestType}' timed out after ${timeoutMs}ms`),
336
+ { _tag: UI_REQUEST_TIMEOUT_TAG }
337
+ )
338
+ );
339
+ }
340
+ }, timeoutMs);
341
+ this.pending.set(requestType, {
342
+ resolve,
343
+ reject,
344
+ timer
345
+ });
346
+ });
347
+ }
348
+ resolve(responseType, payload) {
349
+ let requestType = RESPONSE_TO_REQUEST[responseType];
350
+ if (responseType === UI_RESPONSE.RECEIVE_QR_RESPONSE) {
351
+ if (this.pending.has(UI_REQUEST.REQUEST_QR_DISPLAY)) {
352
+ requestType = UI_REQUEST.REQUEST_QR_DISPLAY;
353
+ } else if (this.pending.has(UI_REQUEST.REQUEST_QR_SCAN)) {
354
+ requestType = UI_REQUEST.REQUEST_QR_SCAN;
355
+ }
356
+ }
357
+ if (!requestType) return;
358
+ const entry = this.pending.get(requestType);
359
+ if (!entry) return;
360
+ clearTimeout(entry.timer);
361
+ this.pending.delete(requestType);
362
+ entry.resolve(payload);
363
+ }
364
+ cancel(requestType) {
365
+ if (requestType) {
366
+ const entry = this.pending.get(requestType);
367
+ if (!entry) return;
368
+ clearTimeout(entry.timer);
369
+ this.pending.delete(requestType);
370
+ entry.reject(
371
+ Object.assign(new Error(`UI request '${requestType}' was cancelled`), {
372
+ _tag: UI_REQUEST_CANCELLED_TAG
373
+ })
374
+ );
375
+ return;
376
+ }
377
+ for (const [type, entry] of this.pending) {
378
+ clearTimeout(entry.timer);
379
+ entry.reject(
380
+ Object.assign(new Error(`UI request '${type}' was cancelled`), {
381
+ _tag: UI_REQUEST_CANCELLED_TAG
382
+ })
383
+ );
384
+ }
385
+ this.pending.clear();
386
+ }
387
+ reset() {
388
+ this.cancel();
389
+ }
390
+ hasPending(requestType) {
391
+ return this.pending.has(requestType);
392
+ }
393
+ };
394
+
293
395
  // src/utils/semver.ts
294
396
  function compareSemver(a, b) {
295
397
  const pa = a.split(".").map(Number);
@@ -352,6 +454,16 @@ function enrichErrorMessage(code, originalMessage) {
352
454
  return `${originalMessage}. The device may need to be set up first.`;
353
455
  case 9 /* OperationTimeout */:
354
456
  return `${originalMessage}. The operation timed out. Please try again.`;
457
+ case 7001 /* EvmBlindSigningRequired */:
458
+ return "Please enable Blind signing on your Ledger: open the Ethereum app \u2192 Settings \u2192 Blind signing \u2192 Enabled, then try again.";
459
+ case 7002 /* EvmClearSignPluginMissing */:
460
+ return "Required Ledger plugin is not installed. Please install the matching plugin on Ledger Live, then try again.";
461
+ case 7003 /* EvmDataTooLarge */:
462
+ return "Transaction data is too large for your Ledger device. Try a simpler transaction or use a Ledger with more memory.";
463
+ case 7004 /* EvmTxTypeNotSupported */:
464
+ return "Transaction type is not supported by your Ledger Ethereum app. Please update the app to the latest version.";
465
+ case 7005 /* AppTooOld */:
466
+ return "Your Ledger app is out of date. Please update it via Ledger Live.";
355
467
  default:
356
468
  return originalMessage;
357
469
  }
@@ -381,7 +493,12 @@ export {
381
493
  TypedEventEmitter,
382
494
  UI_EVENT,
383
495
  UI_REQUEST,
496
+ UI_REQUEST_CANCELLED_TAG,
497
+ UI_REQUEST_DEFAULT_TIMEOUT_MS,
498
+ UI_REQUEST_PREEMPTED_TAG,
499
+ UI_REQUEST_TIMEOUT_TAG,
384
500
  UI_RESPONSE,
501
+ UiRequestRegistry,
385
502
  batchCall,
386
503
  bytesToHex,
387
504
  compareSemver,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types/errors.ts","../src/types/response.ts","../src/types/fingerprint.ts","../src/events/device.ts","../src/events/ui-request.ts","../src/events/sdk.ts","../src/utils/DeviceJobQueue.ts","../src/types/connector.ts","../src/utils/TypedEventEmitter.ts","../src/utils/semver.ts","../src/utils/hex.ts","../src/utils/errorMessages.ts","../src/utils/batchCall.ts"],"sourcesContent":["export enum HardwareErrorCode {\n UnknownError = 0,\n DeviceNotFound = 1,\n DeviceDisconnected = 2,\n UserRejected = 3,\n DeviceBusy = 4,\n FirmwareUpdateRequired = 5,\n AppNotOpen = 6,\n InvalidParams = 7,\n TransportError = 8,\n OperationTimeout = 9,\n MethodNotSupported = 10,\n\n // PIN / Passphrase\n PinInvalid = 5520,\n PinCancelled = 5521,\n PassphraseRejected = 5522,\n\n // Device state\n DeviceLocked = 5530,\n DeviceNotInitialized = 5531,\n DeviceInBootloader = 5532,\n FirmwareTooOld = 5533,\n\n // Ledger specific\n WrongApp = 5540,\n\n // Device identity\n DeviceMismatch = 5560,\n\n // Transport\n BridgeNotFound = 5550,\n TransportNotAvailable = 5551,\n}\n","import { HardwareErrorCode } from './errors';\n\nexport interface Success<T> {\n success: true;\n payload: T;\n}\n\nexport interface Failure {\n success: false;\n payload: {\n error: string;\n code: HardwareErrorCode;\n };\n}\n\nexport type Response<T> = Success<T> | Failure;\n\nexport function success<T>(payload: T): Success<T> {\n return { success: true, payload };\n}\n\nexport function failure(code: HardwareErrorCode, error: string): Failure {\n return { success: false, payload: { error, code } };\n}\n","/**\n * Chain fingerprint utilities for device identity verification.\n *\n * Ledger devices have ephemeral IDs that change every session.\n * To verify that the same seed/device is connected, we derive an address\n * at a fixed path (account 0, index 0) and hash it into a stable \"chain fingerprint\".\n */\n\n/**\n * Fixed derivation paths used to generate chain fingerprints.\n * Uses standard index 0 — Ledger firmware shows device confirmation for\n * non-standard paths (e.g., index=100), which would interrupt wallet creation.\n * The address is hashed into a 16-char fingerprint, not exposed directly.\n * - EVM: cointype 60 (Ledger ETH App only supports 60)\n * - BTC: cointype 1 (testnet)\n * - SOL: cointype 501, standard 3-level hardened\n */\nexport const CHAIN_FINGERPRINT_PATHS: Record<ChainForFingerprint, string> = {\n evm: \"m/44'/60'/0'/0/0\",\n // BTC: account-level path (3 levels), mainnet cointype 0.\n // Cointype 1 (testnet) is rejected by some Ledger BTC App configurations.\n btc: \"m/44'/0'/0'\",\n sol: \"m/44'/501'/0'\",\n tron: \"m/44'/195'/0'/0/0\",\n};\n\nexport type ChainForFingerprint = 'evm' | 'btc' | 'sol' | 'tron';\n\n/**\n * Hash an address string into a 16-character hex fingerprint.\n *\n * Uses a simple non-cryptographic hash (FNV-1a based) to avoid\n * pulling in a SHA-256 dependency. This is NOT used for security —\n * only for device identity matching.\n */\nexport function deriveDeviceFingerprint(address: string): string {\n // FNV-1a 64-bit constants (split into two 32-bit halves for JS)\n let h1 = 0x811c9dc5;\n let h2 = 0x01000193;\n\n for (let i = 0; i < address.length; i++) {\n const c = address.charCodeAt(i);\n h1 = Math.imul(h1 ^ c, h2);\n h2 = Math.imul(h2 ^ (c >>> 4), 0x01000193);\n }\n\n // Mix the two halves for better distribution\n h1 = Math.imul(h1 ^ (h1 >>> 16), 0x45d9f3b);\n h2 = Math.imul(h2 ^ (h2 >>> 16), 0x45d9f3b);\n\n const hex1 = (h1 >>> 0).toString(16).padStart(8, '0');\n const hex2 = (h2 >>> 0).toString(16).padStart(8, '0');\n\n return `${hex1}${hex2}`;\n}\n","export const DEVICE_EVENT = 'DEVICE_EVENT';\n\n/** Events originating from the hardware device. */\nexport const DEVICE = {\n CONNECT: 'device-connect',\n DISCONNECT: 'device-disconnect',\n CHANGED: 'device-changed',\n ACQUIRE: 'device-acquire',\n RELEASE: 'device-release',\n FEATURES: 'features',\n SUPPORT_FEATURES: 'support_features',\n} as const;\n","export const UI_EVENT = 'UI_EVENT';\n\nexport const UI_REQUEST = {\n REQUEST_PIN: 'ui-request-pin',\n REQUEST_PASSPHRASE: 'ui-request-passphrase',\n REQUEST_PASSPHRASE_ON_DEVICE: 'ui-request-passphrase-on-device',\n REQUEST_BUTTON: 'ui-request-button',\n REQUEST_QR_DISPLAY: 'ui-request-qr-display',\n REQUEST_QR_SCAN: 'ui-request-qr-scan',\n REQUEST_DEVICE_PERMISSION: 'ui-request-device-permission',\n REQUEST_SELECT_DEVICE: 'ui-request-select-device',\n REQUEST_DEVICE_CONNECT: 'ui-request-device-connect',\n CLOSE_UI_WINDOW: 'ui-close',\n DEVICE_PROGRESS: 'ui-device_progress',\n FIRMWARE_PROGRESS: 'ui-firmware-progress',\n FIRMWARE_TIP: 'ui-firmware-tip',\n} as const;\n\nexport const UI_RESPONSE = {\n RECEIVE_PIN: 'receive-pin',\n RECEIVE_PASSPHRASE: 'receive-passphrase',\n RECEIVE_PASSPHRASE_ON_DEVICE: 'receive-passphrase-on-device',\n RECEIVE_QR_RESPONSE: 'receive-qr-response',\n RECEIVE_SELECT_DEVICE: 'receive-select-device',\n CANCEL: 'cancel',\n} as const;\n","/** Events generated by SDK internal detection (not from hardware directly). */\nexport const SDK = {\n DEVICE_STUCK: 'device-stuck',\n DEVICE_UNRESPONSIVE: 'device-unresponsive',\n DEVICE_RECOVERED: 'device-recovered',\n DEVICE_INTERACTION: 'device-interaction',\n} as const;\n","/**\n * Per-device serial job queue with preemption support and stuck recovery.\n * Ensures that only one operation runs at a time per device, with intelligent\n * handling of conflicting operations.\n */\n\nexport type Interruptibility = 'none' | 'safe' | 'confirm';\n\nexport type PreemptionDecision = 'cancel-current' | 'wait' | 'reject-new';\n\nexport interface JobOptions {\n interruptibility?: Interruptibility;\n label?: string;\n}\n\nexport interface ActiveJobInfo {\n label?: string;\n interruptibility: Interruptibility;\n startedAt: number;\n}\n\nexport interface PreemptionEvent {\n deviceId: string;\n currentJob: ActiveJobInfo;\n newJob: { label?: string; interruptibility: Interruptibility };\n}\n\ninterface ActiveJob {\n options: Required<Pick<JobOptions, 'interruptibility'>> & Pick<JobOptions, 'label'>;\n abortController: AbortController;\n startedAt: number;\n}\n\nexport class DeviceJobQueue {\n private readonly _queues = new Map<string, Promise<unknown>>();\n private readonly _active = new Map<string, ActiveJob>();\n\n /**\n * Called when a new job conflicts with an active 'confirm'-level job.\n * UI should show a dialog and return the user's decision.\n * If not set, defaults to 'wait' (queue behind current job).\n */\n onPreemptionRequest?: (event: PreemptionEvent) => Promise<PreemptionDecision>;\n\n /**\n * Enqueue a job for a specific device.\n * If a job is already running for this device, behavior depends on interruptibility:\n * - 'none': new job queues silently (no preemption possible)\n * - 'safe': current job is auto-cancelled, new job runs immediately after\n * - 'confirm': onPreemptionRequest is called to ask user\n */\n async enqueue<T>(\n deviceId: string,\n job: (signal: AbortSignal) => Promise<T>,\n options: JobOptions = {}\n ): Promise<T> {\n const interruptibility = options.interruptibility ?? 'confirm';\n const active = this._active.get(deviceId);\n\n if (active) {\n switch (active.options.interruptibility) {\n case 'none':\n // Cannot interrupt, just queue behind\n break;\n case 'safe':\n // Auto-cancel current safe operation\n active.abortController.abort(new Error('Preempted by new operation'));\n break;\n case 'confirm': {\n if (this.onPreemptionRequest) {\n const decision = await this.onPreemptionRequest({\n deviceId,\n currentJob: {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n },\n newJob: {\n label: options.label,\n interruptibility,\n },\n });\n switch (decision) {\n case 'cancel-current':\n active.abortController.abort(new Error('Cancelled by user via preemption'));\n break;\n case 'reject-new':\n throw Object.assign(\n new Error(`Device busy: ${active.options.label ?? 'unknown operation'}`),\n { hardwareErrorCode: 'DEVICE_BUSY' }\n );\n case 'wait':\n break;\n }\n }\n break;\n }\n }\n }\n\n const ac = new AbortController();\n const prev = this._queues.get(deviceId) ?? Promise.resolve();\n\n const next = prev\n .catch(() => {})\n .then(async () => {\n this._active.set(deviceId, {\n options: { interruptibility, label: options.label },\n abortController: ac,\n startedAt: Date.now(),\n });\n try {\n return await job(ac.signal);\n } finally {\n this._active.delete(deviceId);\n }\n });\n\n const tail = next.catch(() => {});\n this._queues.set(deviceId, tail);\n tail.then(() => {\n if (this._queues.get(deviceId) === tail) {\n this._queues.delete(deviceId);\n }\n });\n return next;\n }\n\n /** Manually cancel the active job on a device. Returns false if job is non-interruptible. */\n cancelActive(deviceId: string): boolean {\n const active = this._active.get(deviceId);\n if (!active) return false;\n if (active.options.interruptibility === 'none') return false;\n active.abortController.abort(new Error('Manually cancelled'));\n return true;\n }\n\n /** Force cancel regardless of interruptibility. Use for device stuck recovery. */\n forceCancelActive(deviceId: string): boolean {\n const active = this._active.get(deviceId);\n if (!active) return false;\n active.abortController.abort(new Error('Force cancelled for recovery'));\n return true;\n }\n\n /** Get info about the currently active job for a device, or null if idle. */\n getActiveJob(deviceId: string): ActiveJobInfo | null {\n const active = this._active.get(deviceId);\n if (!active) return null;\n return {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n };\n }\n\n clear(): void {\n // Abort all active jobs\n for (const active of this._active.values()) {\n active.abortController.abort(new Error('Queue cleared'));\n }\n this._active.clear();\n this._queues.clear();\n }\n}\n","import type { DeviceCapabilities, DeviceInfo, VendorType } from './device';\n\n// =====================================================================\n// Connector types — transport-level abstraction for device communication\n// =====================================================================\n\n/**\n * Minimal device info returned during discovery (searchDevices).\n * At scan time, full DeviceInfo fields like firmwareVersion are not yet available.\n */\nexport interface ConnectorDevice {\n connectId: string;\n deviceId: string;\n name: string;\n model?: string;\n\n /** Device capabilities — available from scan time */\n capabilities?: DeviceCapabilities;\n}\n\nexport interface ConnectorSession {\n sessionId: string;\n deviceInfo: DeviceInfo;\n}\n\nexport type ConnectorEventType = 'device-connect' | 'device-disconnect' | 'ui-request' | 'ui-event';\n\n/**\n * Interaction event types emitted via 'ui-event'.\n * These map to user-facing prompts (confirm on device, open app, etc.).\n */\nexport enum EConnectorInteraction {\n /** Device requires user to open a specific app */\n ConfirmOpenApp = 'confirm-open-app',\n /** Device requires user to unlock */\n UnlockDevice = 'unlock-device',\n /** Device needs user to confirm on device (sign, verify, etc.) */\n ConfirmOnDevice = 'confirm-on-device',\n /** Previous interaction completed — clear UI prompt */\n InteractionComplete = 'interaction-complete',\n}\n\nexport type ConnectorUiEvent =\n | { type: EConnectorInteraction.ConfirmOpenApp; payload: { sessionId: string } }\n | { type: EConnectorInteraction.UnlockDevice; payload: { sessionId: string } }\n | { type: EConnectorInteraction.ConfirmOnDevice; payload: { sessionId: string } }\n | { type: EConnectorInteraction.InteractionComplete; payload: { sessionId: string } };\n\nexport interface ConnectorEventMap {\n 'device-connect': { device: ConnectorDevice };\n 'device-disconnect': { connectId: string };\n 'ui-request': { type: string; payload?: unknown };\n 'ui-event': ConnectorUiEvent;\n}\n\nexport interface IConnector {\n searchDevices(): Promise<ConnectorDevice[]>;\n connect(deviceId?: string): Promise<ConnectorSession>;\n disconnect(sessionId: string): Promise<void>;\n call(sessionId: string, method: string, params: unknown): Promise<unknown>;\n cancel(sessionId: string): Promise<void>;\n\n /** Send a UI response (e.g. PIN, passphrase) to the device. */\n uiResponse(response: { type: string; payload: unknown }): void;\n\n on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;\n off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;\n\n reset(): void;\n}\n\n// =====================================================================\n// Hardware bridge — generic forwarding interface for cross-boundary IConnector\n//\n// The same shape works across any process / context boundary that needs to\n// expose a multi-vendor backend behind a single-vendor IConnector facade:\n// - Electron (renderer ↔ preload/main via contextBridge)\n// - Browser Extension (popup/content ↔ background/offscreen via chrome.runtime)\n// - React Native (JS ↔ native module via NativeModules)\n// - Web Worker / iframe (postMessage)\n//\n// Each method takes a `vendor` discriminator so a single bridge implementation\n// can multiplex across vendors (ledger, trezor, ...).\n// =====================================================================\n\nexport interface IHardwareBridge {\n searchDevices(params: { vendor: VendorType }): Promise<ConnectorDevice[]>;\n connect(params: { vendor: VendorType; deviceId?: string }): Promise<ConnectorSession>;\n disconnect(params: { vendor: VendorType; sessionId: string }): Promise<void>;\n call(params: {\n vendor: VendorType;\n sessionId: string;\n method: string;\n callParams: unknown;\n }): Promise<unknown>;\n cancel(params: { vendor: VendorType; sessionId: string }): Promise<void>;\n uiResponse(params: { vendor: VendorType; response: { type: string; payload: unknown } }): void;\n reset(params: { vendor: VendorType }): void;\n\n /** Register an event handler for connector events forwarded across the bridge. */\n onEvent(\n params: { vendor: VendorType },\n handler: (event: { type: ConnectorEventType; data: unknown }) => void\n ): void;\n\n /** Unregister a previously registered event handler. */\n offEvent(\n params: { vendor: VendorType },\n handler: (event: { type: ConnectorEventType; data: unknown }) => void\n ): void;\n}\n\n/**\n * Adapt an IHardwareBridge (multi-vendor backend) into a single-vendor IConnector.\n * Every IConnector method becomes a transparent forward to bridge.<method>({ vendor, ... }).\n * Events are forwarded via bridge.onEvent / offEvent.\n *\n * Use this anywhere the actual hardware lives behind a process / context boundary\n * (Electron main, extension background, native module, worker, iframe).\n */\nexport function createBridgedConnector(\n vendor: VendorType,\n bridge: IHardwareBridge\n): IConnector {\n // Map from typed IConnector handlers to the bridge handler so we can\n // unregister them correctly via off().\n const handlerMap = new Map<\n (data: ConnectorEventMap[ConnectorEventType]) => void,\n (event: { type: ConnectorEventType; data: unknown }) => void\n >();\n\n return {\n searchDevices: () => bridge.searchDevices({ vendor }),\n connect: deviceId => bridge.connect({ vendor, deviceId }),\n disconnect: sessionId => bridge.disconnect({ vendor, sessionId }),\n call: (sessionId, method, callParams) => bridge.call({ vendor, sessionId, method, callParams }),\n cancel: sessionId => bridge.cancel({ vendor, sessionId }),\n uiResponse: response => bridge.uiResponse({ vendor, response }),\n on: (event, handler) => {\n const bridgeHandler = (e: { type: ConnectorEventType; data: unknown }) => {\n if (e.type === event) {\n handler(e.data as ConnectorEventMap[typeof event]);\n }\n };\n handlerMap.set(\n handler as (data: ConnectorEventMap[ConnectorEventType]) => void,\n bridgeHandler\n );\n bridge.onEvent({ vendor }, bridgeHandler);\n },\n off: (_event, handler) => {\n const bridgeHandler = handlerMap.get(\n handler as (data: ConnectorEventMap[ConnectorEventType]) => void\n );\n if (bridgeHandler) {\n bridge.offEvent({ vendor }, bridgeHandler);\n handlerMap.delete(handler as (data: ConnectorEventMap[ConnectorEventType]) => void);\n }\n },\n reset: () => bridge.reset({ vendor }),\n };\n}\n","/**\n * Minimal typed event emitter using Map<string, Set<listener>>.\n * Each adapter uses this for device events (connect, disconnect, pin, etc.).\n *\n * TMap is a record mapping event name strings to their payload types.\n * Example:\n * type MyEvents = { 'connect': { id: string }; 'disconnect': { id: string } };\n * const emitter = new TypedEventEmitter<MyEvents>();\n * emitter.on('connect', (data) => { data.id }); // data is { id: string }\n *\n * For backward compatibility, TMap defaults to Record<string, any> so that\n * existing code using `new TypedEventEmitter<SomeUnionType>()` still compiles.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class TypedEventEmitter<TMap extends Record<string, any> = Record<string, any>> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly _listeners = new Map<string, Set<(event: any) => void>>();\n\n on<K extends keyof TMap & string>(event: K, listener: (event: TMap[K]) => void): void;\n on(event: string, listener: (event: any) => void): void;\n on(event: string, listener: (event: any) => void): void {\n let set = this._listeners.get(event);\n if (!set) {\n set = new Set();\n this._listeners.set(event, set);\n }\n set.add(listener);\n }\n\n off<K extends keyof TMap & string>(event: K, listener: (event: TMap[K]) => void): void;\n off(event: string, listener: (event: any) => void): void;\n off(event: string, listener: (event: any) => void): void {\n const set = this._listeners.get(event);\n if (set) {\n set.delete(listener);\n if (set.size === 0) this._listeners.delete(event);\n }\n }\n\n emit<K extends keyof TMap & string>(event: K, data: TMap[K]): void;\n emit(event: string, data: unknown): void;\n emit(event: string, data: unknown): void {\n const set = this._listeners.get(event);\n if (set) {\n for (const listener of set) listener(data);\n }\n }\n\n removeAllListeners(): void {\n this._listeners.clear();\n }\n}\n","/**\n * Compare two semver strings (e.g. \"2.1.0\" vs \"2.3.1\").\n * Returns -1 if a < b, 0 if equal, 1 if a > b.\n */\nexport function compareSemver(a: string, b: string): number {\n const pa = a.split('.').map(Number);\n const pb = b.split('.').map(Number);\n for (let i = 0; i < 3; i++) {\n const va = pa[i] ?? 0;\n const vb = pb[i] ?? 0;\n if (va < vb) return -1;\n if (va > vb) return 1;\n }\n return 0;\n}\n","/** Ensure hex string has 0x prefix */\nexport function ensure0x(hex: string): string {\n return hex.startsWith('0x') ? hex : `0x${hex}`;\n}\n\n/** Strip 0x prefix from hex string */\nexport function stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Pad hex to 64 chars (32 bytes) with 0x prefix */\nexport function padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n/** Convert a hex string (with or without 0x prefix) to a Uint8Array. */\nexport function hexToBytes(hex: string): Uint8Array {\n const clean = stripHex(hex);\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/** Convert a Uint8Array to a hex string (no 0x prefix). */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n}\n","import { HardwareErrorCode } from '../types/errors';\n\n/**\n * Enrich a hardware error message with actionable recovery hints.\n * Shared across adapters (Ledger, Trezor, etc.).\n */\nexport function enrichErrorMessage(code: HardwareErrorCode, originalMessage: string): string {\n switch (code) {\n case HardwareErrorCode.PinInvalid:\n return `${originalMessage}. Please re-enter your PIN.`;\n case HardwareErrorCode.PinCancelled:\n return `${originalMessage}. PIN entry was cancelled.`;\n case HardwareErrorCode.DeviceBusy:\n return `${originalMessage}. The device is in use by another application. Close other wallet apps and try again.`;\n case HardwareErrorCode.DeviceDisconnected:\n return `${originalMessage}. Please reconnect the device and try again.`;\n case HardwareErrorCode.DeviceLocked:\n return `${originalMessage}. Please unlock your device and try again.`;\n case HardwareErrorCode.UserRejected:\n return `${originalMessage}. The request was rejected on the device.`;\n case HardwareErrorCode.WrongApp:\n return `${originalMessage}. Please open the correct app on your device.`;\n case HardwareErrorCode.AppNotOpen:\n return `${originalMessage}. The required app is not installed on the device.`;\n case HardwareErrorCode.TransportNotAvailable:\n return `${originalMessage}. Ensure the device bridge/transport is available and running.`;\n case HardwareErrorCode.FirmwareTooOld:\n return `${originalMessage}. Please update your device firmware.`;\n case HardwareErrorCode.DeviceNotInitialized:\n return `${originalMessage}. The device may need to be set up first.`;\n case HardwareErrorCode.OperationTimeout:\n return `${originalMessage}. The operation timed out. Please try again.`;\n default:\n return originalMessage;\n }\n}\n","import type { Response } from '../types/response';\n\n/**\n * Generic batch call with progress reporting.\n * If any single call fails, returns the failure immediately.\n */\nexport async function batchCall<TParam, TResult>(\n params: TParam[],\n callFn: (p: TParam) => Promise<Response<TResult>>,\n onProgress?: (progress: { index: number; total: number }) => void\n): Promise<Response<TResult[]>> {\n const results: TResult[] = [];\n for (let i = 0; i < params.length; i++) {\n const result = await callFn(params[i]);\n if (!result.success) {\n return result;\n }\n results.push(result.payload);\n onProgress?.({ index: i, total: params.length });\n }\n return { success: true, payload: results };\n}\n"],"mappings":"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","names":["HardwareErrorCode","EConnectorInteraction"]}
1
+ {"version":3,"sources":["../src/types/errors.ts","../src/types/response.ts","../src/types/fingerprint.ts","../src/events/device.ts","../src/events/ui-request.ts","../src/events/sdk.ts","../src/utils/DeviceJobQueue.ts","../src/types/connector.ts","../src/utils/TypedEventEmitter.ts","../src/utils/UiRequestRegistry.ts","../src/utils/semver.ts","../src/utils/hex.ts","../src/utils/errorMessages.ts","../src/utils/batchCall.ts"],"sourcesContent":["export enum HardwareErrorCode {\n UnknownError = 0,\n DeviceNotFound = 1,\n DeviceDisconnected = 2,\n UserRejected = 3,\n DeviceBusy = 4,\n FirmwareUpdateRequired = 5,\n AppNotOpen = 6,\n InvalidParams = 7,\n TransportError = 8,\n OperationTimeout = 9,\n MethodNotSupported = 10,\n\n // PIN / Passphrase\n PinInvalid = 5520,\n PinCancelled = 5521,\n PassphraseRejected = 5522,\n\n // Device state\n DeviceLocked = 5530,\n DeviceNotInitialized = 5531,\n DeviceInBootloader = 5532,\n FirmwareTooOld = 5533,\n\n // Ledger specific\n WrongApp = 5540,\n\n // Device identity\n DeviceMismatch = 5560,\n\n // Transport\n BridgeNotFound = 5550,\n TransportNotAvailable = 5551,\n\n // --- EVM (Ledger Ethereum App) APDU-specific errors ---\n /** 0x6a80 Invalid data — observed on blindSignTransactionFallback when the\n * user has not enabled Blind signing on the device. */\n EvmBlindSigningRequired = 7001,\n /** 0x6984 Plugin not installed */\n EvmClearSignPluginMissing = 7002,\n /** 0x6a84 Insufficient memory (typical on Nano S with large calldata) */\n EvmDataTooLarge = 7003,\n /** 0x6501 TransactionType not supported (app too old for EIP-1559 / blob / 7702) */\n EvmTxTypeNotSupported = 7004,\n /** 0x911c Command code not supported — app predates current SDK */\n AppTooOld = 7005,\n}\n","import { HardwareErrorCode } from './errors';\n\nexport interface Success<T> {\n success: true;\n payload: T;\n}\n\nexport interface Failure {\n success: false;\n payload: {\n error: string;\n code: HardwareErrorCode;\n appName?: string;\n };\n}\n\nexport type Response<T> = Success<T> | Failure;\n\nexport function success<T>(payload: T): Success<T> {\n return { success: true, payload };\n}\n\nexport function failure(code: HardwareErrorCode, error: string, appName?: string): Failure {\n return { success: false, payload: { error, code, appName } };\n}\n","/**\n * Chain fingerprint utilities for device identity verification.\n *\n * Ledger devices have ephemeral IDs that change every session.\n * To verify that the same seed/device is connected, we derive an address\n * at a fixed path (account 0, index 0) and hash it into a stable \"chain fingerprint\".\n */\n\n/**\n * Fixed derivation paths used to generate chain fingerprints.\n * Uses standard index 0 — Ledger firmware shows device confirmation for\n * non-standard paths (e.g., index=100), which would interrupt wallet creation.\n * The address is hashed into a 16-char fingerprint, not exposed directly.\n * - EVM: cointype 60 (Ledger ETH App only supports 60)\n * - BTC: cointype 1 (testnet)\n * - SOL: cointype 501, standard 3-level hardened\n */\nexport const CHAIN_FINGERPRINT_PATHS: Record<ChainForFingerprint, string> = {\n evm: \"m/44'/60'/0'/0/0\",\n // BTC: account-level path (3 levels), mainnet cointype 0.\n // Cointype 1 (testnet) is rejected by some Ledger BTC App configurations.\n btc: \"m/44'/0'/0'\",\n sol: \"m/44'/501'/0'\",\n tron: \"m/44'/195'/0'/0/0\",\n};\n\nexport type ChainForFingerprint = 'evm' | 'btc' | 'sol' | 'tron';\n\n/**\n * Hash an address string into a 16-character hex fingerprint.\n *\n * Uses a simple non-cryptographic hash (FNV-1a based) to avoid\n * pulling in a SHA-256 dependency. This is NOT used for security —\n * only for device identity matching.\n */\nexport function deriveDeviceFingerprint(address: string): string {\n // FNV-1a 64-bit constants (split into two 32-bit halves for JS)\n let h1 = 0x811c9dc5;\n let h2 = 0x01000193;\n\n for (let i = 0; i < address.length; i++) {\n const c = address.charCodeAt(i);\n h1 = Math.imul(h1 ^ c, h2);\n h2 = Math.imul(h2 ^ (c >>> 4), 0x01000193);\n }\n\n // Mix the two halves for better distribution\n h1 = Math.imul(h1 ^ (h1 >>> 16), 0x45d9f3b);\n h2 = Math.imul(h2 ^ (h2 >>> 16), 0x45d9f3b);\n\n const hex1 = (h1 >>> 0).toString(16).padStart(8, '0');\n const hex2 = (h2 >>> 0).toString(16).padStart(8, '0');\n\n return `${hex1}${hex2}`;\n}\n","export const DEVICE_EVENT = 'DEVICE_EVENT';\n\n/** Events originating from the hardware device. */\nexport const DEVICE = {\n CONNECT: 'device-connect',\n DISCONNECT: 'device-disconnect',\n CHANGED: 'device-changed',\n ACQUIRE: 'device-acquire',\n RELEASE: 'device-release',\n FEATURES: 'features',\n SUPPORT_FEATURES: 'support_features',\n} as const;\n","import type { QrResponseData } from '../types/qr';\n\nexport const UI_EVENT = 'UI_EVENT';\n\nexport const UI_REQUEST = {\n REQUEST_PIN: 'ui-request-pin',\n REQUEST_PASSPHRASE: 'ui-request-passphrase',\n REQUEST_PASSPHRASE_ON_DEVICE: 'ui-request-passphrase-on-device',\n REQUEST_BUTTON: 'ui-request-button',\n REQUEST_QR_DISPLAY: 'ui-request-qr-display',\n REQUEST_QR_SCAN: 'ui-request-qr-scan',\n REQUEST_DEVICE_PERMISSION: 'ui-request-device-permission',\n REQUEST_SELECT_DEVICE: 'ui-request-select-device',\n REQUEST_DEVICE_CONNECT: 'ui-request-device-connect',\n CLOSE_UI_WINDOW: 'ui-close',\n DEVICE_PROGRESS: 'ui-device_progress',\n FIRMWARE_PROGRESS: 'ui-firmware-progress',\n FIRMWARE_TIP: 'ui-firmware-tip',\n} as const;\n\nexport const UI_RESPONSE = {\n RECEIVE_PIN: 'receive-pin',\n RECEIVE_PASSPHRASE: 'receive-passphrase',\n RECEIVE_PASSPHRASE_ON_DEVICE: 'receive-passphrase-on-device',\n RECEIVE_QR_RESPONSE: 'receive-qr-response',\n RECEIVE_SELECT_DEVICE: 'receive-select-device',\n RECEIVE_DEVICE_CONNECT: 'receive-device-connect',\n CANCEL: 'cancel',\n} as const;\n\nexport type UiResponseEvent =\n | {\n type: typeof UI_RESPONSE.RECEIVE_PIN;\n payload: string;\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_PASSPHRASE;\n payload: {\n value: string;\n passphraseOnDevice?: boolean;\n save?: boolean;\n };\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_PASSPHRASE_ON_DEVICE;\n payload?: undefined;\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_QR_RESPONSE;\n payload: QrResponseData;\n }\n | {\n // sdkConnectId echoes one of the DeviceInfo.connectId values emitted in\n // the REQUEST_SELECT_DEVICE event's `devices` list. Scope is the current\n // search session; may be ephemeral (e.g. Ledger USB DMK UUID).\n type: typeof UI_RESPONSE.RECEIVE_SELECT_DEVICE;\n payload: { sdkConnectId: string };\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_DEVICE_CONNECT;\n payload: { confirmed: boolean };\n }\n | {\n type: typeof UI_RESPONSE.CANCEL;\n payload?: undefined;\n };\n","/** Events generated by SDK internal detection (not from hardware directly). */\nexport const SDK = {\n DEVICE_STUCK: 'device-stuck',\n DEVICE_UNRESPONSIVE: 'device-unresponsive',\n DEVICE_RECOVERED: 'device-recovered',\n DEVICE_INTERACTION: 'device-interaction',\n} as const;\n","/**\n * Per-device serial job queue with preemption support and stuck recovery.\n * Ensures that only one operation runs at a time per device, with intelligent\n * handling of conflicting operations.\n */\n\nexport type Interruptibility = 'none' | 'safe' | 'confirm';\n\nexport type PreemptionDecision = 'cancel-current' | 'wait' | 'reject-new';\n\nexport interface JobOptions {\n interruptibility?: Interruptibility;\n label?: string;\n}\n\nexport interface ActiveJobInfo {\n label?: string;\n interruptibility: Interruptibility;\n startedAt: number;\n}\n\nexport interface PreemptionEvent {\n deviceId: string;\n currentJob: ActiveJobInfo;\n newJob: { label?: string; interruptibility: Interruptibility };\n}\n\ninterface ActiveJob {\n options: Required<Pick<JobOptions, 'interruptibility'>> & Pick<JobOptions, 'label'>;\n abortController: AbortController;\n startedAt: number;\n}\n\nexport class DeviceJobQueue {\n private readonly _queues = new Map<string, Promise<unknown>>();\n private readonly _active = new Map<string, ActiveJob>();\n\n /**\n * Called when a new job conflicts with an active 'confirm'-level job.\n * UI should show a dialog and return the user's decision.\n * If not set, defaults to 'wait' (queue behind current job).\n */\n onPreemptionRequest?: (event: PreemptionEvent) => Promise<PreemptionDecision>;\n\n /**\n * Enqueue a job for a specific device.\n * If a job is already running for this device, behavior depends on interruptibility:\n * - 'none': new job queues silently (no preemption possible)\n * - 'safe': current job is auto-cancelled, new job runs immediately after\n * - 'confirm': onPreemptionRequest is called to ask user\n */\n async enqueue<T>(\n deviceId: string,\n job: (signal: AbortSignal) => Promise<T>,\n options: JobOptions = {}\n ): Promise<T> {\n const interruptibility = options.interruptibility ?? 'confirm';\n const active = this._active.get(deviceId);\n\n if (active) {\n switch (active.options.interruptibility) {\n case 'none':\n // Cannot interrupt, just queue behind\n break;\n case 'safe':\n // Auto-cancel current safe operation\n active.abortController.abort(new Error('Preempted by new operation'));\n break;\n case 'confirm': {\n if (this.onPreemptionRequest) {\n const decision = await this.onPreemptionRequest({\n deviceId,\n currentJob: {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n },\n newJob: {\n label: options.label,\n interruptibility,\n },\n });\n switch (decision) {\n case 'cancel-current':\n active.abortController.abort(new Error('Cancelled by user via preemption'));\n break;\n case 'reject-new':\n throw Object.assign(\n new Error(`Device busy: ${active.options.label ?? 'unknown operation'}`),\n { hardwareErrorCode: 'DEVICE_BUSY' }\n );\n case 'wait':\n break;\n }\n }\n break;\n }\n }\n }\n\n const ac = new AbortController();\n const prev = this._queues.get(deviceId) ?? Promise.resolve();\n\n const next = prev\n .catch(() => {})\n .then(async () => {\n this._active.set(deviceId, {\n options: { interruptibility, label: options.label },\n abortController: ac,\n startedAt: Date.now(),\n });\n try {\n return await job(ac.signal);\n } finally {\n this._active.delete(deviceId);\n }\n });\n\n const tail = next.catch(() => {});\n this._queues.set(deviceId, tail);\n tail.then(() => {\n if (this._queues.get(deviceId) === tail) {\n this._queues.delete(deviceId);\n }\n });\n return next;\n }\n\n /** Manually cancel the active job on a device. Returns false if job is non-interruptible. */\n cancelActive(deviceId: string): boolean {\n const active = this._active.get(deviceId);\n if (!active) return false;\n if (active.options.interruptibility === 'none') return false;\n active.abortController.abort(new Error('Manually cancelled'));\n return true;\n }\n\n /** Force cancel regardless of interruptibility. Use for device stuck recovery. */\n forceCancelActive(deviceId: string): boolean {\n const active = this._active.get(deviceId);\n if (!active) return false;\n active.abortController.abort(new Error('Force cancelled for recovery'));\n return true;\n }\n\n /** Get info about the currently active job for a device, or null if idle. */\n getActiveJob(deviceId: string): ActiveJobInfo | null {\n const active = this._active.get(deviceId);\n if (!active) return null;\n return {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n };\n }\n\n clear(): void {\n // Abort all active jobs\n for (const active of this._active.values()) {\n active.abortController.abort(new Error('Queue cleared'));\n }\n this._active.clear();\n this._queues.clear();\n }\n}\n","import type { DeviceCapabilities, DeviceInfo, VendorType } from './device';\nimport type { UiResponseEvent } from '../events/ui-request';\n\n// =====================================================================\n// Connector types — transport-level abstraction for device communication\n// =====================================================================\n\n/**\n * Minimal device info returned during discovery (searchDevices).\n * At scan time, full DeviceInfo fields like firmwareVersion are not yet available.\n */\nexport interface ConnectorDevice {\n connectId: string;\n deviceId: string;\n name: string;\n model?: string;\n\n /** Device capabilities — available from scan time */\n capabilities?: DeviceCapabilities;\n}\n\nexport interface ConnectorSession {\n sessionId: string;\n deviceInfo: DeviceInfo;\n}\n\nexport type ConnectorEventType = 'device-connect' | 'device-disconnect' | 'ui-request' | 'ui-event';\n\n/**\n * Interaction event types emitted via 'ui-event'.\n * These map to user-facing prompts (confirm on device, open app, etc.).\n */\nexport enum EConnectorInteraction {\n /** Device requires user to open a specific app */\n ConfirmOpenApp = 'confirm-open-app',\n /** Device requires user to unlock */\n UnlockDevice = 'unlock-device',\n /** Device needs user to confirm on device (sign, verify, etc.) */\n ConfirmOnDevice = 'confirm-on-device',\n /** Previous interaction completed — clear UI prompt */\n InteractionComplete = 'interaction-complete',\n}\n\nexport type ConnectorUiEvent =\n | { type: EConnectorInteraction.ConfirmOpenApp; payload: { sessionId: string } }\n | { type: EConnectorInteraction.UnlockDevice; payload: { sessionId: string } }\n | { type: EConnectorInteraction.ConfirmOnDevice; payload: { sessionId: string } }\n | { type: EConnectorInteraction.InteractionComplete; payload: { sessionId: string } };\n\nexport interface ConnectorEventMap {\n 'device-connect': { device: ConnectorDevice };\n 'device-disconnect': { connectId: string };\n 'ui-request': { type: string; payload?: unknown };\n 'ui-event': ConnectorUiEvent;\n}\n\nexport interface IConnector {\n searchDevices(): Promise<ConnectorDevice[]>;\n connect(deviceId?: string): Promise<ConnectorSession>;\n disconnect(sessionId: string): Promise<void>;\n call(sessionId: string, method: string, params: unknown): Promise<unknown>;\n cancel(sessionId: string): Promise<void>;\n\n /** Send a UI response (e.g. PIN, passphrase) to the device. */\n uiResponse(response: UiResponseEvent): void;\n\n on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;\n off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;\n\n reset(): void;\n}\n\n// =====================================================================\n// Hardware bridge — generic forwarding interface for cross-boundary IConnector\n//\n// The same shape works across any process / context boundary that needs to\n// expose a multi-vendor backend behind a single-vendor IConnector facade:\n// - Electron (renderer ↔ preload/main via contextBridge)\n// - Browser Extension (popup/content ↔ background/offscreen via chrome.runtime)\n// - React Native (JS ↔ native module via NativeModules)\n// - Web Worker / iframe (postMessage)\n//\n// Each method takes a `vendor` discriminator so a single bridge implementation\n// can multiplex across vendors (ledger, trezor, ...).\n// =====================================================================\n\nexport interface IHardwareBridge {\n searchDevices(params: { vendor: VendorType }): Promise<ConnectorDevice[]>;\n connect(params: { vendor: VendorType; deviceId?: string }): Promise<ConnectorSession>;\n disconnect(params: { vendor: VendorType; sessionId: string }): Promise<void>;\n call(params: {\n vendor: VendorType;\n sessionId: string;\n method: string;\n callParams: unknown;\n }): Promise<unknown>;\n cancel(params: { vendor: VendorType; sessionId: string }): Promise<void>;\n uiResponse(params: { vendor: VendorType; response: UiResponseEvent }): void;\n reset(params: { vendor: VendorType }): void;\n\n /** Register an event handler for connector events forwarded across the bridge. */\n onEvent(\n params: { vendor: VendorType },\n handler: (event: { type: ConnectorEventType; data: unknown }) => void\n ): void;\n\n /** Unregister a previously registered event handler. */\n offEvent(\n params: { vendor: VendorType },\n handler: (event: { type: ConnectorEventType; data: unknown }) => void\n ): void;\n}\n\n/**\n * Adapt an IHardwareBridge (multi-vendor backend) into a single-vendor IConnector.\n * Every IConnector method becomes a transparent forward to bridge.<method>({ vendor, ... }).\n * Events are forwarded via bridge.onEvent / offEvent.\n *\n * Use this anywhere the actual hardware lives behind a process / context boundary\n * (Electron main, extension background, native module, worker, iframe).\n */\nexport function createBridgedConnector(\n vendor: VendorType,\n bridge: IHardwareBridge\n): IConnector {\n // Map from typed IConnector handlers to the bridge handler so we can\n // unregister them correctly via off().\n const handlerMap = new Map<\n (data: ConnectorEventMap[ConnectorEventType]) => void,\n (event: { type: ConnectorEventType; data: unknown }) => void\n >();\n\n return {\n searchDevices: () => bridge.searchDevices({ vendor }),\n connect: deviceId => bridge.connect({ vendor, deviceId }),\n disconnect: sessionId => bridge.disconnect({ vendor, sessionId }),\n call: (sessionId, method, callParams) => bridge.call({ vendor, sessionId, method, callParams }),\n cancel: sessionId => bridge.cancel({ vendor, sessionId }),\n uiResponse: response => bridge.uiResponse({ vendor, response }),\n on: (event, handler) => {\n const bridgeHandler = (e: { type: ConnectorEventType; data: unknown }) => {\n if (e.type === event) {\n handler(e.data as ConnectorEventMap[typeof event]);\n }\n };\n handlerMap.set(\n handler as (data: ConnectorEventMap[ConnectorEventType]) => void,\n bridgeHandler\n );\n bridge.onEvent({ vendor }, bridgeHandler);\n },\n off: (_event, handler) => {\n const bridgeHandler = handlerMap.get(\n handler as (data: ConnectorEventMap[ConnectorEventType]) => void\n );\n if (bridgeHandler) {\n bridge.offEvent({ vendor }, bridgeHandler);\n handlerMap.delete(handler as (data: ConnectorEventMap[ConnectorEventType]) => void);\n }\n },\n reset: () => bridge.reset({ vendor }),\n };\n}\n","/**\n * Minimal typed event emitter using Map<string, Set<listener>>.\n * Each adapter uses this for device events (connect, disconnect, pin, etc.).\n *\n * TMap is a record mapping event name strings to their payload types.\n * Example:\n * type MyEvents = { 'connect': { id: string }; 'disconnect': { id: string } };\n * const emitter = new TypedEventEmitter<MyEvents>();\n * emitter.on('connect', (data) => { data.id }); // data is { id: string }\n *\n * For backward compatibility, TMap defaults to Record<string, any> so that\n * existing code using `new TypedEventEmitter<SomeUnionType>()` still compiles.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class TypedEventEmitter<TMap extends Record<string, any> = Record<string, any>> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly _listeners = new Map<string, Set<(event: any) => void>>();\n\n on<K extends keyof TMap & string>(event: K, listener: (event: TMap[K]) => void): void;\n on(event: string, listener: (event: any) => void): void;\n on(event: string, listener: (event: any) => void): void {\n let set = this._listeners.get(event);\n if (!set) {\n set = new Set();\n this._listeners.set(event, set);\n }\n set.add(listener);\n }\n\n off<K extends keyof TMap & string>(event: K, listener: (event: TMap[K]) => void): void;\n off(event: string, listener: (event: any) => void): void;\n off(event: string, listener: (event: any) => void): void {\n const set = this._listeners.get(event);\n if (set) {\n set.delete(listener);\n if (set.size === 0) this._listeners.delete(event);\n }\n }\n\n emit<K extends keyof TMap & string>(event: K, data: TMap[K]): void;\n emit(event: string, data: unknown): void;\n emit(event: string, data: unknown): void {\n const set = this._listeners.get(event);\n if (set) {\n for (const listener of set) listener(data);\n }\n }\n\n removeAllListeners(): void {\n this._listeners.clear();\n }\n}\n","import { UI_REQUEST, UI_RESPONSE } from '../events/ui-request';\n\n/** 10 min — every UI request is human-in-the-loop; bias toward \"wait long\". */\nexport const UI_REQUEST_DEFAULT_TIMEOUT_MS = 600_000;\n\nconst RESPONSE_TO_REQUEST: Record<string, string> = {\n [UI_RESPONSE.RECEIVE_PIN]: UI_REQUEST.REQUEST_PIN,\n [UI_RESPONSE.RECEIVE_PASSPHRASE]: UI_REQUEST.REQUEST_PASSPHRASE,\n [UI_RESPONSE.RECEIVE_PASSPHRASE_ON_DEVICE]: UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE,\n [UI_RESPONSE.RECEIVE_SELECT_DEVICE]: UI_REQUEST.REQUEST_SELECT_DEVICE,\n [UI_RESPONSE.RECEIVE_DEVICE_CONNECT]: UI_REQUEST.REQUEST_DEVICE_CONNECT,\n // RECEIVE_QR_RESPONSE maps to QR_DISPLAY or QR_SCAN — resolved dynamically below.\n};\n\nexport const UI_REQUEST_PREEMPTED_TAG = 'UiRequestPreempted';\nexport const UI_REQUEST_CANCELLED_TAG = 'UiRequestCancelled';\nexport const UI_REQUEST_TIMEOUT_TAG = 'UiRequestTimeout';\n\ntype PendingEntry = {\n resolve: (payload: unknown) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\n/**\n * Per-type single-slot registry for adapter-level UI requests. A new `wait`\n * of the same type preempts (rejects) the prior one. Unknown response types\n * are dropped silently so the public `uiResponse` entry never throws.\n */\nexport class UiRequestRegistry {\n private pending = new Map<string, PendingEntry>();\n\n wait<T = unknown>(\n requestType: string,\n options?: { timeoutMs?: number }\n ): Promise<T> {\n const existing = this.pending.get(requestType);\n if (existing) {\n clearTimeout(existing.timer);\n this.pending.delete(requestType);\n existing.reject(\n Object.assign(\n new Error(`UI request '${requestType}' was superseded by a new request`),\n { _tag: UI_REQUEST_PREEMPTED_TAG }\n )\n );\n }\n\n const timeoutMs = options?.timeoutMs ?? UI_REQUEST_DEFAULT_TIMEOUT_MS;\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n if (this.pending.get(requestType)?.timer === timer) {\n this.pending.delete(requestType);\n reject(\n Object.assign(\n new Error(`UI request '${requestType}' timed out after ${timeoutMs}ms`),\n { _tag: UI_REQUEST_TIMEOUT_TAG }\n )\n );\n }\n }, timeoutMs);\n\n this.pending.set(requestType, {\n resolve: resolve as (payload: unknown) => void,\n reject,\n timer,\n });\n });\n }\n\n resolve(responseType: string, payload: unknown): void {\n let requestType = RESPONSE_TO_REQUEST[responseType];\n if (responseType === UI_RESPONSE.RECEIVE_QR_RESPONSE) {\n if (this.pending.has(UI_REQUEST.REQUEST_QR_DISPLAY)) {\n requestType = UI_REQUEST.REQUEST_QR_DISPLAY;\n } else if (this.pending.has(UI_REQUEST.REQUEST_QR_SCAN)) {\n requestType = UI_REQUEST.REQUEST_QR_SCAN;\n }\n }\n if (!requestType) return;\n\n const entry = this.pending.get(requestType);\n if (!entry) return;\n\n clearTimeout(entry.timer);\n this.pending.delete(requestType);\n entry.resolve(payload);\n }\n\n cancel(requestType?: string): void {\n if (requestType) {\n const entry = this.pending.get(requestType);\n if (!entry) return;\n clearTimeout(entry.timer);\n this.pending.delete(requestType);\n entry.reject(\n Object.assign(new Error(`UI request '${requestType}' was cancelled`), {\n _tag: UI_REQUEST_CANCELLED_TAG,\n })\n );\n return;\n }\n\n for (const [type, entry] of this.pending) {\n clearTimeout(entry.timer);\n entry.reject(\n Object.assign(new Error(`UI request '${type}' was cancelled`), {\n _tag: UI_REQUEST_CANCELLED_TAG,\n })\n );\n }\n this.pending.clear();\n }\n\n reset(): void {\n this.cancel();\n }\n\n hasPending(requestType: string): boolean {\n return this.pending.has(requestType);\n }\n}\n","/**\n * Compare two semver strings (e.g. \"2.1.0\" vs \"2.3.1\").\n * Returns -1 if a < b, 0 if equal, 1 if a > b.\n */\nexport function compareSemver(a: string, b: string): number {\n const pa = a.split('.').map(Number);\n const pb = b.split('.').map(Number);\n for (let i = 0; i < 3; i++) {\n const va = pa[i] ?? 0;\n const vb = pb[i] ?? 0;\n if (va < vb) return -1;\n if (va > vb) return 1;\n }\n return 0;\n}\n","/** Ensure hex string has 0x prefix */\nexport function ensure0x(hex: string): string {\n return hex.startsWith('0x') ? hex : `0x${hex}`;\n}\n\n/** Strip 0x prefix from hex string */\nexport function stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Pad hex to 64 chars (32 bytes) with 0x prefix */\nexport function padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n/** Convert a hex string (with or without 0x prefix) to a Uint8Array. */\nexport function hexToBytes(hex: string): Uint8Array {\n const clean = stripHex(hex);\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/** Convert a Uint8Array to a hex string (no 0x prefix). */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n}\n","import { HardwareErrorCode } from '../types/errors';\n\n/**\n * Enrich a hardware error message with actionable recovery hints.\n * Shared across adapters (Ledger, Trezor, etc.).\n */\nexport function enrichErrorMessage(code: HardwareErrorCode, originalMessage: string): string {\n switch (code) {\n case HardwareErrorCode.PinInvalid:\n return `${originalMessage}. Please re-enter your PIN.`;\n case HardwareErrorCode.PinCancelled:\n return `${originalMessage}. PIN entry was cancelled.`;\n case HardwareErrorCode.DeviceBusy:\n return `${originalMessage}. The device is in use by another application. Close other wallet apps and try again.`;\n case HardwareErrorCode.DeviceDisconnected:\n return `${originalMessage}. Please reconnect the device and try again.`;\n case HardwareErrorCode.DeviceLocked:\n return `${originalMessage}. Please unlock your device and try again.`;\n case HardwareErrorCode.UserRejected:\n return `${originalMessage}. The request was rejected on the device.`;\n case HardwareErrorCode.WrongApp:\n return `${originalMessage}. Please open the correct app on your device.`;\n case HardwareErrorCode.AppNotOpen:\n return `${originalMessage}. The required app is not installed on the device.`;\n case HardwareErrorCode.TransportNotAvailable:\n return `${originalMessage}. Ensure the device bridge/transport is available and running.`;\n case HardwareErrorCode.FirmwareTooOld:\n return `${originalMessage}. Please update your device firmware.`;\n case HardwareErrorCode.DeviceNotInitialized:\n return `${originalMessage}. The device may need to be set up first.`;\n case HardwareErrorCode.OperationTimeout:\n return `${originalMessage}. The operation timed out. Please try again.`;\n case HardwareErrorCode.EvmBlindSigningRequired:\n return 'Please enable Blind signing on your Ledger: open the Ethereum app → Settings → Blind signing → Enabled, then try again.';\n case HardwareErrorCode.EvmClearSignPluginMissing:\n return 'Required Ledger plugin is not installed. Please install the matching plugin on Ledger Live, then try again.';\n case HardwareErrorCode.EvmDataTooLarge:\n return 'Transaction data is too large for your Ledger device. Try a simpler transaction or use a Ledger with more memory.';\n case HardwareErrorCode.EvmTxTypeNotSupported:\n return 'Transaction type is not supported by your Ledger Ethereum app. Please update the app to the latest version.';\n case HardwareErrorCode.AppTooOld:\n return 'Your Ledger app is out of date. Please update it via Ledger Live.';\n default:\n return originalMessage;\n }\n}\n","import type { Response } from '../types/response';\n\n/**\n * Generic batch call with progress reporting.\n * If any single call fails, returns the failure immediately.\n */\nexport async function batchCall<TParam, TResult>(\n params: TParam[],\n callFn: (p: TParam) => Promise<Response<TResult>>,\n onProgress?: (progress: { index: number; total: number }) => void\n): Promise<Response<TResult[]>> {\n const results: TResult[] = [];\n for (let i = 0; i < params.length; i++) {\n const result = await callFn(params[i]);\n if (!result.success) {\n return result;\n }\n results.push(result.payload);\n onProgress?.({ index: i, total: params.length });\n }\n return { success: true, payload: results };\n}\n"],"mappings":"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","names":["HardwareErrorCode","EConnectorInteraction"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hwk-adapter-core",
3
- "version": "1.1.26-alpha.100",
3
+ "version": "1.1.26-alpha.102",
4
4
  "description": "Shared types and utilities for OneKey hardware wallet kit",
5
5
  "author": "OneKey",
6
6
  "license": "MIT",
@@ -47,5 +47,5 @@
47
47
  "tsup": "^8.0.0",
48
48
  "typescript": "^5.4.0"
49
49
  },
50
- "gitHead": "02e9376cb38df57b5743b674326c742fa74d1e8b"
50
+ "gitHead": "febc746b8084aeed27880f14fa6ed2467e050231"
51
51
  }