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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,50 +1,78 @@
1
+ /**
2
+ * HWK HardwareErrorCode — independent namespace from the legacy
3
+ * `@onekeyfe/shared` HardwareErrorCode (which occupies 0-902).
4
+ *
5
+ * All HWK codes are 5-digit (>= 10000) so the two tables never collide
6
+ * even if either side grows. Each sub-category gets a 100-slot block.
7
+ *
8
+ * 10000-10099 Generic / cross-cutting primitives
9
+ * 10100-10199 Device state
10
+ * 10200-10299 Firmware
11
+ * 10300-10399 Transport + OS-level permission
12
+ * 10400-10499 PIN / Passphrase
13
+ * 10500-10599 App lifecycle (wrong app, not open, too old)
14
+ * 10600-10999 RESERVED — future adapter-level categories
15
+ *
16
+ * 11000-11099 EVM APDU (reactive mapping)
17
+ * 11100-11199 Solana APDU
18
+ * 11200-11299 Tron APDU
19
+ * 11300-11399 BTC APDU
20
+ * 11400-11999 RESERVED — future chain APDU blocks (100 per chain)
21
+ *
22
+ * 12000-99999 RESERVED — future major categories
23
+ */
1
24
  declare enum HardwareErrorCode {
2
- UnknownError = 0,
3
- DeviceNotFound = 1,
4
- DeviceDisconnected = 2,
5
- UserRejected = 3,
6
- DeviceBusy = 4,
7
- FirmwareUpdateRequired = 5,
8
- AppNotOpen = 6,
9
- InvalidParams = 7,
10
- TransportError = 8,
11
- OperationTimeout = 9,
12
- MethodNotSupported = 10,
13
- PinInvalid = 5520,
14
- PinCancelled = 5521,
15
- PassphraseRejected = 5522,
16
- DeviceLocked = 5530,
17
- DeviceNotInitialized = 5531,
18
- DeviceInBootloader = 5532,
19
- FirmwareTooOld = 5533,
20
- WrongApp = 5540,
21
- DeviceMismatch = 5560,
22
- BridgeNotFound = 5550,
23
- TransportNotAvailable = 5551,
24
- DevicePermissionDenied = 5570,
25
+ UnknownError = 10000,
26
+ UserRejected = 10001,
27
+ InvalidParams = 10002,
28
+ OperationTimeout = 10003,
29
+ MethodNotSupported = 10004,
30
+ DeviceNotFound = 10100,
31
+ DeviceDisconnected = 10101,
32
+ DeviceBusy = 10102,
33
+ DeviceLocked = 10103,
34
+ DeviceNotInitialized = 10104,
35
+ DeviceInBootloader = 10105,
36
+ DeviceMismatch = 10106,
37
+ FirmwareTooOld = 10200,
38
+ FirmwareUpdateRequired = 10201,
39
+ TransportError = 10300,
40
+ BridgeNotFound = 10301,
41
+ TransportNotAvailable = 10302,
42
+ /**
43
+ * OS-level permission (Bluetooth / USB / etc.) — denied, blocked,
44
+ * unavailable, or dismissed. Consumers surface a single "please grant
45
+ * permission" toast and let the user retry manually.
46
+ */
47
+ DevicePermissionDenied = 10303,
48
+ PinInvalid = 10400,
49
+ PinCancelled = 10401,
50
+ PassphraseRejected = 10402,
51
+ AppNotOpen = 10500,
52
+ WrongApp = 10501,
53
+ /** 0x911c Command code not supported — app predates current SDK. */
54
+ AppTooOld = 10502,
25
55
  /** 0x6a80 Invalid data — observed on blindSignTransactionFallback when the
26
56
  * user has not enabled Blind signing on the device. */
27
- EvmBlindSigningRequired = 7001,
57
+ EvmBlindSigningRequired = 11000,
28
58
  /** 0x6984 Plugin not installed */
29
- EvmClearSignPluginMissing = 7002,
59
+ EvmClearSignPluginMissing = 11001,
30
60
  /** 0x6a84 Insufficient memory (typical on Nano S with large calldata) */
31
- EvmDataTooLarge = 7003,
61
+ EvmDataTooLarge = 11002,
32
62
  /** 0x6501 TransactionType not supported (app too old for EIP-1559 / blob / 7702) */
33
- EvmTxTypeNotSupported = 7004,
34
- /** 0x911c Command code not supported — app predates current SDK */
35
- AppTooOld = 7005,
63
+ EvmTxTypeNotSupported = 11003,
36
64
  /** 0x6808 Blind signing disabled for this instruction. */
37
- SolanaBlindSigningRequired = 7101,
65
+ SolanaBlindSigningRequired = 11100,
38
66
  /** 0x6a8d Custom Contracts setting disabled (blocks TRC-20 etc.). */
39
- TronCustomContractRequired = 7201,
67
+ TronCustomContractRequired = 11200,
40
68
  /** 0x6a8b Transactions Data setting disabled. */
41
- TronDataSigningRequired = 7202,
69
+ TronDataSigningRequired = 11201,
42
70
  /** 0x6a8c Sign by Hash setting disabled (hash-signing fallback). */
43
- TronSignByHashRequired = 7203,
71
+ TronSignByHashRequired = 11202,
44
72
  /** 0xb008 Wallet policy HMAC mismatch or not registered. */
45
- BtcWalletPolicyHmacMismatch = 7301,
73
+ BtcWalletPolicyHmacMismatch = 11300,
46
74
  /** 0xb007 Aborted due to unexpected state (malformed PSBT / missing UTXO). */
47
- BtcUnexpectedState = 7302
75
+ BtcUnexpectedState = 11301
48
76
  }
49
77
 
50
78
  interface Success<T> {
package/dist/index.d.ts CHANGED
@@ -1,50 +1,78 @@
1
+ /**
2
+ * HWK HardwareErrorCode — independent namespace from the legacy
3
+ * `@onekeyfe/shared` HardwareErrorCode (which occupies 0-902).
4
+ *
5
+ * All HWK codes are 5-digit (>= 10000) so the two tables never collide
6
+ * even if either side grows. Each sub-category gets a 100-slot block.
7
+ *
8
+ * 10000-10099 Generic / cross-cutting primitives
9
+ * 10100-10199 Device state
10
+ * 10200-10299 Firmware
11
+ * 10300-10399 Transport + OS-level permission
12
+ * 10400-10499 PIN / Passphrase
13
+ * 10500-10599 App lifecycle (wrong app, not open, too old)
14
+ * 10600-10999 RESERVED — future adapter-level categories
15
+ *
16
+ * 11000-11099 EVM APDU (reactive mapping)
17
+ * 11100-11199 Solana APDU
18
+ * 11200-11299 Tron APDU
19
+ * 11300-11399 BTC APDU
20
+ * 11400-11999 RESERVED — future chain APDU blocks (100 per chain)
21
+ *
22
+ * 12000-99999 RESERVED — future major categories
23
+ */
1
24
  declare enum HardwareErrorCode {
2
- UnknownError = 0,
3
- DeviceNotFound = 1,
4
- DeviceDisconnected = 2,
5
- UserRejected = 3,
6
- DeviceBusy = 4,
7
- FirmwareUpdateRequired = 5,
8
- AppNotOpen = 6,
9
- InvalidParams = 7,
10
- TransportError = 8,
11
- OperationTimeout = 9,
12
- MethodNotSupported = 10,
13
- PinInvalid = 5520,
14
- PinCancelled = 5521,
15
- PassphraseRejected = 5522,
16
- DeviceLocked = 5530,
17
- DeviceNotInitialized = 5531,
18
- DeviceInBootloader = 5532,
19
- FirmwareTooOld = 5533,
20
- WrongApp = 5540,
21
- DeviceMismatch = 5560,
22
- BridgeNotFound = 5550,
23
- TransportNotAvailable = 5551,
24
- DevicePermissionDenied = 5570,
25
+ UnknownError = 10000,
26
+ UserRejected = 10001,
27
+ InvalidParams = 10002,
28
+ OperationTimeout = 10003,
29
+ MethodNotSupported = 10004,
30
+ DeviceNotFound = 10100,
31
+ DeviceDisconnected = 10101,
32
+ DeviceBusy = 10102,
33
+ DeviceLocked = 10103,
34
+ DeviceNotInitialized = 10104,
35
+ DeviceInBootloader = 10105,
36
+ DeviceMismatch = 10106,
37
+ FirmwareTooOld = 10200,
38
+ FirmwareUpdateRequired = 10201,
39
+ TransportError = 10300,
40
+ BridgeNotFound = 10301,
41
+ TransportNotAvailable = 10302,
42
+ /**
43
+ * OS-level permission (Bluetooth / USB / etc.) — denied, blocked,
44
+ * unavailable, or dismissed. Consumers surface a single "please grant
45
+ * permission" toast and let the user retry manually.
46
+ */
47
+ DevicePermissionDenied = 10303,
48
+ PinInvalid = 10400,
49
+ PinCancelled = 10401,
50
+ PassphraseRejected = 10402,
51
+ AppNotOpen = 10500,
52
+ WrongApp = 10501,
53
+ /** 0x911c Command code not supported — app predates current SDK. */
54
+ AppTooOld = 10502,
25
55
  /** 0x6a80 Invalid data — observed on blindSignTransactionFallback when the
26
56
  * user has not enabled Blind signing on the device. */
27
- EvmBlindSigningRequired = 7001,
57
+ EvmBlindSigningRequired = 11000,
28
58
  /** 0x6984 Plugin not installed */
29
- EvmClearSignPluginMissing = 7002,
59
+ EvmClearSignPluginMissing = 11001,
30
60
  /** 0x6a84 Insufficient memory (typical on Nano S with large calldata) */
31
- EvmDataTooLarge = 7003,
61
+ EvmDataTooLarge = 11002,
32
62
  /** 0x6501 TransactionType not supported (app too old for EIP-1559 / blob / 7702) */
33
- EvmTxTypeNotSupported = 7004,
34
- /** 0x911c Command code not supported — app predates current SDK */
35
- AppTooOld = 7005,
63
+ EvmTxTypeNotSupported = 11003,
36
64
  /** 0x6808 Blind signing disabled for this instruction. */
37
- SolanaBlindSigningRequired = 7101,
65
+ SolanaBlindSigningRequired = 11100,
38
66
  /** 0x6a8d Custom Contracts setting disabled (blocks TRC-20 etc.). */
39
- TronCustomContractRequired = 7201,
67
+ TronCustomContractRequired = 11200,
40
68
  /** 0x6a8b Transactions Data setting disabled. */
41
- TronDataSigningRequired = 7202,
69
+ TronDataSigningRequired = 11201,
42
70
  /** 0x6a8c Sign by Hash setting disabled (hash-signing fallback). */
43
- TronSignByHashRequired = 7203,
71
+ TronSignByHashRequired = 11202,
44
72
  /** 0xb008 Wallet policy HMAC mismatch or not registered. */
45
- BtcWalletPolicyHmacMismatch = 7301,
73
+ BtcWalletPolicyHmacMismatch = 11300,
46
74
  /** 0xb007 Aborted due to unexpected state (malformed PSBT / missing UTXO). */
47
- BtcUnexpectedState = 7302
75
+ BtcUnexpectedState = 11301
48
76
  }
49
77
 
50
78
  interface Success<T> {
package/dist/index.js CHANGED
@@ -53,40 +53,40 @@ module.exports = __toCommonJS(index_exports);
53
53
 
54
54
  // src/types/errors.ts
55
55
  var HardwareErrorCode = /* @__PURE__ */ ((HardwareErrorCode2) => {
56
- HardwareErrorCode2[HardwareErrorCode2["UnknownError"] = 0] = "UnknownError";
57
- HardwareErrorCode2[HardwareErrorCode2["DeviceNotFound"] = 1] = "DeviceNotFound";
58
- HardwareErrorCode2[HardwareErrorCode2["DeviceDisconnected"] = 2] = "DeviceDisconnected";
59
- HardwareErrorCode2[HardwareErrorCode2["UserRejected"] = 3] = "UserRejected";
60
- HardwareErrorCode2[HardwareErrorCode2["DeviceBusy"] = 4] = "DeviceBusy";
61
- HardwareErrorCode2[HardwareErrorCode2["FirmwareUpdateRequired"] = 5] = "FirmwareUpdateRequired";
62
- HardwareErrorCode2[HardwareErrorCode2["AppNotOpen"] = 6] = "AppNotOpen";
63
- HardwareErrorCode2[HardwareErrorCode2["InvalidParams"] = 7] = "InvalidParams";
64
- HardwareErrorCode2[HardwareErrorCode2["TransportError"] = 8] = "TransportError";
65
- HardwareErrorCode2[HardwareErrorCode2["OperationTimeout"] = 9] = "OperationTimeout";
66
- HardwareErrorCode2[HardwareErrorCode2["MethodNotSupported"] = 10] = "MethodNotSupported";
67
- HardwareErrorCode2[HardwareErrorCode2["PinInvalid"] = 5520] = "PinInvalid";
68
- HardwareErrorCode2[HardwareErrorCode2["PinCancelled"] = 5521] = "PinCancelled";
69
- HardwareErrorCode2[HardwareErrorCode2["PassphraseRejected"] = 5522] = "PassphraseRejected";
70
- HardwareErrorCode2[HardwareErrorCode2["DeviceLocked"] = 5530] = "DeviceLocked";
71
- HardwareErrorCode2[HardwareErrorCode2["DeviceNotInitialized"] = 5531] = "DeviceNotInitialized";
72
- HardwareErrorCode2[HardwareErrorCode2["DeviceInBootloader"] = 5532] = "DeviceInBootloader";
73
- HardwareErrorCode2[HardwareErrorCode2["FirmwareTooOld"] = 5533] = "FirmwareTooOld";
74
- HardwareErrorCode2[HardwareErrorCode2["WrongApp"] = 5540] = "WrongApp";
75
- HardwareErrorCode2[HardwareErrorCode2["DeviceMismatch"] = 5560] = "DeviceMismatch";
76
- HardwareErrorCode2[HardwareErrorCode2["BridgeNotFound"] = 5550] = "BridgeNotFound";
77
- HardwareErrorCode2[HardwareErrorCode2["TransportNotAvailable"] = 5551] = "TransportNotAvailable";
78
- HardwareErrorCode2[HardwareErrorCode2["DevicePermissionDenied"] = 5570] = "DevicePermissionDenied";
79
- HardwareErrorCode2[HardwareErrorCode2["EvmBlindSigningRequired"] = 7001] = "EvmBlindSigningRequired";
80
- HardwareErrorCode2[HardwareErrorCode2["EvmClearSignPluginMissing"] = 7002] = "EvmClearSignPluginMissing";
81
- HardwareErrorCode2[HardwareErrorCode2["EvmDataTooLarge"] = 7003] = "EvmDataTooLarge";
82
- HardwareErrorCode2[HardwareErrorCode2["EvmTxTypeNotSupported"] = 7004] = "EvmTxTypeNotSupported";
83
- HardwareErrorCode2[HardwareErrorCode2["AppTooOld"] = 7005] = "AppTooOld";
84
- HardwareErrorCode2[HardwareErrorCode2["SolanaBlindSigningRequired"] = 7101] = "SolanaBlindSigningRequired";
85
- HardwareErrorCode2[HardwareErrorCode2["TronCustomContractRequired"] = 7201] = "TronCustomContractRequired";
86
- HardwareErrorCode2[HardwareErrorCode2["TronDataSigningRequired"] = 7202] = "TronDataSigningRequired";
87
- HardwareErrorCode2[HardwareErrorCode2["TronSignByHashRequired"] = 7203] = "TronSignByHashRequired";
88
- HardwareErrorCode2[HardwareErrorCode2["BtcWalletPolicyHmacMismatch"] = 7301] = "BtcWalletPolicyHmacMismatch";
89
- HardwareErrorCode2[HardwareErrorCode2["BtcUnexpectedState"] = 7302] = "BtcUnexpectedState";
56
+ HardwareErrorCode2[HardwareErrorCode2["UnknownError"] = 1e4] = "UnknownError";
57
+ HardwareErrorCode2[HardwareErrorCode2["UserRejected"] = 10001] = "UserRejected";
58
+ HardwareErrorCode2[HardwareErrorCode2["InvalidParams"] = 10002] = "InvalidParams";
59
+ HardwareErrorCode2[HardwareErrorCode2["OperationTimeout"] = 10003] = "OperationTimeout";
60
+ HardwareErrorCode2[HardwareErrorCode2["MethodNotSupported"] = 10004] = "MethodNotSupported";
61
+ HardwareErrorCode2[HardwareErrorCode2["DeviceNotFound"] = 10100] = "DeviceNotFound";
62
+ HardwareErrorCode2[HardwareErrorCode2["DeviceDisconnected"] = 10101] = "DeviceDisconnected";
63
+ HardwareErrorCode2[HardwareErrorCode2["DeviceBusy"] = 10102] = "DeviceBusy";
64
+ HardwareErrorCode2[HardwareErrorCode2["DeviceLocked"] = 10103] = "DeviceLocked";
65
+ HardwareErrorCode2[HardwareErrorCode2["DeviceNotInitialized"] = 10104] = "DeviceNotInitialized";
66
+ HardwareErrorCode2[HardwareErrorCode2["DeviceInBootloader"] = 10105] = "DeviceInBootloader";
67
+ HardwareErrorCode2[HardwareErrorCode2["DeviceMismatch"] = 10106] = "DeviceMismatch";
68
+ HardwareErrorCode2[HardwareErrorCode2["FirmwareTooOld"] = 10200] = "FirmwareTooOld";
69
+ HardwareErrorCode2[HardwareErrorCode2["FirmwareUpdateRequired"] = 10201] = "FirmwareUpdateRequired";
70
+ HardwareErrorCode2[HardwareErrorCode2["TransportError"] = 10300] = "TransportError";
71
+ HardwareErrorCode2[HardwareErrorCode2["BridgeNotFound"] = 10301] = "BridgeNotFound";
72
+ HardwareErrorCode2[HardwareErrorCode2["TransportNotAvailable"] = 10302] = "TransportNotAvailable";
73
+ HardwareErrorCode2[HardwareErrorCode2["DevicePermissionDenied"] = 10303] = "DevicePermissionDenied";
74
+ HardwareErrorCode2[HardwareErrorCode2["PinInvalid"] = 10400] = "PinInvalid";
75
+ HardwareErrorCode2[HardwareErrorCode2["PinCancelled"] = 10401] = "PinCancelled";
76
+ HardwareErrorCode2[HardwareErrorCode2["PassphraseRejected"] = 10402] = "PassphraseRejected";
77
+ HardwareErrorCode2[HardwareErrorCode2["AppNotOpen"] = 10500] = "AppNotOpen";
78
+ HardwareErrorCode2[HardwareErrorCode2["WrongApp"] = 10501] = "WrongApp";
79
+ HardwareErrorCode2[HardwareErrorCode2["AppTooOld"] = 10502] = "AppTooOld";
80
+ HardwareErrorCode2[HardwareErrorCode2["EvmBlindSigningRequired"] = 11e3] = "EvmBlindSigningRequired";
81
+ HardwareErrorCode2[HardwareErrorCode2["EvmClearSignPluginMissing"] = 11001] = "EvmClearSignPluginMissing";
82
+ HardwareErrorCode2[HardwareErrorCode2["EvmDataTooLarge"] = 11002] = "EvmDataTooLarge";
83
+ HardwareErrorCode2[HardwareErrorCode2["EvmTxTypeNotSupported"] = 11003] = "EvmTxTypeNotSupported";
84
+ HardwareErrorCode2[HardwareErrorCode2["SolanaBlindSigningRequired"] = 11100] = "SolanaBlindSigningRequired";
85
+ HardwareErrorCode2[HardwareErrorCode2["TronCustomContractRequired"] = 11200] = "TronCustomContractRequired";
86
+ HardwareErrorCode2[HardwareErrorCode2["TronDataSigningRequired"] = 11201] = "TronDataSigningRequired";
87
+ HardwareErrorCode2[HardwareErrorCode2["TronSignByHashRequired"] = 11202] = "TronSignByHashRequired";
88
+ HardwareErrorCode2[HardwareErrorCode2["BtcWalletPolicyHmacMismatch"] = 11300] = "BtcWalletPolicyHmacMismatch";
89
+ HardwareErrorCode2[HardwareErrorCode2["BtcUnexpectedState"] = 11301] = "BtcUnexpectedState";
90
90
  return HardwareErrorCode2;
91
91
  })(HardwareErrorCode || {});
92
92
 
@@ -508,51 +508,51 @@ function bytesToHex2(bytes) {
508
508
  // src/utils/errorMessages.ts
509
509
  function enrichErrorMessage(code, originalMessage) {
510
510
  switch (code) {
511
- case 5520 /* PinInvalid */:
511
+ case 10400 /* PinInvalid */:
512
512
  return `${originalMessage}. Please re-enter your PIN.`;
513
- case 5521 /* PinCancelled */:
513
+ case 10401 /* PinCancelled */:
514
514
  return `${originalMessage}. PIN entry was cancelled.`;
515
- case 4 /* DeviceBusy */:
515
+ case 10102 /* DeviceBusy */:
516
516
  return `${originalMessage}. The device is in use by another application. Close other wallet apps and try again.`;
517
- case 2 /* DeviceDisconnected */:
517
+ case 10101 /* DeviceDisconnected */:
518
518
  return `${originalMessage}. Please reconnect the device and try again.`;
519
- case 5530 /* DeviceLocked */:
519
+ case 10103 /* DeviceLocked */:
520
520
  return `${originalMessage}. Please unlock your device and try again.`;
521
- case 3 /* UserRejected */:
521
+ case 10001 /* UserRejected */:
522
522
  return `${originalMessage}. The request was rejected on the device.`;
523
- case 5540 /* WrongApp */:
523
+ case 10501 /* WrongApp */:
524
524
  return `${originalMessage}. Please open the correct app on your device.`;
525
- case 6 /* AppNotOpen */:
525
+ case 10500 /* AppNotOpen */:
526
526
  return `${originalMessage}. The required app is not installed on the device.`;
527
- case 5551 /* TransportNotAvailable */:
527
+ case 10302 /* TransportNotAvailable */:
528
528
  return `${originalMessage}. Ensure the device bridge/transport is available and running.`;
529
- case 5533 /* FirmwareTooOld */:
529
+ case 10200 /* FirmwareTooOld */:
530
530
  return `${originalMessage}. Please update your device firmware.`;
531
- case 5531 /* DeviceNotInitialized */:
531
+ case 10104 /* DeviceNotInitialized */:
532
532
  return `${originalMessage}. The device may need to be set up first.`;
533
- case 9 /* OperationTimeout */:
533
+ case 10003 /* OperationTimeout */:
534
534
  return `${originalMessage}. The operation timed out. Please try again.`;
535
- case 7001 /* EvmBlindSigningRequired */:
535
+ case 11e3 /* EvmBlindSigningRequired */:
536
536
  return "Ledger: Blind signing not enabled in Ethereum app.";
537
- case 7002 /* EvmClearSignPluginMissing */:
537
+ case 11001 /* EvmClearSignPluginMissing */:
538
538
  return "Ledger: Required plugin not installed (install via Ledger Live).";
539
- case 7003 /* EvmDataTooLarge */:
539
+ case 11002 /* EvmDataTooLarge */:
540
540
  return "Ledger: Transaction data too large for device memory.";
541
- case 7004 /* EvmTxTypeNotSupported */:
541
+ case 11003 /* EvmTxTypeNotSupported */:
542
542
  return "Ledger: Transaction type not supported by current Ethereum app.";
543
- case 7005 /* AppTooOld */:
543
+ case 10502 /* AppTooOld */:
544
544
  return "Ledger: App out of date (update via Ledger Live).";
545
- case 7101 /* SolanaBlindSigningRequired */:
545
+ case 11100 /* SolanaBlindSigningRequired */:
546
546
  return "Blind signing disabled in the Solana app.";
547
- case 7201 /* TronCustomContractRequired */:
547
+ case 11200 /* TronCustomContractRequired */:
548
548
  return "Custom Contracts setting disabled in the Tron app.";
549
- case 7202 /* TronDataSigningRequired */:
549
+ case 11201 /* TronDataSigningRequired */:
550
550
  return "Transactions Data setting disabled in the Tron app.";
551
- case 7203 /* TronSignByHashRequired */:
551
+ case 11202 /* TronSignByHashRequired */:
552
552
  return "Sign by Hash setting disabled in the Tron app.";
553
- case 7301 /* BtcWalletPolicyHmacMismatch */:
553
+ case 11300 /* BtcWalletPolicyHmacMismatch */:
554
554
  return "Wallet policy not registered or HMAC mismatch.";
555
- case 7302 /* BtcUnexpectedState */:
555
+ case 11301 /* BtcUnexpectedState */:
556
556
  return "Signing aborted due to unexpected device state.";
557
557
  default:
558
558
  return originalMessage;
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/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 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 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 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 DeviceJobQueueDeps,\n} from './utils/DeviceJobQueue';\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 // OS-level permission (Bluetooth / USB / etc.) — denied, blocked, unavailable,\n // or dismissed. Consumers surface a single \"please grant permission\" toast\n // and let the user retry manually.\n DevicePermissionDenied = 5570,\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 // --- Solana ---\n /** 0x6808 Blind signing disabled for this instruction. */\n SolanaBlindSigningRequired = 7101,\n\n // --- Tron ---\n /** 0x6a8d Custom Contracts setting disabled (blocks TRC-20 etc.). */\n TronCustomContractRequired = 7201,\n /** 0x6a8b Transactions Data setting disabled. */\n TronDataSigningRequired = 7202,\n /** 0x6a8c Sign by Hash setting disabled (hash-signing fallback). */\n TronSignByHashRequired = 7203,\n\n // --- BTC ---\n /** 0xb008 Wallet policy HMAC mismatch or not registered. */\n BtcWalletPolicyHmacMismatch = 7301,\n /** 0xb007 Aborted due to unexpected state (malformed PSBT / missing UTXO). */\n BtcUnexpectedState = 7302,\n}\n","import type { 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 */\nimport { sha256 } from '@noble/hashes/sha256';\nimport { bytesToHex, utf8ToBytes } from '@noble/hashes/utils';\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 * 16-char SHA-256 fingerprint for device-identity verification.\n * Callers must canonicalize input (e.g. EVM address → lowercase) —\n * encoding variations otherwise cause false DeviceMismatch.\n */\nexport function deriveDeviceFingerprint(value: string): string {\n return bytesToHex(sha256(utf8ToBytes(value))).slice(0, 16);\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} as const;\n","import type { QrResponseData } from '../types/qr';\nimport type { PreemptionDecision } from '../utils/DeviceJobQueue';\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 REQUEST_PREEMPTION: 'ui-request-preemption',\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 RECEIVE_DEVICE_PERMISSION: 'receive-device-permission',\n RECEIVE_PREEMPTION: 'receive-preemption',\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.RECEIVE_DEVICE_PERMISSION;\n payload: { granted: boolean };\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_PREEMPTION;\n payload: { decision: PreemptionDecision };\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 * The 'confirm' level uses the standard UI request/response flow:\n * emits REQUEST_PREEMPTION → waits for RECEIVE_PREEMPTION via UiRequestRegistry.\n */\n\nimport { UI_REQUEST } from '../events/ui-request';\n\nimport type { UiRequestRegistry } from './UiRequestRegistry';\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 interface DeviceJobQueueDeps {\n /** Emit a UI request event to the frontend. */\n emit: (event: string, data: unknown) => void;\n /** Registry for waiting on UI responses. */\n uiRegistry: UiRequestRegistry;\n}\n\nexport class DeviceJobQueue {\n private readonly _queues = new Map<string, Promise<unknown>>();\n\n private readonly _active = new Map<string, ActiveJob>();\n\n private readonly _deps: DeviceJobQueueDeps | null;\n\n /** Incremented on clear() so stale queued jobs can detect invalidation. */\n private _generation = 0;\n\n constructor(deps?: DeviceJobQueueDeps) {\n this._deps = deps ?? null;\n }\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': emits REQUEST_PREEMPTION and waits for UI response\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 a preemption dialog is already pending, reject immediately.\n // The user is already deciding for a previous request — don't\n // overwrite the UiRequestRegistry slot (single-slot per type).\n if (this._deps?.uiRegistry.hasPending(UI_REQUEST.REQUEST_PREEMPTION)) {\n throw Object.assign(\n new Error(`Device busy: a preemption decision is already pending`),\n { hardwareErrorCode: 'DEVICE_BUSY' }\n );\n }\n const decision = await this._requestPreemptionDecision(deviceId, active, {\n label: options.label,\n interruptibility,\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 default:\n // Unknown decision value from UI — fall back to safest option: wait.\n break;\n }\n break;\n }\n }\n }\n\n const ac = new AbortController();\n const prev = this._queues.get(deviceId) ?? Promise.resolve();\n const gen = this._generation;\n\n const next = prev\n .catch(() => {})\n .then(async () => {\n if (this._generation !== gen) {\n throw new Error('Job cancelled: queue was cleared');\n }\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 this._generation++;\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 /**\n * Request preemption decision via UI request/response flow.\n * Falls back to 'wait' if deps are not provided.\n */\n private async _requestPreemptionDecision(\n deviceId: string,\n active: ActiveJob,\n newJob: { label?: string; interruptibility: Interruptibility }\n ): Promise<PreemptionDecision> {\n if (!this._deps) return 'wait';\n\n const { emit, uiRegistry } = this._deps;\n\n emit(UI_REQUEST.REQUEST_PREEMPTION, {\n type: UI_REQUEST.REQUEST_PREEMPTION,\n payload: {\n deviceId,\n currentJob: {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n },\n newJob,\n },\n });\n\n const response = await uiRegistry.wait<{ decision: PreemptionDecision }>(\n UI_REQUEST.REQUEST_PREEMPTION\n );\n\n return response?.decision ?? 'wait';\n }\n}\n","import type { ConnectionType, 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 /** Physical connection type this connector uses. Fixed at construction. */\n readonly connectionType: ConnectionType;\n\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 connectionType: ConnectionType,\n bridge: IHardwareBridge\n): IConnector {\n // Keyed by (event, handler). A flat handler-only map would collide when the\n // same function is registered for multiple events — second .on() would\n // overwrite the first bridge handler reference, leaking it permanently.\n type UserHandler = (data: ConnectorEventMap[ConnectorEventType]) => void;\n type BridgeHandler = (event: { type: ConnectorEventType; data: unknown }) => void;\n const handlerMap = new Map<ConnectorEventType, Map<UserHandler, BridgeHandler>>();\n\n return {\n connectionType,\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: BridgeHandler = e => {\n if (e.type === event) {\n handler(e.data as ConnectorEventMap[typeof event]);\n }\n };\n let inner = handlerMap.get(event);\n if (!inner) {\n inner = new Map();\n handlerMap.set(event, inner);\n }\n inner.set(handler as UserHandler, bridgeHandler);\n bridge.onEvent({ vendor }, bridgeHandler);\n },\n off: (event, handler) => {\n const inner = handlerMap.get(event);\n const bridgeHandler = inner?.get(handler as UserHandler);\n if (!bridgeHandler || !inner) return;\n bridge.offEvent({ vendor }, bridgeHandler);\n inner.delete(handler as UserHandler);\n if (inner.size === 0) handlerMap.delete(event);\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\n on(event: string, listener: (event: any) => void): void;\n\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\n off(event: string, listener: (event: any) => void): void;\n\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\n emit(event: string, data: unknown): void;\n\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 [UI_RESPONSE.RECEIVE_DEVICE_PERMISSION]: UI_REQUEST.REQUEST_DEVICE_PERMISSION,\n [UI_RESPONSE.RECEIVE_PREEMPTION]: UI_REQUEST.REQUEST_PREEMPTION,\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>(requestType: string, options?: { timeoutMs?: number }): 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(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(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","import { bytesToHex as nobleBytesToHex, hexToBytes as nobleHexToBytes } from '@noble/hashes/utils';\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/**\n * Convert a hex string (with or without 0x prefix) to a Uint8Array.\n * Throws on invalid hex (non-hex characters, odd length).\n */\nexport function hexToBytes(hex: string): Uint8Array {\n return nobleHexToBytes(stripHex(hex));\n}\n\n/** Convert a Uint8Array to a hex string (no 0x prefix). */\nexport function bytesToHex(bytes: Uint8Array): string {\n return nobleBytesToHex(bytes);\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 'Ledger: Blind signing not enabled in Ethereum app.';\n case HardwareErrorCode.EvmClearSignPluginMissing:\n return 'Ledger: Required plugin not installed (install via Ledger Live).';\n case HardwareErrorCode.EvmDataTooLarge:\n return 'Ledger: Transaction data too large for device memory.';\n case HardwareErrorCode.EvmTxTypeNotSupported:\n return 'Ledger: Transaction type not supported by current Ethereum app.';\n case HardwareErrorCode.AppTooOld:\n return 'Ledger: App out of date (update via Ledger Live).';\n case HardwareErrorCode.SolanaBlindSigningRequired:\n return 'Blind signing disabled in the Solana app.';\n case HardwareErrorCode.TronCustomContractRequired:\n return 'Custom Contracts setting disabled in the Tron app.';\n case HardwareErrorCode.TronDataSigningRequired:\n return 'Transactions Data setting disabled in the Tron app.';\n case HardwareErrorCode.TronSignByHashRequired:\n return 'Sign by Hash setting disabled in the Tron app.';\n case HardwareErrorCode.BtcWalletPolicyHmacMismatch:\n return 'Wallet policy not registered or HMAC mismatch.';\n case HardwareErrorCode.BtcUnexpectedState:\n return 'Signing aborted due to unexpected device state.';\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":["bytesToHex","HardwareErrorCode","EConnectorInteraction","import_utils","nobleHexToBytes","bytesToHex","nobleBytesToHex"]}
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 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 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 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 DeviceJobQueueDeps,\n} from './utils/DeviceJobQueue';\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","/**\n * HWK HardwareErrorCode — independent namespace from the legacy\n * `@onekeyfe/shared` HardwareErrorCode (which occupies 0-902).\n *\n * All HWK codes are 5-digit (>= 10000) so the two tables never collide\n * even if either side grows. Each sub-category gets a 100-slot block.\n *\n * 10000-10099 Generic / cross-cutting primitives\n * 10100-10199 Device state\n * 10200-10299 Firmware\n * 10300-10399 Transport + OS-level permission\n * 10400-10499 PIN / Passphrase\n * 10500-10599 App lifecycle (wrong app, not open, too old)\n * 10600-10999 RESERVED — future adapter-level categories\n *\n * 11000-11099 EVM APDU (reactive mapping)\n * 11100-11199 Solana APDU\n * 11200-11299 Tron APDU\n * 11300-11399 BTC APDU\n * 11400-11999 RESERVED — future chain APDU blocks (100 per chain)\n *\n * 12000-99999 RESERVED — future major categories\n */\nexport enum HardwareErrorCode {\n // --- 10000s Generic ---\n UnknownError = 10000,\n UserRejected = 10001,\n InvalidParams = 10002,\n OperationTimeout = 10003,\n MethodNotSupported = 10004,\n\n // --- 10100s Device state ---\n DeviceNotFound = 10100,\n DeviceDisconnected = 10101,\n DeviceBusy = 10102,\n DeviceLocked = 10103,\n DeviceNotInitialized = 10104,\n DeviceInBootloader = 10105,\n DeviceMismatch = 10106,\n\n // --- 10200s Firmware ---\n FirmwareTooOld = 10200,\n FirmwareUpdateRequired = 10201,\n\n // --- 10300s Transport + permission ---\n TransportError = 10300,\n BridgeNotFound = 10301,\n TransportNotAvailable = 10302,\n /**\n * OS-level permission (Bluetooth / USB / etc.) — denied, blocked,\n * unavailable, or dismissed. Consumers surface a single \"please grant\n * permission\" toast and let the user retry manually.\n */\n DevicePermissionDenied = 10303,\n\n // --- 10400s PIN / Passphrase ---\n PinInvalid = 10400,\n PinCancelled = 10401,\n PassphraseRejected = 10402,\n\n // --- 10500s App lifecycle ---\n AppNotOpen = 10500,\n WrongApp = 10501,\n /** 0x911c Command code not supported — app predates current SDK. */\n AppTooOld = 10502,\n\n // --- 11000s EVM (Ledger Ethereum App) APDU-specific ---\n /** 0x6a80 Invalid data — observed on blindSignTransactionFallback when the\n * user has not enabled Blind signing on the device. */\n EvmBlindSigningRequired = 11000,\n /** 0x6984 Plugin not installed */\n EvmClearSignPluginMissing = 11001,\n /** 0x6a84 Insufficient memory (typical on Nano S with large calldata) */\n EvmDataTooLarge = 11002,\n /** 0x6501 TransactionType not supported (app too old for EIP-1559 / blob / 7702) */\n EvmTxTypeNotSupported = 11003,\n\n // --- 11100s Solana ---\n /** 0x6808 Blind signing disabled for this instruction. */\n SolanaBlindSigningRequired = 11100,\n\n // --- 11200s Tron ---\n /** 0x6a8d Custom Contracts setting disabled (blocks TRC-20 etc.). */\n TronCustomContractRequired = 11200,\n /** 0x6a8b Transactions Data setting disabled. */\n TronDataSigningRequired = 11201,\n /** 0x6a8c Sign by Hash setting disabled (hash-signing fallback). */\n TronSignByHashRequired = 11202,\n\n // --- 11300s BTC ---\n /** 0xb008 Wallet policy HMAC mismatch or not registered. */\n BtcWalletPolicyHmacMismatch = 11300,\n /** 0xb007 Aborted due to unexpected state (malformed PSBT / missing UTXO). */\n BtcUnexpectedState = 11301,\n}\n","import type { 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 */\nimport { sha256 } from '@noble/hashes/sha256';\nimport { bytesToHex, utf8ToBytes } from '@noble/hashes/utils';\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 * 16-char SHA-256 fingerprint for device-identity verification.\n * Callers must canonicalize input (e.g. EVM address → lowercase) —\n * encoding variations otherwise cause false DeviceMismatch.\n */\nexport function deriveDeviceFingerprint(value: string): string {\n return bytesToHex(sha256(utf8ToBytes(value))).slice(0, 16);\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} as const;\n","import type { QrResponseData } from '../types/qr';\nimport type { PreemptionDecision } from '../utils/DeviceJobQueue';\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 REQUEST_PREEMPTION: 'ui-request-preemption',\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 RECEIVE_DEVICE_PERMISSION: 'receive-device-permission',\n RECEIVE_PREEMPTION: 'receive-preemption',\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.RECEIVE_DEVICE_PERMISSION;\n payload: { granted: boolean };\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_PREEMPTION;\n payload: { decision: PreemptionDecision };\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 * The 'confirm' level uses the standard UI request/response flow:\n * emits REQUEST_PREEMPTION → waits for RECEIVE_PREEMPTION via UiRequestRegistry.\n */\n\nimport { UI_REQUEST } from '../events/ui-request';\n\nimport type { UiRequestRegistry } from './UiRequestRegistry';\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 interface DeviceJobQueueDeps {\n /** Emit a UI request event to the frontend. */\n emit: (event: string, data: unknown) => void;\n /** Registry for waiting on UI responses. */\n uiRegistry: UiRequestRegistry;\n}\n\nexport class DeviceJobQueue {\n private readonly _queues = new Map<string, Promise<unknown>>();\n\n private readonly _active = new Map<string, ActiveJob>();\n\n private readonly _deps: DeviceJobQueueDeps | null;\n\n /** Incremented on clear() so stale queued jobs can detect invalidation. */\n private _generation = 0;\n\n constructor(deps?: DeviceJobQueueDeps) {\n this._deps = deps ?? null;\n }\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': emits REQUEST_PREEMPTION and waits for UI response\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 a preemption dialog is already pending, reject immediately.\n // The user is already deciding for a previous request — don't\n // overwrite the UiRequestRegistry slot (single-slot per type).\n if (this._deps?.uiRegistry.hasPending(UI_REQUEST.REQUEST_PREEMPTION)) {\n throw Object.assign(\n new Error(`Device busy: a preemption decision is already pending`),\n { hardwareErrorCode: 'DEVICE_BUSY' }\n );\n }\n const decision = await this._requestPreemptionDecision(deviceId, active, {\n label: options.label,\n interruptibility,\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 default:\n // Unknown decision value from UI — fall back to safest option: wait.\n break;\n }\n break;\n }\n }\n }\n\n const ac = new AbortController();\n const prev = this._queues.get(deviceId) ?? Promise.resolve();\n const gen = this._generation;\n\n const next = prev\n .catch(() => {})\n .then(async () => {\n if (this._generation !== gen) {\n throw new Error('Job cancelled: queue was cleared');\n }\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 this._generation++;\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 /**\n * Request preemption decision via UI request/response flow.\n * Falls back to 'wait' if deps are not provided.\n */\n private async _requestPreemptionDecision(\n deviceId: string,\n active: ActiveJob,\n newJob: { label?: string; interruptibility: Interruptibility }\n ): Promise<PreemptionDecision> {\n if (!this._deps) return 'wait';\n\n const { emit, uiRegistry } = this._deps;\n\n emit(UI_REQUEST.REQUEST_PREEMPTION, {\n type: UI_REQUEST.REQUEST_PREEMPTION,\n payload: {\n deviceId,\n currentJob: {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n },\n newJob,\n },\n });\n\n const response = await uiRegistry.wait<{ decision: PreemptionDecision }>(\n UI_REQUEST.REQUEST_PREEMPTION\n );\n\n return response?.decision ?? 'wait';\n }\n}\n","import type { ConnectionType, 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 /** Physical connection type this connector uses. Fixed at construction. */\n readonly connectionType: ConnectionType;\n\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 connectionType: ConnectionType,\n bridge: IHardwareBridge\n): IConnector {\n // Keyed by (event, handler). A flat handler-only map would collide when the\n // same function is registered for multiple events — second .on() would\n // overwrite the first bridge handler reference, leaking it permanently.\n type UserHandler = (data: ConnectorEventMap[ConnectorEventType]) => void;\n type BridgeHandler = (event: { type: ConnectorEventType; data: unknown }) => void;\n const handlerMap = new Map<ConnectorEventType, Map<UserHandler, BridgeHandler>>();\n\n return {\n connectionType,\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: BridgeHandler = e => {\n if (e.type === event) {\n handler(e.data as ConnectorEventMap[typeof event]);\n }\n };\n let inner = handlerMap.get(event);\n if (!inner) {\n inner = new Map();\n handlerMap.set(event, inner);\n }\n inner.set(handler as UserHandler, bridgeHandler);\n bridge.onEvent({ vendor }, bridgeHandler);\n },\n off: (event, handler) => {\n const inner = handlerMap.get(event);\n const bridgeHandler = inner?.get(handler as UserHandler);\n if (!bridgeHandler || !inner) return;\n bridge.offEvent({ vendor }, bridgeHandler);\n inner.delete(handler as UserHandler);\n if (inner.size === 0) handlerMap.delete(event);\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\n on(event: string, listener: (event: any) => void): void;\n\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\n off(event: string, listener: (event: any) => void): void;\n\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\n emit(event: string, data: unknown): void;\n\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 [UI_RESPONSE.RECEIVE_DEVICE_PERMISSION]: UI_REQUEST.REQUEST_DEVICE_PERMISSION,\n [UI_RESPONSE.RECEIVE_PREEMPTION]: UI_REQUEST.REQUEST_PREEMPTION,\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>(requestType: string, options?: { timeoutMs?: number }): 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(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(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","import { bytesToHex as nobleBytesToHex, hexToBytes as nobleHexToBytes } from '@noble/hashes/utils';\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/**\n * Convert a hex string (with or without 0x prefix) to a Uint8Array.\n * Throws on invalid hex (non-hex characters, odd length).\n */\nexport function hexToBytes(hex: string): Uint8Array {\n return nobleHexToBytes(stripHex(hex));\n}\n\n/** Convert a Uint8Array to a hex string (no 0x prefix). */\nexport function bytesToHex(bytes: Uint8Array): string {\n return nobleBytesToHex(bytes);\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 'Ledger: Blind signing not enabled in Ethereum app.';\n case HardwareErrorCode.EvmClearSignPluginMissing:\n return 'Ledger: Required plugin not installed (install via Ledger Live).';\n case HardwareErrorCode.EvmDataTooLarge:\n return 'Ledger: Transaction data too large for device memory.';\n case HardwareErrorCode.EvmTxTypeNotSupported:\n return 'Ledger: Transaction type not supported by current Ethereum app.';\n case HardwareErrorCode.AppTooOld:\n return 'Ledger: App out of date (update via Ledger Live).';\n case HardwareErrorCode.SolanaBlindSigningRequired:\n return 'Blind signing disabled in the Solana app.';\n case HardwareErrorCode.TronCustomContractRequired:\n return 'Custom Contracts setting disabled in the Tron app.';\n case HardwareErrorCode.TronDataSigningRequired:\n return 'Transactions Data setting disabled in the Tron app.';\n case HardwareErrorCode.TronSignByHashRequired:\n return 'Sign by Hash setting disabled in the Tron app.';\n case HardwareErrorCode.BtcWalletPolicyHmacMismatch:\n return 'Wallet policy not registered or HMAC mismatch.';\n case HardwareErrorCode.BtcUnexpectedState:\n return 'Signing aborted due to unexpected device state.';\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACuBO,IAAK,oBAAL,kBAAKC,uBAAL;AAEL,EAAAA,sCAAA,kBAAe,OAAf;AACA,EAAAA,sCAAA,kBAAe,SAAf;AACA,EAAAA,sCAAA,mBAAgB,SAAhB;AACA,EAAAA,sCAAA,sBAAmB,SAAnB;AACA,EAAAA,sCAAA,wBAAqB,SAArB;AAGA,EAAAA,sCAAA,oBAAiB,SAAjB;AACA,EAAAA,sCAAA,wBAAqB,SAArB;AACA,EAAAA,sCAAA,gBAAa,SAAb;AACA,EAAAA,sCAAA,kBAAe,SAAf;AACA,EAAAA,sCAAA,0BAAuB,SAAvB;AACA,EAAAA,sCAAA,wBAAqB,SAArB;AACA,EAAAA,sCAAA,oBAAiB,SAAjB;AAGA,EAAAA,sCAAA,oBAAiB,SAAjB;AACA,EAAAA,sCAAA,4BAAyB,SAAzB;AAGA,EAAAA,sCAAA,oBAAiB,SAAjB;AACA,EAAAA,sCAAA,oBAAiB,SAAjB;AACA,EAAAA,sCAAA,2BAAwB,SAAxB;AAMA,EAAAA,sCAAA,4BAAyB,SAAzB;AAGA,EAAAA,sCAAA,gBAAa,SAAb;AACA,EAAAA,sCAAA,kBAAe,SAAf;AACA,EAAAA,sCAAA,wBAAqB,SAArB;AAGA,EAAAA,sCAAA,gBAAa,SAAb;AACA,EAAAA,sCAAA,cAAW,SAAX;AAEA,EAAAA,sCAAA,eAAY,SAAZ;AAKA,EAAAA,sCAAA,6BAA0B,QAA1B;AAEA,EAAAA,sCAAA,+BAA4B,SAA5B;AAEA,EAAAA,sCAAA,qBAAkB,SAAlB;AAEA,EAAAA,sCAAA,2BAAwB,SAAxB;AAIA,EAAAA,sCAAA,gCAA6B,SAA7B;AAIA,EAAAA,sCAAA,gCAA6B,SAA7B;AAEA,EAAAA,sCAAA,6BAA0B,SAA1B;AAEA,EAAAA,sCAAA,4BAAyB,SAAzB;AAIA,EAAAA,sCAAA,iCAA8B,SAA9B;AAEA,EAAAA,sCAAA,wBAAqB,SAArB;AAtEU,SAAAA;AAAA,GAAA;;;ACNL,SAAS,QAAW,SAAwB;AACjD,SAAO,EAAE,SAAS,MAAM,QAAQ;AAClC;AAEO,SAAS,QAAQ,MAAyB,OAAwB;AACvE,SAAO,EAAE,SAAS,OAAO,SAAS,EAAE,OAAO,KAAK,EAAE;AACpD;;;AChBA,oBAAuB;AACvB,mBAAwC;AAWjC,IAAM,0BAA+D;AAAA,EAC1E,KAAK;AAAA;AAAA;AAAA,EAGL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AACR;AASO,SAAS,wBAAwB,OAAuB;AAC7D,aAAO,6BAAW,0BAAO,0BAAY,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,EAAE;AAC3D;;;ACrCO,IAAM,eAAe;AAGrB,IAAM,SAAS;AAAA,EACpB,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,SAAS;AACX;;;ACJO,IAAM,WAAW;AAEjB,IAAM,aAAa;AAAA,EACxB,aAAa;AAAA,EACb,oBAAoB;AAAA,EACpB,8BAA8B;AAAA,EAC9B,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,iBAAiB;AAAA,EACjB,2BAA2B;AAAA,EAC3B,uBAAuB;AAAA,EACvB,wBAAwB;AAAA,EACxB,oBAAoB;AAAA,EACpB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB,cAAc;AAChB;AAEO,IAAM,cAAc;AAAA,EACzB,aAAa;AAAA,EACb,oBAAoB;AAAA,EACpB,8BAA8B;AAAA,EAC9B,qBAAqB;AAAA,EACrB,uBAAuB;AAAA,EACvB,wBAAwB;AAAA,EACxB,2BAA2B;AAAA,EAC3B,oBAAoB;AAAA,EACpB,QAAQ;AACV;;;AC/BO,IAAM,MAAM;AAAA,EACjB,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,oBAAoB;AACtB;;;ACyCO,IAAM,iBAAN,MAAqB;AAAA,EAU1B,YAAY,MAA2B;AATvC,SAAiB,UAAU,oBAAI,IAA8B;AAE7D,SAAiB,UAAU,oBAAI,IAAuB;AAKtD;AAAA,SAAQ,cAAc;AAGpB,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QACJ,UACA,KACA,UAAsB,CAAC,GACX;AACZ,UAAM,mBAAmB,QAAQ,oBAAoB;AACrD,UAAM,SAAS,KAAK,QAAQ,IAAI,QAAQ;AAExC,QAAI,QAAQ;AACV,cAAQ,OAAO,QAAQ,kBAAkB;AAAA,QACvC,KAAK;AAEH;AAAA,QACF,KAAK;AAEH,iBAAO,gBAAgB,MAAM,IAAI,MAAM,4BAA4B,CAAC;AACpE;AAAA,QACF,KAAK,WAAW;AAId,cAAI,KAAK,OAAO,WAAW,WAAW,WAAW,kBAAkB,GAAG;AACpE,kBAAM,OAAO;AAAA,cACX,IAAI,MAAM,uDAAuD;AAAA,cACjE,EAAE,mBAAmB,cAAc;AAAA,YACrC;AAAA,UACF;AACA,gBAAM,WAAW,MAAM,KAAK,2BAA2B,UAAU,QAAQ;AAAA,YACvE,OAAO,QAAQ;AAAA,YACf;AAAA,UACF,CAAC;AACD,kBAAQ,UAAU;AAAA,YAChB,KAAK;AACH,qBAAO,gBAAgB,MAAM,IAAI,MAAM,kCAAkC,CAAC;AAC1E;AAAA,YACF,KAAK;AACH,oBAAM,OAAO;AAAA,gBACX,IAAI,MAAM,gBAAgB,OAAO,QAAQ,SAAS,mBAAmB,EAAE;AAAA,gBACvE,EAAE,mBAAmB,cAAc;AAAA,cACrC;AAAA,YACF,KAAK;AACH;AAAA,YACF;AAEE;AAAA,UACJ;AACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,KAAK,IAAI,gBAAgB;AAC/B,UAAM,OAAO,KAAK,QAAQ,IAAI,QAAQ,KAAK,QAAQ,QAAQ;AAC3D,UAAM,MAAM,KAAK;AAEjB,UAAM,OAAO,KACV,MAAM,MAAM;AAAA,IAAC,CAAC,EACd,KAAK,YAAY;AAChB,UAAI,KAAK,gBAAgB,KAAK;AAC5B,cAAM,IAAI,MAAM,kCAAkC;AAAA,MACpD;AACA,WAAK,QAAQ,IAAI,UAAU;AAAA,QACzB,SAAS,EAAE,kBAAkB,OAAO,QAAQ,MAAM;AAAA,QAClD,iBAAiB;AAAA,QACjB,WAAW,KAAK,IAAI;AAAA,MACtB,CAAC;AACD,UAAI;AACF,eAAO,MAAM,IAAI,GAAG,MAAM;AAAA,MAC5B,UAAE;AACA,aAAK,QAAQ,OAAO,QAAQ;AAAA,MAC9B;AAAA,IACF,CAAC;AAEH,UAAM,OAAO,KAAK,MAAM,MAAM;AAAA,IAAC,CAAC;AAChC,SAAK,QAAQ,IAAI,UAAU,IAAI;AAC/B,SAAK,KAAK,MAAM;AACd,UAAI,KAAK,QAAQ,IAAI,QAAQ,MAAM,MAAM;AACvC,aAAK,QAAQ,OAAO,QAAQ;AAAA,MAC9B;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,aAAa,UAA2B;AACtC,UAAM,SAAS,KAAK,QAAQ,IAAI,QAAQ;AACxC,QAAI,CAAC,OAAQ,QAAO;AACpB,QAAI,OAAO,QAAQ,qBAAqB,OAAQ,QAAO;AACvD,WAAO,gBAAgB,MAAM,IAAI,MAAM,oBAAoB,CAAC;AAC5D,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,kBAAkB,UAA2B;AAC3C,UAAM,SAAS,KAAK,QAAQ,IAAI,QAAQ;AACxC,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO,gBAAgB,MAAM,IAAI,MAAM,8BAA8B,CAAC;AACtE,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,aAAa,UAAwC;AACnD,UAAM,SAAS,KAAK,QAAQ,IAAI,QAAQ;AACxC,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO;AAAA,MACL,OAAO,OAAO,QAAQ;AAAA,MACtB,kBAAkB,OAAO,QAAQ;AAAA,MACjC,WAAW,OAAO;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,SAAK;AACL,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AAC1C,aAAO,gBAAgB,MAAM,IAAI,MAAM,eAAe,CAAC;AAAA,IACzD;AACA,SAAK,QAAQ,MAAM;AACnB,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,2BACZ,UACA,QACA,QAC6B;AAC7B,QAAI,CAAC,KAAK,MAAO,QAAO;AAExB,UAAM,EAAE,MAAM,WAAW,IAAI,KAAK;AAElC,SAAK,WAAW,oBAAoB;AAAA,MAClC,MAAM,WAAW;AAAA,MACjB,SAAS;AAAA,QACP;AAAA,QACA,YAAY;AAAA,UACV,OAAO,OAAO,QAAQ;AAAA,UACtB,kBAAkB,OAAO,QAAQ;AAAA,UACjC,WAAW,OAAO;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,WAAW,MAAM,WAAW;AAAA,MAChC,WAAW;AAAA,IACb;AAEA,WAAO,UAAU,YAAY;AAAA,EAC/B;AACF;;;AC5LO,IAAK,wBAAL,kBAAKC,2BAAL;AAEL,EAAAA,uBAAA,oBAAiB;AAEjB,EAAAA,uBAAA,kBAAe;AAEf,EAAAA,uBAAA,qBAAkB;AAElB,EAAAA,uBAAA,yBAAsB;AARZ,SAAAA;AAAA,GAAA;AA4FL,SAAS,uBACd,QACA,gBACA,QACY;AAMZ,QAAM,aAAa,oBAAI,IAAyD;AAEhF,SAAO;AAAA,IACL;AAAA,IACA,eAAe,MAAM,OAAO,cAAc,EAAE,OAAO,CAAC;AAAA,IACpD,SAAS,cAAY,OAAO,QAAQ,EAAE,QAAQ,SAAS,CAAC;AAAA,IACxD,YAAY,eAAa,OAAO,WAAW,EAAE,QAAQ,UAAU,CAAC;AAAA,IAChE,MAAM,CAAC,WAAW,QAAQ,eAAe,OAAO,KAAK,EAAE,QAAQ,WAAW,QAAQ,WAAW,CAAC;AAAA,IAC9F,QAAQ,eAAa,OAAO,OAAO,EAAE,QAAQ,UAAU,CAAC;AAAA,IACxD,YAAY,cAAY,OAAO,WAAW,EAAE,QAAQ,SAAS,CAAC;AAAA,IAC9D,IAAI,CAAC,OAAO,YAAY;AACtB,YAAM,gBAA+B,OAAK;AACxC,YAAI,EAAE,SAAS,OAAO;AACpB,kBAAQ,EAAE,IAAuC;AAAA,QACnD;AAAA,MACF;AACA,UAAI,QAAQ,WAAW,IAAI,KAAK;AAChC,UAAI,CAAC,OAAO;AACV,gBAAQ,oBAAI,IAAI;AAChB,mBAAW,IAAI,OAAO,KAAK;AAAA,MAC7B;AACA,YAAM,IAAI,SAAwB,aAAa;AAC/C,aAAO,QAAQ,EAAE,OAAO,GAAG,aAAa;AAAA,IAC1C;AAAA,IACA,KAAK,CAAC,OAAO,YAAY;AACvB,YAAM,QAAQ,WAAW,IAAI,KAAK;AAClC,YAAM,gBAAgB,OAAO,IAAI,OAAsB;AACvD,UAAI,CAAC,iBAAiB,CAAC,MAAO;AAC9B,aAAO,SAAS,EAAE,OAAO,GAAG,aAAa;AACzC,YAAM,OAAO,OAAsB;AACnC,UAAI,MAAM,SAAS,EAAG,YAAW,OAAO,KAAK;AAAA,IAC/C;AAAA,IACA,OAAO,MAAM,OAAO,MAAM,EAAE,OAAO,CAAC;AAAA,EACtC;AACF;;;AC1JO,IAAM,oBAAN,MAAgF;AAAA,EAAhF;AAEL;AAAA,SAAiB,aAAa,oBAAI,IAAuC;AAAA;AAAA,EAMzE,GAAG,OAAe,UAAsC;AACtD,QAAI,MAAM,KAAK,WAAW,IAAI,KAAK;AACnC,QAAI,CAAC,KAAK;AACR,YAAM,oBAAI,IAAI;AACd,WAAK,WAAW,IAAI,OAAO,GAAG;AAAA,IAChC;AACA,QAAI,IAAI,QAAQ;AAAA,EAClB;AAAA,EAMA,IAAI,OAAe,UAAsC;AACvD,UAAM,MAAM,KAAK,WAAW,IAAI,KAAK;AACrC,QAAI,KAAK;AACP,UAAI,OAAO,QAAQ;AACnB,UAAI,IAAI,SAAS,EAAG,MAAK,WAAW,OAAO,KAAK;AAAA,IAClD;AAAA,EACF;AAAA,EAMA,KAAK,OAAe,MAAqB;AACvC,UAAM,MAAM,KAAK,WAAW,IAAI,KAAK;AACrC,QAAI,KAAK;AACP,iBAAW,YAAY,IAAK,UAAS,IAAI;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,qBAA2B;AACzB,SAAK,WAAW,MAAM;AAAA,EACxB;AACF;;;ACtDO,IAAM,gCAAgC;AAE7C,IAAM,sBAA8C;AAAA,EAClD,CAAC,YAAY,WAAW,GAAG,WAAW;AAAA,EACtC,CAAC,YAAY,kBAAkB,GAAG,WAAW;AAAA,EAC7C,CAAC,YAAY,4BAA4B,GAAG,WAAW;AAAA,EACvD,CAAC,YAAY,qBAAqB,GAAG,WAAW;AAAA,EAChD,CAAC,YAAY,sBAAsB,GAAG,WAAW;AAAA,EACjD,CAAC,YAAY,yBAAyB,GAAG,WAAW;AAAA,EACpD,CAAC,YAAY,kBAAkB,GAAG,WAAW;AAAA;AAE/C;AAEO,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,yBAAyB;AAa/B,IAAM,oBAAN,MAAwB;AAAA,EAAxB;AACL,SAAQ,UAAU,oBAAI,IAA0B;AAAA;AAAA,EAEhD,KAAkB,aAAqB,SAA8C;AACnF,UAAM,WAAW,KAAK,QAAQ,IAAI,WAAW;AAC7C,QAAI,UAAU;AACZ,mBAAa,SAAS,KAAK;AAC3B,WAAK,QAAQ,OAAO,WAAW;AAC/B,eAAS;AAAA,QACP,OAAO,OAAO,IAAI,MAAM,eAAe,WAAW,mCAAmC,GAAG;AAAA,UACtF,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,YAAY,SAAS,aAAa;AAExC,WAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,YAAM,QAAQ,WAAW,MAAM;AAC7B,YAAI,KAAK,QAAQ,IAAI,WAAW,GAAG,UAAU,OAAO;AAClD,eAAK,QAAQ,OAAO,WAAW;AAC/B;AAAA,YACE,OAAO,OAAO,IAAI,MAAM,eAAe,WAAW,qBAAqB,SAAS,IAAI,GAAG;AAAA,cACrF,MAAM;AAAA,YACR,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF,GAAG,SAAS;AAEZ,WAAK,QAAQ,IAAI,aAAa;AAAA,QAC5B;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ,cAAsB,SAAwB;AACpD,QAAI,cAAc,oBAAoB,YAAY;AAClD,QAAI,iBAAiB,YAAY,qBAAqB;AACpD,UAAI,KAAK,QAAQ,IAAI,WAAW,kBAAkB,GAAG;AACnD,sBAAc,WAAW;AAAA,MAC3B,WAAW,KAAK,QAAQ,IAAI,WAAW,eAAe,GAAG;AACvD,sBAAc,WAAW;AAAA,MAC3B;AAAA,IACF;AACA,QAAI,CAAC,YAAa;AAElB,UAAM,QAAQ,KAAK,QAAQ,IAAI,WAAW;AAC1C,QAAI,CAAC,MAAO;AAEZ,iBAAa,MAAM,KAAK;AACxB,SAAK,QAAQ,OAAO,WAAW;AAC/B,UAAM,QAAQ,OAAO;AAAA,EACvB;AAAA,EAEA,OAAO,aAA4B;AACjC,QAAI,aAAa;AACf,YAAM,QAAQ,KAAK,QAAQ,IAAI,WAAW;AAC1C,UAAI,CAAC,MAAO;AACZ,mBAAa,MAAM,KAAK;AACxB,WAAK,QAAQ,OAAO,WAAW;AAC/B,YAAM;AAAA,QACJ,OAAO,OAAO,IAAI,MAAM,eAAe,WAAW,iBAAiB,GAAG;AAAA,UACpE,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AACA;AAAA,IACF;AAEA,eAAW,CAAC,MAAM,KAAK,KAAK,KAAK,SAAS;AACxC,mBAAa,MAAM,KAAK;AACxB,YAAM;AAAA,QACJ,OAAO,OAAO,IAAI,MAAM,eAAe,IAAI,iBAAiB,GAAG;AAAA,UAC7D,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF;AACA,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEA,QAAc;AACZ,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,WAAW,aAA8B;AACvC,WAAO,KAAK,QAAQ,IAAI,WAAW;AAAA,EACrC;AACF;;;ACnHO,SAAS,cAAc,GAAW,GAAmB;AAC1D,QAAM,KAAK,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM;AAClC,QAAM,KAAK,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM;AAClC,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,KAAK,GAAG,CAAC,KAAK;AACpB,UAAM,KAAK,GAAG,CAAC,KAAK;AACpB,QAAI,KAAK,GAAI,QAAO;AACpB,QAAI,KAAK,GAAI,QAAO;AAAA,EACtB;AACA,SAAO;AACT;;;ACdA,IAAAC,gBAA6E;AAGtE,SAAS,SAAS,KAAqB;AAC5C,SAAO,IAAI,WAAW,IAAI,IAAI,MAAM,KAAK,GAAG;AAC9C;AAGO,SAAS,SAAS,KAAqB;AAC5C,SAAO,IAAI,WAAW,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI;AAC/C;AAGO,SAAS,SAAS,KAAqB;AAC5C,SAAO,KAAK,SAAS,GAAG,EAAE,SAAS,IAAI,GAAG,CAAC;AAC7C;AAMO,SAAS,WAAW,KAAyB;AAClD,aAAO,cAAAC,YAAgB,SAAS,GAAG,CAAC;AACtC;AAGO,SAASC,YAAW,OAA2B;AACpD,aAAO,cAAAC,YAAgB,KAAK;AAC9B;;;ACtBO,SAAS,mBAAmB,MAAyB,iBAAiC;AAC3F,UAAQ,MAAM;AAAA,IACZ;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO,GAAG,eAAe;AAAA,IAC3B;AACE,aAAO;AAAA,IACT;AACE,aAAO;AAAA,IACT;AACE,aAAO;AAAA,IACT;AACE,aAAO;AAAA,IACT;AACE,aAAO;AAAA,IACT;AACE,aAAO;AAAA,IACT;AACE,aAAO;AAAA,IACT;AACE,aAAO;AAAA,IACT;AACE,aAAO;AAAA,IACT;AACE,aAAO;AAAA,IACT;AACE,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;;;ACnDA,eAAsB,UACpB,QACA,QACA,YAC8B;AAC9B,QAAM,UAAqB,CAAC;AAC5B,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,SAAS,MAAM,OAAO,OAAO,CAAC,CAAC;AACrC,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO;AAAA,IACT;AACA,YAAQ,KAAK,OAAO,OAAO;AAC3B,iBAAa,EAAE,OAAO,GAAG,OAAO,OAAO,OAAO,CAAC;AAAA,EACjD;AACA,SAAO,EAAE,SAAS,MAAM,SAAS,QAAQ;AAC3C;","names":["bytesToHex","HardwareErrorCode","EConnectorInteraction","import_utils","nobleHexToBytes","bytesToHex","nobleBytesToHex"]}
package/dist/index.mjs CHANGED
@@ -1,39 +1,39 @@
1
1
  // src/types/errors.ts
2
2
  var HardwareErrorCode = /* @__PURE__ */ ((HardwareErrorCode2) => {
3
- HardwareErrorCode2[HardwareErrorCode2["UnknownError"] = 0] = "UnknownError";
4
- HardwareErrorCode2[HardwareErrorCode2["DeviceNotFound"] = 1] = "DeviceNotFound";
5
- HardwareErrorCode2[HardwareErrorCode2["DeviceDisconnected"] = 2] = "DeviceDisconnected";
6
- HardwareErrorCode2[HardwareErrorCode2["UserRejected"] = 3] = "UserRejected";
7
- HardwareErrorCode2[HardwareErrorCode2["DeviceBusy"] = 4] = "DeviceBusy";
8
- HardwareErrorCode2[HardwareErrorCode2["FirmwareUpdateRequired"] = 5] = "FirmwareUpdateRequired";
9
- HardwareErrorCode2[HardwareErrorCode2["AppNotOpen"] = 6] = "AppNotOpen";
10
- HardwareErrorCode2[HardwareErrorCode2["InvalidParams"] = 7] = "InvalidParams";
11
- HardwareErrorCode2[HardwareErrorCode2["TransportError"] = 8] = "TransportError";
12
- HardwareErrorCode2[HardwareErrorCode2["OperationTimeout"] = 9] = "OperationTimeout";
13
- HardwareErrorCode2[HardwareErrorCode2["MethodNotSupported"] = 10] = "MethodNotSupported";
14
- HardwareErrorCode2[HardwareErrorCode2["PinInvalid"] = 5520] = "PinInvalid";
15
- HardwareErrorCode2[HardwareErrorCode2["PinCancelled"] = 5521] = "PinCancelled";
16
- HardwareErrorCode2[HardwareErrorCode2["PassphraseRejected"] = 5522] = "PassphraseRejected";
17
- HardwareErrorCode2[HardwareErrorCode2["DeviceLocked"] = 5530] = "DeviceLocked";
18
- HardwareErrorCode2[HardwareErrorCode2["DeviceNotInitialized"] = 5531] = "DeviceNotInitialized";
19
- HardwareErrorCode2[HardwareErrorCode2["DeviceInBootloader"] = 5532] = "DeviceInBootloader";
20
- HardwareErrorCode2[HardwareErrorCode2["FirmwareTooOld"] = 5533] = "FirmwareTooOld";
21
- HardwareErrorCode2[HardwareErrorCode2["WrongApp"] = 5540] = "WrongApp";
22
- HardwareErrorCode2[HardwareErrorCode2["DeviceMismatch"] = 5560] = "DeviceMismatch";
23
- HardwareErrorCode2[HardwareErrorCode2["BridgeNotFound"] = 5550] = "BridgeNotFound";
24
- HardwareErrorCode2[HardwareErrorCode2["TransportNotAvailable"] = 5551] = "TransportNotAvailable";
25
- HardwareErrorCode2[HardwareErrorCode2["DevicePermissionDenied"] = 5570] = "DevicePermissionDenied";
26
- HardwareErrorCode2[HardwareErrorCode2["EvmBlindSigningRequired"] = 7001] = "EvmBlindSigningRequired";
27
- HardwareErrorCode2[HardwareErrorCode2["EvmClearSignPluginMissing"] = 7002] = "EvmClearSignPluginMissing";
28
- HardwareErrorCode2[HardwareErrorCode2["EvmDataTooLarge"] = 7003] = "EvmDataTooLarge";
29
- HardwareErrorCode2[HardwareErrorCode2["EvmTxTypeNotSupported"] = 7004] = "EvmTxTypeNotSupported";
30
- HardwareErrorCode2[HardwareErrorCode2["AppTooOld"] = 7005] = "AppTooOld";
31
- HardwareErrorCode2[HardwareErrorCode2["SolanaBlindSigningRequired"] = 7101] = "SolanaBlindSigningRequired";
32
- HardwareErrorCode2[HardwareErrorCode2["TronCustomContractRequired"] = 7201] = "TronCustomContractRequired";
33
- HardwareErrorCode2[HardwareErrorCode2["TronDataSigningRequired"] = 7202] = "TronDataSigningRequired";
34
- HardwareErrorCode2[HardwareErrorCode2["TronSignByHashRequired"] = 7203] = "TronSignByHashRequired";
35
- HardwareErrorCode2[HardwareErrorCode2["BtcWalletPolicyHmacMismatch"] = 7301] = "BtcWalletPolicyHmacMismatch";
36
- HardwareErrorCode2[HardwareErrorCode2["BtcUnexpectedState"] = 7302] = "BtcUnexpectedState";
3
+ HardwareErrorCode2[HardwareErrorCode2["UnknownError"] = 1e4] = "UnknownError";
4
+ HardwareErrorCode2[HardwareErrorCode2["UserRejected"] = 10001] = "UserRejected";
5
+ HardwareErrorCode2[HardwareErrorCode2["InvalidParams"] = 10002] = "InvalidParams";
6
+ HardwareErrorCode2[HardwareErrorCode2["OperationTimeout"] = 10003] = "OperationTimeout";
7
+ HardwareErrorCode2[HardwareErrorCode2["MethodNotSupported"] = 10004] = "MethodNotSupported";
8
+ HardwareErrorCode2[HardwareErrorCode2["DeviceNotFound"] = 10100] = "DeviceNotFound";
9
+ HardwareErrorCode2[HardwareErrorCode2["DeviceDisconnected"] = 10101] = "DeviceDisconnected";
10
+ HardwareErrorCode2[HardwareErrorCode2["DeviceBusy"] = 10102] = "DeviceBusy";
11
+ HardwareErrorCode2[HardwareErrorCode2["DeviceLocked"] = 10103] = "DeviceLocked";
12
+ HardwareErrorCode2[HardwareErrorCode2["DeviceNotInitialized"] = 10104] = "DeviceNotInitialized";
13
+ HardwareErrorCode2[HardwareErrorCode2["DeviceInBootloader"] = 10105] = "DeviceInBootloader";
14
+ HardwareErrorCode2[HardwareErrorCode2["DeviceMismatch"] = 10106] = "DeviceMismatch";
15
+ HardwareErrorCode2[HardwareErrorCode2["FirmwareTooOld"] = 10200] = "FirmwareTooOld";
16
+ HardwareErrorCode2[HardwareErrorCode2["FirmwareUpdateRequired"] = 10201] = "FirmwareUpdateRequired";
17
+ HardwareErrorCode2[HardwareErrorCode2["TransportError"] = 10300] = "TransportError";
18
+ HardwareErrorCode2[HardwareErrorCode2["BridgeNotFound"] = 10301] = "BridgeNotFound";
19
+ HardwareErrorCode2[HardwareErrorCode2["TransportNotAvailable"] = 10302] = "TransportNotAvailable";
20
+ HardwareErrorCode2[HardwareErrorCode2["DevicePermissionDenied"] = 10303] = "DevicePermissionDenied";
21
+ HardwareErrorCode2[HardwareErrorCode2["PinInvalid"] = 10400] = "PinInvalid";
22
+ HardwareErrorCode2[HardwareErrorCode2["PinCancelled"] = 10401] = "PinCancelled";
23
+ HardwareErrorCode2[HardwareErrorCode2["PassphraseRejected"] = 10402] = "PassphraseRejected";
24
+ HardwareErrorCode2[HardwareErrorCode2["AppNotOpen"] = 10500] = "AppNotOpen";
25
+ HardwareErrorCode2[HardwareErrorCode2["WrongApp"] = 10501] = "WrongApp";
26
+ HardwareErrorCode2[HardwareErrorCode2["AppTooOld"] = 10502] = "AppTooOld";
27
+ HardwareErrorCode2[HardwareErrorCode2["EvmBlindSigningRequired"] = 11e3] = "EvmBlindSigningRequired";
28
+ HardwareErrorCode2[HardwareErrorCode2["EvmClearSignPluginMissing"] = 11001] = "EvmClearSignPluginMissing";
29
+ HardwareErrorCode2[HardwareErrorCode2["EvmDataTooLarge"] = 11002] = "EvmDataTooLarge";
30
+ HardwareErrorCode2[HardwareErrorCode2["EvmTxTypeNotSupported"] = 11003] = "EvmTxTypeNotSupported";
31
+ HardwareErrorCode2[HardwareErrorCode2["SolanaBlindSigningRequired"] = 11100] = "SolanaBlindSigningRequired";
32
+ HardwareErrorCode2[HardwareErrorCode2["TronCustomContractRequired"] = 11200] = "TronCustomContractRequired";
33
+ HardwareErrorCode2[HardwareErrorCode2["TronDataSigningRequired"] = 11201] = "TronDataSigningRequired";
34
+ HardwareErrorCode2[HardwareErrorCode2["TronSignByHashRequired"] = 11202] = "TronSignByHashRequired";
35
+ HardwareErrorCode2[HardwareErrorCode2["BtcWalletPolicyHmacMismatch"] = 11300] = "BtcWalletPolicyHmacMismatch";
36
+ HardwareErrorCode2[HardwareErrorCode2["BtcUnexpectedState"] = 11301] = "BtcUnexpectedState";
37
37
  return HardwareErrorCode2;
38
38
  })(HardwareErrorCode || {});
39
39
 
@@ -455,51 +455,51 @@ function bytesToHex2(bytes) {
455
455
  // src/utils/errorMessages.ts
456
456
  function enrichErrorMessage(code, originalMessage) {
457
457
  switch (code) {
458
- case 5520 /* PinInvalid */:
458
+ case 10400 /* PinInvalid */:
459
459
  return `${originalMessage}. Please re-enter your PIN.`;
460
- case 5521 /* PinCancelled */:
460
+ case 10401 /* PinCancelled */:
461
461
  return `${originalMessage}. PIN entry was cancelled.`;
462
- case 4 /* DeviceBusy */:
462
+ case 10102 /* DeviceBusy */:
463
463
  return `${originalMessage}. The device is in use by another application. Close other wallet apps and try again.`;
464
- case 2 /* DeviceDisconnected */:
464
+ case 10101 /* DeviceDisconnected */:
465
465
  return `${originalMessage}. Please reconnect the device and try again.`;
466
- case 5530 /* DeviceLocked */:
466
+ case 10103 /* DeviceLocked */:
467
467
  return `${originalMessage}. Please unlock your device and try again.`;
468
- case 3 /* UserRejected */:
468
+ case 10001 /* UserRejected */:
469
469
  return `${originalMessage}. The request was rejected on the device.`;
470
- case 5540 /* WrongApp */:
470
+ case 10501 /* WrongApp */:
471
471
  return `${originalMessage}. Please open the correct app on your device.`;
472
- case 6 /* AppNotOpen */:
472
+ case 10500 /* AppNotOpen */:
473
473
  return `${originalMessage}. The required app is not installed on the device.`;
474
- case 5551 /* TransportNotAvailable */:
474
+ case 10302 /* TransportNotAvailable */:
475
475
  return `${originalMessage}. Ensure the device bridge/transport is available and running.`;
476
- case 5533 /* FirmwareTooOld */:
476
+ case 10200 /* FirmwareTooOld */:
477
477
  return `${originalMessage}. Please update your device firmware.`;
478
- case 5531 /* DeviceNotInitialized */:
478
+ case 10104 /* DeviceNotInitialized */:
479
479
  return `${originalMessage}. The device may need to be set up first.`;
480
- case 9 /* OperationTimeout */:
480
+ case 10003 /* OperationTimeout */:
481
481
  return `${originalMessage}. The operation timed out. Please try again.`;
482
- case 7001 /* EvmBlindSigningRequired */:
482
+ case 11e3 /* EvmBlindSigningRequired */:
483
483
  return "Ledger: Blind signing not enabled in Ethereum app.";
484
- case 7002 /* EvmClearSignPluginMissing */:
484
+ case 11001 /* EvmClearSignPluginMissing */:
485
485
  return "Ledger: Required plugin not installed (install via Ledger Live).";
486
- case 7003 /* EvmDataTooLarge */:
486
+ case 11002 /* EvmDataTooLarge */:
487
487
  return "Ledger: Transaction data too large for device memory.";
488
- case 7004 /* EvmTxTypeNotSupported */:
488
+ case 11003 /* EvmTxTypeNotSupported */:
489
489
  return "Ledger: Transaction type not supported by current Ethereum app.";
490
- case 7005 /* AppTooOld */:
490
+ case 10502 /* AppTooOld */:
491
491
  return "Ledger: App out of date (update via Ledger Live).";
492
- case 7101 /* SolanaBlindSigningRequired */:
492
+ case 11100 /* SolanaBlindSigningRequired */:
493
493
  return "Blind signing disabled in the Solana app.";
494
- case 7201 /* TronCustomContractRequired */:
494
+ case 11200 /* TronCustomContractRequired */:
495
495
  return "Custom Contracts setting disabled in the Tron app.";
496
- case 7202 /* TronDataSigningRequired */:
496
+ case 11201 /* TronDataSigningRequired */:
497
497
  return "Transactions Data setting disabled in the Tron app.";
498
- case 7203 /* TronSignByHashRequired */:
498
+ case 11202 /* TronSignByHashRequired */:
499
499
  return "Sign by Hash setting disabled in the Tron app.";
500
- case 7301 /* BtcWalletPolicyHmacMismatch */:
500
+ case 11300 /* BtcWalletPolicyHmacMismatch */:
501
501
  return "Wallet policy not registered or HMAC mismatch.";
502
- case 7302 /* BtcUnexpectedState */:
502
+ case 11301 /* BtcUnexpectedState */:
503
503
  return "Signing aborted due to unexpected device state.";
504
504
  default:
505
505
  return originalMessage;
@@ -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/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 // OS-level permission (Bluetooth / USB / etc.) — denied, blocked, unavailable,\n // or dismissed. Consumers surface a single \"please grant permission\" toast\n // and let the user retry manually.\n DevicePermissionDenied = 5570,\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 // --- Solana ---\n /** 0x6808 Blind signing disabled for this instruction. */\n SolanaBlindSigningRequired = 7101,\n\n // --- Tron ---\n /** 0x6a8d Custom Contracts setting disabled (blocks TRC-20 etc.). */\n TronCustomContractRequired = 7201,\n /** 0x6a8b Transactions Data setting disabled. */\n TronDataSigningRequired = 7202,\n /** 0x6a8c Sign by Hash setting disabled (hash-signing fallback). */\n TronSignByHashRequired = 7203,\n\n // --- BTC ---\n /** 0xb008 Wallet policy HMAC mismatch or not registered. */\n BtcWalletPolicyHmacMismatch = 7301,\n /** 0xb007 Aborted due to unexpected state (malformed PSBT / missing UTXO). */\n BtcUnexpectedState = 7302,\n}\n","import type { 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 */\nimport { sha256 } from '@noble/hashes/sha256';\nimport { bytesToHex, utf8ToBytes } from '@noble/hashes/utils';\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 * 16-char SHA-256 fingerprint for device-identity verification.\n * Callers must canonicalize input (e.g. EVM address → lowercase) —\n * encoding variations otherwise cause false DeviceMismatch.\n */\nexport function deriveDeviceFingerprint(value: string): string {\n return bytesToHex(sha256(utf8ToBytes(value))).slice(0, 16);\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} as const;\n","import type { QrResponseData } from '../types/qr';\nimport type { PreemptionDecision } from '../utils/DeviceJobQueue';\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 REQUEST_PREEMPTION: 'ui-request-preemption',\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 RECEIVE_DEVICE_PERMISSION: 'receive-device-permission',\n RECEIVE_PREEMPTION: 'receive-preemption',\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.RECEIVE_DEVICE_PERMISSION;\n payload: { granted: boolean };\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_PREEMPTION;\n payload: { decision: PreemptionDecision };\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 * The 'confirm' level uses the standard UI request/response flow:\n * emits REQUEST_PREEMPTION → waits for RECEIVE_PREEMPTION via UiRequestRegistry.\n */\n\nimport { UI_REQUEST } from '../events/ui-request';\n\nimport type { UiRequestRegistry } from './UiRequestRegistry';\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 interface DeviceJobQueueDeps {\n /** Emit a UI request event to the frontend. */\n emit: (event: string, data: unknown) => void;\n /** Registry for waiting on UI responses. */\n uiRegistry: UiRequestRegistry;\n}\n\nexport class DeviceJobQueue {\n private readonly _queues = new Map<string, Promise<unknown>>();\n\n private readonly _active = new Map<string, ActiveJob>();\n\n private readonly _deps: DeviceJobQueueDeps | null;\n\n /** Incremented on clear() so stale queued jobs can detect invalidation. */\n private _generation = 0;\n\n constructor(deps?: DeviceJobQueueDeps) {\n this._deps = deps ?? null;\n }\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': emits REQUEST_PREEMPTION and waits for UI response\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 a preemption dialog is already pending, reject immediately.\n // The user is already deciding for a previous request — don't\n // overwrite the UiRequestRegistry slot (single-slot per type).\n if (this._deps?.uiRegistry.hasPending(UI_REQUEST.REQUEST_PREEMPTION)) {\n throw Object.assign(\n new Error(`Device busy: a preemption decision is already pending`),\n { hardwareErrorCode: 'DEVICE_BUSY' }\n );\n }\n const decision = await this._requestPreemptionDecision(deviceId, active, {\n label: options.label,\n interruptibility,\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 default:\n // Unknown decision value from UI — fall back to safest option: wait.\n break;\n }\n break;\n }\n }\n }\n\n const ac = new AbortController();\n const prev = this._queues.get(deviceId) ?? Promise.resolve();\n const gen = this._generation;\n\n const next = prev\n .catch(() => {})\n .then(async () => {\n if (this._generation !== gen) {\n throw new Error('Job cancelled: queue was cleared');\n }\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 this._generation++;\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 /**\n * Request preemption decision via UI request/response flow.\n * Falls back to 'wait' if deps are not provided.\n */\n private async _requestPreemptionDecision(\n deviceId: string,\n active: ActiveJob,\n newJob: { label?: string; interruptibility: Interruptibility }\n ): Promise<PreemptionDecision> {\n if (!this._deps) return 'wait';\n\n const { emit, uiRegistry } = this._deps;\n\n emit(UI_REQUEST.REQUEST_PREEMPTION, {\n type: UI_REQUEST.REQUEST_PREEMPTION,\n payload: {\n deviceId,\n currentJob: {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n },\n newJob,\n },\n });\n\n const response = await uiRegistry.wait<{ decision: PreemptionDecision }>(\n UI_REQUEST.REQUEST_PREEMPTION\n );\n\n return response?.decision ?? 'wait';\n }\n}\n","import type { ConnectionType, 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 /** Physical connection type this connector uses. Fixed at construction. */\n readonly connectionType: ConnectionType;\n\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 connectionType: ConnectionType,\n bridge: IHardwareBridge\n): IConnector {\n // Keyed by (event, handler). A flat handler-only map would collide when the\n // same function is registered for multiple events — second .on() would\n // overwrite the first bridge handler reference, leaking it permanently.\n type UserHandler = (data: ConnectorEventMap[ConnectorEventType]) => void;\n type BridgeHandler = (event: { type: ConnectorEventType; data: unknown }) => void;\n const handlerMap = new Map<ConnectorEventType, Map<UserHandler, BridgeHandler>>();\n\n return {\n connectionType,\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: BridgeHandler = e => {\n if (e.type === event) {\n handler(e.data as ConnectorEventMap[typeof event]);\n }\n };\n let inner = handlerMap.get(event);\n if (!inner) {\n inner = new Map();\n handlerMap.set(event, inner);\n }\n inner.set(handler as UserHandler, bridgeHandler);\n bridge.onEvent({ vendor }, bridgeHandler);\n },\n off: (event, handler) => {\n const inner = handlerMap.get(event);\n const bridgeHandler = inner?.get(handler as UserHandler);\n if (!bridgeHandler || !inner) return;\n bridge.offEvent({ vendor }, bridgeHandler);\n inner.delete(handler as UserHandler);\n if (inner.size === 0) handlerMap.delete(event);\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\n on(event: string, listener: (event: any) => void): void;\n\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\n off(event: string, listener: (event: any) => void): void;\n\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\n emit(event: string, data: unknown): void;\n\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 [UI_RESPONSE.RECEIVE_DEVICE_PERMISSION]: UI_REQUEST.REQUEST_DEVICE_PERMISSION,\n [UI_RESPONSE.RECEIVE_PREEMPTION]: UI_REQUEST.REQUEST_PREEMPTION,\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>(requestType: string, options?: { timeoutMs?: number }): 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(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(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","import { bytesToHex as nobleBytesToHex, hexToBytes as nobleHexToBytes } from '@noble/hashes/utils';\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/**\n * Convert a hex string (with or without 0x prefix) to a Uint8Array.\n * Throws on invalid hex (non-hex characters, odd length).\n */\nexport function hexToBytes(hex: string): Uint8Array {\n return nobleHexToBytes(stripHex(hex));\n}\n\n/** Convert a Uint8Array to a hex string (no 0x prefix). */\nexport function bytesToHex(bytes: Uint8Array): string {\n return nobleBytesToHex(bytes);\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 'Ledger: Blind signing not enabled in Ethereum app.';\n case HardwareErrorCode.EvmClearSignPluginMissing:\n return 'Ledger: Required plugin not installed (install via Ledger Live).';\n case HardwareErrorCode.EvmDataTooLarge:\n return 'Ledger: Transaction data too large for device memory.';\n case HardwareErrorCode.EvmTxTypeNotSupported:\n return 'Ledger: Transaction type not supported by current Ethereum app.';\n case HardwareErrorCode.AppTooOld:\n return 'Ledger: App out of date (update via Ledger Live).';\n case HardwareErrorCode.SolanaBlindSigningRequired:\n return 'Blind signing disabled in the Solana app.';\n case HardwareErrorCode.TronCustomContractRequired:\n return 'Custom Contracts setting disabled in the Tron app.';\n case HardwareErrorCode.TronDataSigningRequired:\n return 'Transactions Data setting disabled in the Tron app.';\n case HardwareErrorCode.TronSignByHashRequired:\n return 'Sign by Hash setting disabled in the Tron app.';\n case HardwareErrorCode.BtcWalletPolicyHmacMismatch:\n return 'Wallet policy not registered or HMAC mismatch.';\n case HardwareErrorCode.BtcUnexpectedState:\n return 'Signing aborted due to unexpected device state.';\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","bytesToHex"]}
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":["/**\n * HWK HardwareErrorCode — independent namespace from the legacy\n * `@onekeyfe/shared` HardwareErrorCode (which occupies 0-902).\n *\n * All HWK codes are 5-digit (>= 10000) so the two tables never collide\n * even if either side grows. Each sub-category gets a 100-slot block.\n *\n * 10000-10099 Generic / cross-cutting primitives\n * 10100-10199 Device state\n * 10200-10299 Firmware\n * 10300-10399 Transport + OS-level permission\n * 10400-10499 PIN / Passphrase\n * 10500-10599 App lifecycle (wrong app, not open, too old)\n * 10600-10999 RESERVED — future adapter-level categories\n *\n * 11000-11099 EVM APDU (reactive mapping)\n * 11100-11199 Solana APDU\n * 11200-11299 Tron APDU\n * 11300-11399 BTC APDU\n * 11400-11999 RESERVED — future chain APDU blocks (100 per chain)\n *\n * 12000-99999 RESERVED — future major categories\n */\nexport enum HardwareErrorCode {\n // --- 10000s Generic ---\n UnknownError = 10000,\n UserRejected = 10001,\n InvalidParams = 10002,\n OperationTimeout = 10003,\n MethodNotSupported = 10004,\n\n // --- 10100s Device state ---\n DeviceNotFound = 10100,\n DeviceDisconnected = 10101,\n DeviceBusy = 10102,\n DeviceLocked = 10103,\n DeviceNotInitialized = 10104,\n DeviceInBootloader = 10105,\n DeviceMismatch = 10106,\n\n // --- 10200s Firmware ---\n FirmwareTooOld = 10200,\n FirmwareUpdateRequired = 10201,\n\n // --- 10300s Transport + permission ---\n TransportError = 10300,\n BridgeNotFound = 10301,\n TransportNotAvailable = 10302,\n /**\n * OS-level permission (Bluetooth / USB / etc.) — denied, blocked,\n * unavailable, or dismissed. Consumers surface a single \"please grant\n * permission\" toast and let the user retry manually.\n */\n DevicePermissionDenied = 10303,\n\n // --- 10400s PIN / Passphrase ---\n PinInvalid = 10400,\n PinCancelled = 10401,\n PassphraseRejected = 10402,\n\n // --- 10500s App lifecycle ---\n AppNotOpen = 10500,\n WrongApp = 10501,\n /** 0x911c Command code not supported — app predates current SDK. */\n AppTooOld = 10502,\n\n // --- 11000s EVM (Ledger Ethereum App) APDU-specific ---\n /** 0x6a80 Invalid data — observed on blindSignTransactionFallback when the\n * user has not enabled Blind signing on the device. */\n EvmBlindSigningRequired = 11000,\n /** 0x6984 Plugin not installed */\n EvmClearSignPluginMissing = 11001,\n /** 0x6a84 Insufficient memory (typical on Nano S with large calldata) */\n EvmDataTooLarge = 11002,\n /** 0x6501 TransactionType not supported (app too old for EIP-1559 / blob / 7702) */\n EvmTxTypeNotSupported = 11003,\n\n // --- 11100s Solana ---\n /** 0x6808 Blind signing disabled for this instruction. */\n SolanaBlindSigningRequired = 11100,\n\n // --- 11200s Tron ---\n /** 0x6a8d Custom Contracts setting disabled (blocks TRC-20 etc.). */\n TronCustomContractRequired = 11200,\n /** 0x6a8b Transactions Data setting disabled. */\n TronDataSigningRequired = 11201,\n /** 0x6a8c Sign by Hash setting disabled (hash-signing fallback). */\n TronSignByHashRequired = 11202,\n\n // --- 11300s BTC ---\n /** 0xb008 Wallet policy HMAC mismatch or not registered. */\n BtcWalletPolicyHmacMismatch = 11300,\n /** 0xb007 Aborted due to unexpected state (malformed PSBT / missing UTXO). */\n BtcUnexpectedState = 11301,\n}\n","import type { 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 */\nimport { sha256 } from '@noble/hashes/sha256';\nimport { bytesToHex, utf8ToBytes } from '@noble/hashes/utils';\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 * 16-char SHA-256 fingerprint for device-identity verification.\n * Callers must canonicalize input (e.g. EVM address → lowercase) —\n * encoding variations otherwise cause false DeviceMismatch.\n */\nexport function deriveDeviceFingerprint(value: string): string {\n return bytesToHex(sha256(utf8ToBytes(value))).slice(0, 16);\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} as const;\n","import type { QrResponseData } from '../types/qr';\nimport type { PreemptionDecision } from '../utils/DeviceJobQueue';\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 REQUEST_PREEMPTION: 'ui-request-preemption',\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 RECEIVE_DEVICE_PERMISSION: 'receive-device-permission',\n RECEIVE_PREEMPTION: 'receive-preemption',\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.RECEIVE_DEVICE_PERMISSION;\n payload: { granted: boolean };\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_PREEMPTION;\n payload: { decision: PreemptionDecision };\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 * The 'confirm' level uses the standard UI request/response flow:\n * emits REQUEST_PREEMPTION → waits for RECEIVE_PREEMPTION via UiRequestRegistry.\n */\n\nimport { UI_REQUEST } from '../events/ui-request';\n\nimport type { UiRequestRegistry } from './UiRequestRegistry';\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 interface DeviceJobQueueDeps {\n /** Emit a UI request event to the frontend. */\n emit: (event: string, data: unknown) => void;\n /** Registry for waiting on UI responses. */\n uiRegistry: UiRequestRegistry;\n}\n\nexport class DeviceJobQueue {\n private readonly _queues = new Map<string, Promise<unknown>>();\n\n private readonly _active = new Map<string, ActiveJob>();\n\n private readonly _deps: DeviceJobQueueDeps | null;\n\n /** Incremented on clear() so stale queued jobs can detect invalidation. */\n private _generation = 0;\n\n constructor(deps?: DeviceJobQueueDeps) {\n this._deps = deps ?? null;\n }\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': emits REQUEST_PREEMPTION and waits for UI response\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 a preemption dialog is already pending, reject immediately.\n // The user is already deciding for a previous request — don't\n // overwrite the UiRequestRegistry slot (single-slot per type).\n if (this._deps?.uiRegistry.hasPending(UI_REQUEST.REQUEST_PREEMPTION)) {\n throw Object.assign(\n new Error(`Device busy: a preemption decision is already pending`),\n { hardwareErrorCode: 'DEVICE_BUSY' }\n );\n }\n const decision = await this._requestPreemptionDecision(deviceId, active, {\n label: options.label,\n interruptibility,\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 default:\n // Unknown decision value from UI — fall back to safest option: wait.\n break;\n }\n break;\n }\n }\n }\n\n const ac = new AbortController();\n const prev = this._queues.get(deviceId) ?? Promise.resolve();\n const gen = this._generation;\n\n const next = prev\n .catch(() => {})\n .then(async () => {\n if (this._generation !== gen) {\n throw new Error('Job cancelled: queue was cleared');\n }\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 this._generation++;\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 /**\n * Request preemption decision via UI request/response flow.\n * Falls back to 'wait' if deps are not provided.\n */\n private async _requestPreemptionDecision(\n deviceId: string,\n active: ActiveJob,\n newJob: { label?: string; interruptibility: Interruptibility }\n ): Promise<PreemptionDecision> {\n if (!this._deps) return 'wait';\n\n const { emit, uiRegistry } = this._deps;\n\n emit(UI_REQUEST.REQUEST_PREEMPTION, {\n type: UI_REQUEST.REQUEST_PREEMPTION,\n payload: {\n deviceId,\n currentJob: {\n label: active.options.label,\n interruptibility: active.options.interruptibility,\n startedAt: active.startedAt,\n },\n newJob,\n },\n });\n\n const response = await uiRegistry.wait<{ decision: PreemptionDecision }>(\n UI_REQUEST.REQUEST_PREEMPTION\n );\n\n return response?.decision ?? 'wait';\n }\n}\n","import type { ConnectionType, 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 /** Physical connection type this connector uses. Fixed at construction. */\n readonly connectionType: ConnectionType;\n\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 connectionType: ConnectionType,\n bridge: IHardwareBridge\n): IConnector {\n // Keyed by (event, handler). A flat handler-only map would collide when the\n // same function is registered for multiple events — second .on() would\n // overwrite the first bridge handler reference, leaking it permanently.\n type UserHandler = (data: ConnectorEventMap[ConnectorEventType]) => void;\n type BridgeHandler = (event: { type: ConnectorEventType; data: unknown }) => void;\n const handlerMap = new Map<ConnectorEventType, Map<UserHandler, BridgeHandler>>();\n\n return {\n connectionType,\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: BridgeHandler = e => {\n if (e.type === event) {\n handler(e.data as ConnectorEventMap[typeof event]);\n }\n };\n let inner = handlerMap.get(event);\n if (!inner) {\n inner = new Map();\n handlerMap.set(event, inner);\n }\n inner.set(handler as UserHandler, bridgeHandler);\n bridge.onEvent({ vendor }, bridgeHandler);\n },\n off: (event, handler) => {\n const inner = handlerMap.get(event);\n const bridgeHandler = inner?.get(handler as UserHandler);\n if (!bridgeHandler || !inner) return;\n bridge.offEvent({ vendor }, bridgeHandler);\n inner.delete(handler as UserHandler);\n if (inner.size === 0) handlerMap.delete(event);\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\n on(event: string, listener: (event: any) => void): void;\n\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\n off(event: string, listener: (event: any) => void): void;\n\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\n emit(event: string, data: unknown): void;\n\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 [UI_RESPONSE.RECEIVE_DEVICE_PERMISSION]: UI_REQUEST.REQUEST_DEVICE_PERMISSION,\n [UI_RESPONSE.RECEIVE_PREEMPTION]: UI_REQUEST.REQUEST_PREEMPTION,\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>(requestType: string, options?: { timeoutMs?: number }): 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(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(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","import { bytesToHex as nobleBytesToHex, hexToBytes as nobleHexToBytes } from '@noble/hashes/utils';\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/**\n * Convert a hex string (with or without 0x prefix) to a Uint8Array.\n * Throws on invalid hex (non-hex characters, odd length).\n */\nexport function hexToBytes(hex: string): Uint8Array {\n return nobleHexToBytes(stripHex(hex));\n}\n\n/** Convert a Uint8Array to a hex string (no 0x prefix). */\nexport function bytesToHex(bytes: Uint8Array): string {\n return nobleBytesToHex(bytes);\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 'Ledger: Blind signing not enabled in Ethereum app.';\n case HardwareErrorCode.EvmClearSignPluginMissing:\n return 'Ledger: Required plugin not installed (install via Ledger Live).';\n case HardwareErrorCode.EvmDataTooLarge:\n return 'Ledger: Transaction data too large for device memory.';\n case HardwareErrorCode.EvmTxTypeNotSupported:\n return 'Ledger: Transaction type not supported by current Ethereum app.';\n case HardwareErrorCode.AppTooOld:\n return 'Ledger: App out of date (update via Ledger Live).';\n case HardwareErrorCode.SolanaBlindSigningRequired:\n return 'Blind signing disabled in the Solana app.';\n case HardwareErrorCode.TronCustomContractRequired:\n return 'Custom Contracts setting disabled in the Tron app.';\n case HardwareErrorCode.TronDataSigningRequired:\n return 'Transactions Data setting disabled in the Tron app.';\n case HardwareErrorCode.TronSignByHashRequired:\n return 'Sign by Hash setting disabled in the Tron app.';\n case HardwareErrorCode.BtcWalletPolicyHmacMismatch:\n return 'Wallet policy not registered or HMAC mismatch.';\n case HardwareErrorCode.BtcUnexpectedState:\n return 'Signing aborted due to unexpected device state.';\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","bytesToHex"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hwk-adapter-core",
3
- "version": "1.1.26-alpha.7",
3
+ "version": "1.1.26-alpha.8",
4
4
  "description": "Shared types and utilities for OneKey hardware wallet kit",
5
5
  "author": "OneKey",
6
6
  "license": "MIT",
@@ -50,5 +50,5 @@
50
50
  "tsup": "^8.0.0",
51
51
  "typescript": "^5.4.0"
52
52
  },
53
- "gitHead": "ea5c815742a83d3831b641a70babea5499813fe7"
53
+ "gitHead": "f8267f4b63086b9d0bd61b0a3a41912c4c197291"
54
54
  }