@onekeyfe/hwk-adapter-core 1.1.26 → 1.1.27-alpha.100

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.js CHANGED
@@ -41,6 +41,7 @@ __export(index_exports, {
41
41
  bytesToHex: () => bytesToHex2,
42
42
  compareSemver: () => compareSemver,
43
43
  createBridgedConnector: () => createBridgedConnector,
44
+ createCombinedConnector: () => createCombinedConnector,
44
45
  deriveDeviceFingerprint: () => deriveDeviceFingerprint,
45
46
  enrichErrorMessage: () => enrichErrorMessage,
46
47
  ensure0x: () => ensure0x,
@@ -69,6 +70,7 @@ var HardwareErrorCode = /* @__PURE__ */ ((HardwareErrorCode2) => {
69
70
  HardwareErrorCode2[HardwareErrorCode2["DeviceMismatch"] = 10106] = "DeviceMismatch";
70
71
  HardwareErrorCode2[HardwareErrorCode2["DeviceAppStuck"] = 10107] = "DeviceAppStuck";
71
72
  HardwareErrorCode2[HardwareErrorCode2["ChainNotSupported"] = 10108] = "ChainNotSupported";
73
+ HardwareErrorCode2[HardwareErrorCode2["DeviceOneDeviceOnly"] = 10109] = "DeviceOneDeviceOnly";
72
74
  HardwareErrorCode2[HardwareErrorCode2["FirmwareTooOld"] = 10200] = "FirmwareTooOld";
73
75
  HardwareErrorCode2[HardwareErrorCode2["FirmwareUpdateRequired"] = 10201] = "FirmwareUpdateRequired";
74
76
  HardwareErrorCode2[HardwareErrorCode2["TransportError"] = 10300] = "TransportError";
@@ -76,12 +78,15 @@ var HardwareErrorCode = /* @__PURE__ */ ((HardwareErrorCode2) => {
76
78
  HardwareErrorCode2[HardwareErrorCode2["TransportNotAvailable"] = 10302] = "TransportNotAvailable";
77
79
  HardwareErrorCode2[HardwareErrorCode2["DevicePermissionDenied"] = 10303] = "DevicePermissionDenied";
78
80
  HardwareErrorCode2[HardwareErrorCode2["BlePairingTimeout"] = 10304] = "BlePairingTimeout";
81
+ HardwareErrorCode2[HardwareErrorCode2["ThpPairingFailed"] = 10305] = "ThpPairingFailed";
79
82
  HardwareErrorCode2[HardwareErrorCode2["PinInvalid"] = 10400] = "PinInvalid";
80
83
  HardwareErrorCode2[HardwareErrorCode2["PinCancelled"] = 10401] = "PinCancelled";
81
84
  HardwareErrorCode2[HardwareErrorCode2["PassphraseRejected"] = 10402] = "PassphraseRejected";
85
+ HardwareErrorCode2[HardwareErrorCode2["PassphraseStateMismatch"] = 10403] = "PassphraseStateMismatch";
82
86
  HardwareErrorCode2[HardwareErrorCode2["AppNotInstalled"] = 10500] = "AppNotInstalled";
83
87
  HardwareErrorCode2[HardwareErrorCode2["WrongApp"] = 10501] = "WrongApp";
84
88
  HardwareErrorCode2[HardwareErrorCode2["AppTooOld"] = 10502] = "AppTooOld";
89
+ HardwareErrorCode2[HardwareErrorCode2["DeviceOutOfMemory"] = 10503] = "DeviceOutOfMemory";
85
90
  HardwareErrorCode2[HardwareErrorCode2["EvmBlindSigningRequired"] = 11e3] = "EvmBlindSigningRequired";
86
91
  HardwareErrorCode2[HardwareErrorCode2["EvmClearSignPluginMissing"] = 11001] = "EvmClearSignPluginMissing";
87
92
  HardwareErrorCode2[HardwareErrorCode2["EvmDataTooLarge"] = 11002] = "EvmDataTooLarge";
@@ -101,9 +106,11 @@ var ORPHAN_ELIGIBLE_ERROR_CODES = [
101
106
  10101 /* DeviceDisconnected */,
102
107
  10106 /* DeviceMismatch */,
103
108
  10107 /* DeviceAppStuck */,
109
+ 10109 /* DeviceOneDeviceOnly */,
104
110
  10300 /* TransportError */,
105
111
  10303 /* DevicePermissionDenied */,
106
- 10304 /* BlePairingTimeout */
112
+ 10304 /* BlePairingTimeout */,
113
+ 10305 /* ThpPairingFailed */
107
114
  ];
108
115
 
109
116
  // src/types/response.ts
@@ -137,7 +144,18 @@ var DEVICE_EVENT = "DEVICE_EVENT";
137
144
  var DEVICE = {
138
145
  CONNECT: "device-connect",
139
146
  DISCONNECT: "device-disconnect",
140
- CHANGED: "device-changed"
147
+ CHANGED: "device-changed",
148
+ /**
149
+ * Trezor-only. Emitted after a successful THP handshake that minted or
150
+ * refreshed pairing credentials. The host should persist `credentials`
151
+ * keyed by `deviceId` and feed them back into the connector on the next
152
+ * connect to skip the CodeEntry/QrCode/NFC pairing UX.
153
+ *
154
+ * The `TREZOR_` prefix mirrors `UI_REQUEST.REQUEST_TREZOR_THP_PAIRING` —
155
+ * vendor-specific events live in the shared event taxonomy but are named
156
+ * so hosts can ignore them when they don't drive Trezor hardware.
157
+ */
158
+ TREZOR_THP_CREDENTIALS_CHANGED: "device-trezor-thp-credentials-changed"
141
159
  };
142
160
 
143
161
  // src/events/ui-request.ts
@@ -155,6 +173,8 @@ var UI_REQUEST = {
155
173
  // Ledger BTC App: account index >= 100 requires display=true. Adapter asks
156
174
  // the user once per session before promoting the call.
157
175
  REQUEST_BTC_HIGH_INDEX_CONFIRM: "ui-request-btc-high-index-confirm",
176
+ REQUEST_PREEMPTION: "ui-request-preemption",
177
+ REQUEST_TREZOR_THP_PAIRING: "ui-request-trezor-thp-pairing",
158
178
  CLOSE_UI_WINDOW: "ui-close",
159
179
  DEVICE_PROGRESS: "ui-device_progress",
160
180
  FIRMWARE_PROGRESS: "ui-firmware-progress",
@@ -169,6 +189,8 @@ var UI_RESPONSE = {
169
189
  RECEIVE_DEVICE_CONNECT: "receive-device-connect",
170
190
  RECEIVE_DEVICE_PERMISSION: "receive-device-permission",
171
191
  RECEIVE_BTC_HIGH_INDEX_CONFIRM: "receive-btc-high-index-confirm",
192
+ RECEIVE_PREEMPTION: "receive-preemption",
193
+ RECEIVE_TREZOR_THP_PAIRING: "receive-trezor-thp-pairing",
172
194
  CANCEL: "cancel"
173
195
  };
174
196
 
@@ -327,7 +349,143 @@ function createBridgedConnector(vendor, connectionType, bridge) {
327
349
  inner.delete(handler);
328
350
  if (inner.size === 0) handlerMap.delete(event);
329
351
  },
330
- reset: () => bridge.reset({ vendor })
352
+ reset: () => bridge.reset({ vendor }),
353
+ setKnownCredentials: bridge.setKnownCredentials ? (credentials) => {
354
+ void bridge.setKnownCredentials({ vendor, credentials });
355
+ } : void 0
356
+ };
357
+ }
358
+ function createCombinedConnector(connectors) {
359
+ if (connectors.length === 0) {
360
+ throw new Error("createCombinedConnector: at least one connector is required");
361
+ }
362
+ const deviceOwner = /* @__PURE__ */ new Map();
363
+ const sessionOwner = /* @__PURE__ */ new Map();
364
+ const forwarders = /* @__PURE__ */ new Map();
365
+ const rank = (device) => device.connectionType === "ble" ? 1 : 0;
366
+ const sharedCredentials = [];
367
+ const credentialKey = (c) => c.credential ?? JSON.stringify(c);
368
+ const mergeShared = (incoming) => {
369
+ let changed = false;
370
+ for (const cred of incoming) {
371
+ const key = credentialKey(cred);
372
+ if (!sharedCredentials.some((e) => credentialKey(e) === key)) {
373
+ sharedCredentials.push(cred);
374
+ changed = true;
375
+ }
376
+ }
377
+ return changed;
378
+ };
379
+ const broadcastCredentials = () => {
380
+ for (const child of connectors) child.setKnownCredentials?.(sharedCredentials);
381
+ };
382
+ for (const child of connectors) {
383
+ child.on("device-trezor-thp-credentials-changed", (data) => {
384
+ if (mergeShared(data.credentials)) broadcastCredentials();
385
+ });
386
+ }
387
+ const searchDevices = async () => {
388
+ const perConnector = await Promise.all(
389
+ connectors.map(async (child) => {
390
+ try {
391
+ const devices = await child.searchDevices();
392
+ return devices.map((device) => ({
393
+ ...device,
394
+ connectionType: device.connectionType ?? child.connectionType
395
+ }));
396
+ } catch {
397
+ return [];
398
+ }
399
+ })
400
+ );
401
+ deviceOwner.clear();
402
+ const merged = [];
403
+ perConnector.forEach((devices, index) => {
404
+ for (const device of devices) {
405
+ deviceOwner.set(device.connectId, connectors[index]);
406
+ merged.push(device);
407
+ }
408
+ });
409
+ return merged.sort((a, b) => rank(a) - rank(b));
410
+ };
411
+ const resolveOwner = async (deviceId) => {
412
+ if (deviceId && deviceOwner.has(deviceId)) {
413
+ return { owner: deviceOwner.get(deviceId), deviceId };
414
+ }
415
+ const devices = await searchDevices();
416
+ if (deviceId) {
417
+ const owner = deviceOwner.get(deviceId);
418
+ if (!owner) throw new Error(`Combined connector: device not found: ${deviceId}`);
419
+ return { owner, deviceId };
420
+ }
421
+ const first = devices[0];
422
+ if (!first) throw new Error("Combined connector: no devices found");
423
+ return { owner: deviceOwner.get(first.connectId), deviceId: first.connectId };
424
+ };
425
+ return {
426
+ // Nominal value only — the per-device `connectionType` is authoritative
427
+ // for a fused connector.
428
+ connectionType: connectors[0].connectionType,
429
+ searchDevices,
430
+ connect: async (deviceId) => {
431
+ const { owner, deviceId: resolved } = await resolveOwner(deviceId);
432
+ const session = await owner.connect(resolved);
433
+ sessionOwner.set(session.sessionId, owner);
434
+ return session;
435
+ },
436
+ disconnect: async (sessionId) => {
437
+ const owner = sessionOwner.get(sessionId);
438
+ if (!owner) return;
439
+ await owner.disconnect(sessionId);
440
+ sessionOwner.delete(sessionId);
441
+ },
442
+ call: async (sessionId, method, params) => {
443
+ const owner = sessionOwner.get(sessionId);
444
+ if (!owner) throw new Error(`Combined connector: session not found: ${sessionId}`);
445
+ return owner.call(sessionId, method, params);
446
+ },
447
+ cancel: async (sessionId) => {
448
+ const owner = sessionOwner.get(sessionId);
449
+ if (!owner) return;
450
+ await owner.cancel(sessionId);
451
+ },
452
+ uiResponse: (response) => {
453
+ for (const child of connectors) child.uiResponse(response);
454
+ },
455
+ on: (event, handler) => {
456
+ const attached = connectors.map((child) => {
457
+ const forward = (data) => handler(data);
458
+ child.on(event, forward);
459
+ return { child, handler: forward };
460
+ });
461
+ let inner = forwarders.get(event);
462
+ if (!inner) {
463
+ inner = /* @__PURE__ */ new Map();
464
+ forwarders.set(event, inner);
465
+ }
466
+ inner.set(handler, attached);
467
+ },
468
+ off: (event, handler) => {
469
+ const inner = forwarders.get(event);
470
+ const attached = inner?.get(handler);
471
+ if (!attached || !inner) return;
472
+ for (const { child, handler: forward } of attached) {
473
+ child.off(event, forward);
474
+ }
475
+ inner.delete(handler);
476
+ if (inner.size === 0) forwarders.delete(event);
477
+ },
478
+ reset: () => {
479
+ for (const child of connectors) child.reset();
480
+ deviceOwner.clear();
481
+ sessionOwner.clear();
482
+ forwarders.clear();
483
+ },
484
+ setKnownCredentials: connectors.some((c) => c.setKnownCredentials) ? (credentials) => {
485
+ sharedCredentials.length = 0;
486
+ mergeShared(credentials ?? []);
487
+ broadcastCredentials();
488
+ } : void 0
331
489
  };
332
490
  }
333
491
 
@@ -361,6 +519,10 @@ var TypedEventEmitter = class {
361
519
  removeAllListeners() {
362
520
  this._listeners.clear();
363
521
  }
522
+ /** Number of listeners registered for `event`. 0 if none. */
523
+ listenerCount(event) {
524
+ return this._listeners.get(event)?.size ?? 0;
525
+ }
364
526
  };
365
527
 
366
528
  // src/utils/UiRequestRegistry.ts
@@ -372,7 +534,9 @@ var RESPONSE_TO_REQUEST = {
372
534
  [UI_RESPONSE.RECEIVE_SELECT_DEVICE]: UI_REQUEST.REQUEST_SELECT_DEVICE,
373
535
  [UI_RESPONSE.RECEIVE_DEVICE_CONNECT]: UI_REQUEST.REQUEST_DEVICE_CONNECT,
374
536
  [UI_RESPONSE.RECEIVE_DEVICE_PERMISSION]: UI_REQUEST.REQUEST_DEVICE_PERMISSION,
375
- [UI_RESPONSE.RECEIVE_BTC_HIGH_INDEX_CONFIRM]: UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM
537
+ [UI_RESPONSE.RECEIVE_BTC_HIGH_INDEX_CONFIRM]: UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM,
538
+ [UI_RESPONSE.RECEIVE_PREEMPTION]: UI_REQUEST.REQUEST_PREEMPTION,
539
+ [UI_RESPONSE.RECEIVE_TREZOR_THP_PAIRING]: UI_REQUEST.REQUEST_TREZOR_THP_PAIRING
376
540
  // RECEIVE_QR_RESPONSE maps to QR_DISPLAY or QR_SCAN — resolved dynamically below.
377
541
  };
378
542
  var UI_REQUEST_PREEMPTED_TAG = "UiRequestPreempted";
@@ -504,12 +668,16 @@ function enrichErrorMessage(code, originalMessage) {
504
668
  return `${originalMessage}. Please reconnect the device and try again.`;
505
669
  case 10103 /* DeviceLocked */:
506
670
  return `${originalMessage}. Please unlock your device and try again.`;
671
+ case 10109 /* DeviceOneDeviceOnly */:
672
+ return `${originalMessage}. Disconnect the extra device and try again.`;
507
673
  case 10001 /* UserRejected */:
508
674
  return `${originalMessage}. The request was rejected on the device.`;
509
675
  case 10501 /* WrongApp */:
510
676
  return `${originalMessage}. Please open the correct app on your device.`;
511
677
  case 10500 /* AppNotInstalled */:
512
678
  return `${originalMessage}. The required app is not installed on the device.`;
679
+ case 10503 /* DeviceOutOfMemory */:
680
+ return `${originalMessage}. Not enough free space on the device. Please uninstall some apps and try again.`;
513
681
  case 10302 /* TransportNotAvailable */:
514
682
  return `${originalMessage}. Ensure the device bridge/transport is available and running.`;
515
683
  case 10200 /* FirmwareTooOld */:
@@ -581,6 +749,7 @@ async function batchCall(params, callFn, onProgress) {
581
749
  bytesToHex,
582
750
  compareSemver,
583
751
  createBridgedConnector,
752
+ createCombinedConnector,
584
753
  deriveDeviceFingerprint,
585
754
  enrichErrorMessage,
586
755
  ensure0x,
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, ORPHAN_ELIGIBLE_ERROR_CODES } 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 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 SearchDevicesOptions,\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 {\n DevicePermissionDeniedReason,\n DevicePermissionResponse,\n UiResponseEvent,\n} 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 { JobOptions, ActiveJobInfo } from './utils/DeviceJobQueue';\n\nexport type {\n ConnectorDevice,\n ConnectorSession,\n ConnectorEventType,\n ConnectorEventMap,\n ConnectorUiEvent,\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 /** User dismissed in-app cancel UI. Distinct from UserRejected (on-device). */\n UserAborted = 10005,\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 /** Chain app wedged (e.g. Ledger BTC 0x6901). User must exit app on device. */\n DeviceAppStuck = 10107,\n /** Vendor (Ledger / Trezor) doesn't support the chain at all. */\n ChainNotSupported = 10108,\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 * BLE SMP pairing did not complete within the GATT bonding window.\n * GATT connected but the device didn't acknowledge SMP — typically\n * because the user didn't confirm the passkey on the device, or the\n * device went out of range mid-pairing. Distinct from OperationTimeout\n * (generic) and from DeviceLocked (Secure Element actually locked).\n */\n BlePairingTimeout = 10304,\n\n // --- 10400s PIN / Passphrase ---\n PinInvalid = 10400,\n PinCancelled = 10401,\n PassphraseRejected = 10402,\n\n // --- 10500s App lifecycle ---\n /** Chain app NOT INSTALLED on device. User must install via Ledger Live. */\n AppNotInstalled = 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\n/**\n * Device-level failures the SDK cannot self-recover from — affect the entire\n * batch (vs per-chain failures like AppNotInstalled / WrongApp which soft-\n * skip in onboarding). Combined with `accounts.length === 0`, signals\n * genuine orphan. Also reused as the batch-abort whitelist for HWK.\n * Single source of truth.\n *\n * UserRejected (device-side reject) is included: pressing reject is an\n * explicit \"I don't consent\" — continuing the batch to ask again on the\n * next chain is harassment, not helpful.\n */\nexport const ORPHAN_ELIGIBLE_ERROR_CODES: number[] = [\n HardwareErrorCode.UserAborted,\n HardwareErrorCode.UserRejected,\n HardwareErrorCode.DeviceNotFound,\n HardwareErrorCode.DeviceDisconnected,\n HardwareErrorCode.DeviceMismatch,\n HardwareErrorCode.DeviceAppStuck,\n HardwareErrorCode.TransportError,\n HardwareErrorCode.DevicePermissionDenied,\n HardwareErrorCode.BlePairingTimeout,\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 params?: Record<string, unknown>;\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(\n code: HardwareErrorCode,\n error: string,\n params?: Record<string, unknown>\n): Failure {\n return {\n success: false,\n payload: { error, code, ...(params ? { params } : {}) },\n };\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';\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 // Ledger BTC App: account index >= 100 requires display=true. Adapter asks\n // the user once per session before promoting the call.\n REQUEST_BTC_HIGH_INDEX_CONFIRM: 'ui-request-btc-high-index-confirm',\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_BTC_HIGH_INDEX_CONFIRM: 'receive-btc-high-index-confirm',\n CANCEL: 'cancel',\n} as const;\n\nexport type DevicePermissionDeniedReason =\n | 'bluetoothTurnedOff'\n | 'permissionDenied'\n | (string & Record<never, never>);\n\nexport type DevicePermissionResponse = {\n granted: boolean;\n reason?: DevicePermissionDeniedReason;\n message?: string;\n};\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: DevicePermissionResponse;\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_BTC_HIGH_INDEX_CONFIRM;\n payload: { confirmed: boolean };\n }\n | {\n type: typeof UI_RESPONSE.CANCEL;\n payload?: undefined;\n };\n","/** Events generated by SDK internal detection (not from hardware directly). */\nexport const SDK = {\n DEVICE_STUCK: 'device-stuck',\n DEVICE_UNRESPONSIVE: 'device-unresponsive',\n DEVICE_RECOVERED: 'device-recovered',\n DEVICE_INTERACTION: 'device-interaction',\n} as const;\n","/**\n * Pure FIFO job queue. Every enqueue chains onto the tail; jobs run one at\n * a time across all devices. The queue is intentionally passive — it does\n * NOT decide whether to interrupt or ask the user. Those are application-\n * layer concerns owned by the caller (e.g. a UI button handler that wants\n * to ask \"device is busy, interrupt current?\" before submitting). The\n * queue exposes inspection (`getActiveJob`) and explicit cancellation\n * (`cancelActive` / `cancelAll`) so callers can implement those policies\n * synchronously, without racing against in-flight enqueues.\n */\n\nexport interface JobOptions {\n label?: string;\n rejectIfBusy?: boolean;\n busyError?: Error;\n}\n\nexport interface ActiveJobInfo {\n deviceId: string;\n label?: string;\n startedAt: number;\n}\n\ninterface ActiveJob {\n deviceId: string;\n label?: string;\n abortController: AbortController;\n startedAt: number;\n}\n\nexport class DeviceJobQueue {\n private _tail: Promise<unknown> = Promise.resolve();\n\n private _active: ActiveJob | null = null;\n\n private readonly _jobs = new Map<object, { deviceId: string }>();\n\n /** Incremented on clear() so queued-but-not-yet-running jobs detect invalidation. */\n private _generation = 0;\n\n private readonly _generationCancelReasons = new Map<number, Error>();\n\n /**\n * Enqueue a job. Runs after every previously-enqueued job has settled.\n * `deviceId` is a label only — used by inspection / cancellation routing.\n */\n async enqueue<T>(\n deviceId: string,\n job: (signal: AbortSignal) => Promise<T>,\n options: JobOptions = {}\n ): Promise<T> {\n if (options.rejectIfBusy && this._jobs.size > 0) {\n throw options.busyError ?? new Error('Device is busy');\n }\n\n const ac = new AbortController();\n const gen = this._generation;\n const prev = this._tail;\n const jobToken = {};\n const activeJob: ActiveJob = {\n deviceId,\n label: options.label,\n abortController: ac,\n startedAt: Date.now(),\n };\n this._jobs.set(jobToken, { deviceId });\n\n const next = prev\n .catch(() => {})\n .then(async () => {\n if (this._generation !== gen) {\n throw (\n this._generationCancelReasons.get(gen) ?? new Error('Job cancelled: queue was cleared')\n );\n }\n this._active = activeJob;\n try {\n return await job(ac.signal);\n } finally {\n // Identity guard: a previous job's deferred finally must not\n // null out a successor's `_active`.\n if (this._active === activeJob) {\n this._active = null;\n }\n }\n })\n .finally(() => {\n this._jobs.delete(jobToken);\n });\n\n this._tail = next.catch(() => {});\n return next;\n }\n\n /** Cancel the active job. If `deviceId` is given, only cancels when it matches. */\n cancelActive(deviceId?: string): boolean {\n if (!this._active) return false;\n if (deviceId && this._active.deviceId !== deviceId) return false;\n this._active.abortController.abort(new Error('Manually cancelled'));\n return true;\n }\n\n /** Force cancel the active job. `reason` becomes signal.reason. */\n forceCancelActive(deviceId?: string, reason?: Error): boolean {\n if (!this._active) return false;\n if (deviceId && this._active.deviceId !== deviceId) return false;\n this._active.abortController.abort(reason ?? new Error('Force cancelled for recovery'));\n return true;\n }\n\n /** Cancel the active job (alias for callers that previously needed multi-device cancel). */\n cancelAllActive(reason?: Error): void {\n if (!this._active) return;\n this._active.abortController.abort(reason ?? new Error('Cancelled by cancelAllActive'));\n }\n\n /** Cancel the active job and invalidate queued jobs that have not started. */\n cancelActiveAndPending(deviceId?: string, reason?: Error): boolean {\n if (deviceId && this._active && this._active.deviceId !== deviceId) {\n return false;\n }\n this.clear(reason ?? new Error('Cancelled by cancelActiveAndPending'));\n return true;\n }\n\n /** Get info about the currently active job, or null if idle. */\n getActiveJob(deviceId?: string): ActiveJobInfo | null {\n if (!this._active) return null;\n if (deviceId && this._active.deviceId !== deviceId) return null;\n return {\n deviceId: this._active.deviceId,\n label: this._active.label,\n startedAt: this._active.startedAt,\n };\n }\n\n /** True if any job is currently running. */\n isBusy(): boolean {\n return this._jobs.size > 0;\n }\n\n clear(reason?: Error): void {\n const cancelledGeneration = this._generation;\n this._generation++;\n const cancelReason = reason ?? new Error('Job cancelled: queue was cleared');\n this._generationCancelReasons.set(cancelledGeneration, cancelReason);\n for (const generation of this._generationCancelReasons.keys()) {\n if (generation < this._generation - 10) {\n this._generationCancelReasons.delete(generation);\n }\n }\n if (this._active) {\n this._active.abortController.abort(cancelReason);\n }\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 /** Machine model id (e.g. \"nanoX\"). */\n model?: string;\n /** Human-readable model name (e.g. \"Ledger Nano X\"). */\n modelName?: string;\n /** BLE signal strength (BLE only). */\n rssi?: number | null;\n /** BLE connectable flag (BLE only). */\n isConnectable?: boolean | null;\n /** USB serial number (USB only). */\n serialNumber?: 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 /** Adapter is actively searching for the device (no session yet) */\n Searching = 'searching',\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\n// All variants share the same payload shape so that emit sites where the\n// `type` is a broad `EConnectorInteraction` value (e.g. piped through\n// `collapseSignerInteraction`) still type-check. Searching has no session\n// yet so it carries an empty `sessionId`.\nexport type ConnectorUiEvent =\n | { type: EConnectorInteraction.Searching; payload: { sessionId: string } }\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_BTC_HIGH_INDEX_CONFIRM]: UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM,\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 supersedes (rejects) the prior pending entry. With the\n * job queue running globally serially, cross-type collisions don't occur in\n * normal flow — same-type preemption is a defensive measure for callers\n * that fire the same request twice without waiting on the first.\n *\n * Unknown response types are dropped silently so the public `uiResponse`\n * 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 if (requestType) return this.pending.has(requestType);\n return this.pending.size > 0;\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.AppNotInstalled:\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, ORPHAN_ELIGIBLE_ERROR_CODES } 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 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 TronResource,\n TronTransferContract,\n TronTriggerSmartContract,\n TronFreezeBalanceV2Contract,\n TronUnfreezeBalanceV2Contract,\n TronVote,\n TronVoteWitnessContract,\n TronWithdrawExpireUnfreezeContract,\n TronContract,\n TronSignTxParams,\n TronSignedTx,\n TronSignMsgParams,\n TronSignature,\n ITronMethods,\n} from './types/chain-tron';\n\nexport type { PassphraseStateAware } from './types/passphrase';\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 SearchDevicesOptions,\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 {\n DevicePermissionDeniedReason,\n DevicePermissionResponse,\n UiResponseEvent,\n} 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 { JobOptions, ActiveJobInfo } from './utils/DeviceJobQueue';\n\nexport type {\n ConnectorDevice,\n ConnectorSession,\n ConnectorEventType,\n ConnectorEventMap,\n ConnectorUiEvent,\n IConnector,\n IHardwareBridge,\n} from './types/connector';\nexport {\n createBridgedConnector,\n createCombinedConnector,\n EConnectorInteraction,\n} 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 /** User dismissed in-app cancel UI. Distinct from UserRejected (on-device). */\n UserAborted = 10005,\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 /** Chain app wedged (e.g. Ledger BTC 0x6901). User must exit app on device. */\n DeviceAppStuck = 10107,\n /** Vendor (Ledger / Trezor) doesn't support the chain at all. */\n ChainNotSupported = 10108,\n /** Current operation supports only one connected device. */\n DeviceOneDeviceOnly = 10109,\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 * BLE SMP pairing did not complete within the GATT bonding window.\n * GATT connected but the device didn't acknowledge SMP — typically\n * because the user didn't confirm the passkey on the device, or the\n * device went out of range mid-pairing. Distinct from OperationTimeout\n * (generic) and from DeviceLocked (Secure Element actually locked).\n */\n BlePairingTimeout = 10304,\n /**\n * Host-managed pairing handshake failed (Trezor THP). The device rejected the\n * pairing exchange — e.g. CodeEntry: the user mistyped the code shown on the\n * device, so the CPace tag didn't match (\"Unexpected Code Entry Tag\").\n * Recoverable: the user re-pairs and re-enters the code. Distinct from\n * BlePairingTimeout (BLE SMP bonding window) and UserRejected (on-device\n * reject button).\n */\n ThpPairingFailed = 10305,\n\n // --- 10400s PIN / Passphrase ---\n PinInvalid = 10400,\n PinCancelled = 10401,\n PassphraseRejected = 10402,\n /**\n * The passphrase entered produced a different wallet (master fingerprint /\n * passphraseState) than the one the caller asked to operate on. Trezor-only:\n * the host pins a wallet by its XFP and the SDK refuses to sign with a\n * mismatched passphrase session. Surfaced by TrezorAdapter.getPassphraseState.\n */\n PassphraseStateMismatch = 10403,\n\n // --- 10500s App lifecycle ---\n /** Chain app NOT INSTALLED on device. User must install via Ledger Live. */\n AppNotInstalled = 10500,\n WrongApp = 10501,\n /** 0x911c Command code not supported — app predates current SDK. */\n AppTooOld = 10502,\n /** Not enough free storage for install/update; user must uninstall apps first. */\n DeviceOutOfMemory = 10503,\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\n/**\n * Device-level failures the SDK cannot self-recover from — affect the entire\n * batch (vs per-chain failures like AppNotInstalled / WrongApp which soft-\n * skip in onboarding). Combined with `accounts.length === 0`, signals\n * genuine orphan. Also reused as the batch-abort whitelist for HWK.\n * Single source of truth.\n *\n * UserRejected (device-side reject) is included: pressing reject is an\n * explicit \"I don't consent\" — continuing the batch to ask again on the\n * next chain is harassment, not helpful.\n */\nexport const ORPHAN_ELIGIBLE_ERROR_CODES: number[] = [\n HardwareErrorCode.UserAborted,\n HardwareErrorCode.UserRejected,\n HardwareErrorCode.DeviceNotFound,\n HardwareErrorCode.DeviceDisconnected,\n HardwareErrorCode.DeviceMismatch,\n HardwareErrorCode.DeviceAppStuck,\n HardwareErrorCode.DeviceOneDeviceOnly,\n HardwareErrorCode.TransportError,\n HardwareErrorCode.DevicePermissionDenied,\n HardwareErrorCode.BlePairingTimeout,\n HardwareErrorCode.ThpPairingFailed,\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 params?: Record<string, unknown>;\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(\n code: HardwareErrorCode,\n error: string,\n params?: Record<string, unknown>\n): Failure {\n return {\n success: false,\n payload: { error, code, ...(params ? { params } : {}) },\n };\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 /**\n * Trezor-only. Emitted after a successful THP handshake that minted or\n * refreshed pairing credentials. The host should persist `credentials`\n * keyed by `deviceId` and feed them back into the connector on the next\n * connect to skip the CodeEntry/QrCode/NFC pairing UX.\n *\n * The `TREZOR_` prefix mirrors `UI_REQUEST.REQUEST_TREZOR_THP_PAIRING` —\n * vendor-specific events live in the shared event taxonomy but are named\n * so hosts can ignore them when they don't drive Trezor hardware.\n */\n TREZOR_THP_CREDENTIALS_CHANGED: 'device-trezor-thp-credentials-changed',\n} as const;\n","import type { QrResponseData } from '../types/qr';\n\nexport const UI_EVENT = 'UI_EVENT';\n\nexport const UI_REQUEST = {\n REQUEST_PIN: 'ui-request-pin',\n REQUEST_PASSPHRASE: 'ui-request-passphrase',\n REQUEST_PASSPHRASE_ON_DEVICE: 'ui-request-passphrase-on-device',\n REQUEST_BUTTON: 'ui-request-button',\n REQUEST_QR_DISPLAY: 'ui-request-qr-display',\n REQUEST_QR_SCAN: 'ui-request-qr-scan',\n REQUEST_DEVICE_PERMISSION: 'ui-request-device-permission',\n REQUEST_SELECT_DEVICE: 'ui-request-select-device',\n REQUEST_DEVICE_CONNECT: 'ui-request-device-connect',\n // Ledger BTC App: account index >= 100 requires display=true. Adapter asks\n // the user once per session before promoting the call.\n REQUEST_BTC_HIGH_INDEX_CONFIRM: 'ui-request-btc-high-index-confirm',\n REQUEST_PREEMPTION: 'ui-request-preemption',\n REQUEST_TREZOR_THP_PAIRING: 'ui-request-trezor-thp-pairing',\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_BTC_HIGH_INDEX_CONFIRM: 'receive-btc-high-index-confirm',\n RECEIVE_PREEMPTION: 'receive-preemption',\n RECEIVE_TREZOR_THP_PAIRING: 'receive-trezor-thp-pairing',\n CANCEL: 'cancel',\n} as const;\n\nexport type DevicePermissionDeniedReason =\n | 'bluetoothTurnedOff'\n | 'permissionDenied'\n | (string & Record<never, never>);\n\nexport type DevicePermissionResponse = {\n granted: boolean;\n reason?: DevicePermissionDeniedReason;\n message?: string;\n};\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: DevicePermissionResponse;\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_BTC_HIGH_INDEX_CONFIRM;\n payload: { confirmed: boolean };\n }\n | {\n type: typeof UI_RESPONSE.RECEIVE_TREZOR_THP_PAIRING;\n payload: {\n selectedMethod?: number | string;\n tag?: string;\n };\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 * Pure FIFO job queue. Every enqueue chains onto the tail; jobs run one at\n * a time across all devices. The queue is intentionally passive — it does\n * NOT decide whether to interrupt or ask the user. Those are application-\n * layer concerns owned by the caller (e.g. a UI button handler that wants\n * to ask \"device is busy, interrupt current?\" before submitting). The\n * queue exposes inspection (`getActiveJob`) and explicit cancellation\n * (`cancelActive` / `cancelAll`) so callers can implement those policies\n * synchronously, without racing against in-flight enqueues.\n */\n\nexport interface JobOptions {\n label?: string;\n rejectIfBusy?: boolean;\n busyError?: Error;\n}\n\nexport interface ActiveJobInfo {\n deviceId: string;\n label?: string;\n startedAt: number;\n}\n\ninterface ActiveJob {\n deviceId: string;\n label?: string;\n abortController: AbortController;\n startedAt: number;\n}\n\nexport class DeviceJobQueue {\n private _tail: Promise<unknown> = Promise.resolve();\n\n private _active: ActiveJob | null = null;\n\n private readonly _jobs = new Map<object, { deviceId: string }>();\n\n /** Incremented on clear() so queued-but-not-yet-running jobs detect invalidation. */\n private _generation = 0;\n\n private readonly _generationCancelReasons = new Map<number, Error>();\n\n /**\n * Enqueue a job. Runs after every previously-enqueued job has settled.\n * `deviceId` is a label only — used by inspection / cancellation routing.\n */\n async enqueue<T>(\n deviceId: string,\n job: (signal: AbortSignal) => Promise<T>,\n options: JobOptions = {}\n ): Promise<T> {\n if (options.rejectIfBusy && this._jobs.size > 0) {\n throw options.busyError ?? new Error('Device is busy');\n }\n\n const ac = new AbortController();\n const gen = this._generation;\n const prev = this._tail;\n const jobToken = {};\n const activeJob: ActiveJob = {\n deviceId,\n label: options.label,\n abortController: ac,\n startedAt: Date.now(),\n };\n this._jobs.set(jobToken, { deviceId });\n\n const next = prev\n .catch(() => {})\n .then(async () => {\n if (this._generation !== gen) {\n throw (\n this._generationCancelReasons.get(gen) ?? new Error('Job cancelled: queue was cleared')\n );\n }\n this._active = activeJob;\n try {\n return await job(ac.signal);\n } finally {\n // Identity guard: a previous job's deferred finally must not\n // null out a successor's `_active`.\n if (this._active === activeJob) {\n this._active = null;\n }\n }\n })\n .finally(() => {\n this._jobs.delete(jobToken);\n });\n\n this._tail = next.catch(() => {});\n return next;\n }\n\n /** Cancel the active job. If `deviceId` is given, only cancels when it matches. */\n cancelActive(deviceId?: string): boolean {\n if (!this._active) return false;\n if (deviceId && this._active.deviceId !== deviceId) return false;\n this._active.abortController.abort(new Error('Manually cancelled'));\n return true;\n }\n\n /** Force cancel the active job. `reason` becomes signal.reason. */\n forceCancelActive(deviceId?: string, reason?: Error): boolean {\n if (!this._active) return false;\n if (deviceId && this._active.deviceId !== deviceId) return false;\n this._active.abortController.abort(reason ?? new Error('Force cancelled for recovery'));\n return true;\n }\n\n /** Cancel the active job (alias for callers that previously needed multi-device cancel). */\n cancelAllActive(reason?: Error): void {\n if (!this._active) return;\n this._active.abortController.abort(reason ?? new Error('Cancelled by cancelAllActive'));\n }\n\n /** Cancel the active job and invalidate queued jobs that have not started. */\n cancelActiveAndPending(deviceId?: string, reason?: Error): boolean {\n if (deviceId && this._active && this._active.deviceId !== deviceId) {\n return false;\n }\n this.clear(reason ?? new Error('Cancelled by cancelActiveAndPending'));\n return true;\n }\n\n /** Get info about the currently active job, or null if idle. */\n getActiveJob(deviceId?: string): ActiveJobInfo | null {\n if (!this._active) return null;\n if (deviceId && this._active.deviceId !== deviceId) return null;\n return {\n deviceId: this._active.deviceId,\n label: this._active.label,\n startedAt: this._active.startedAt,\n };\n }\n\n /** True if any job is currently running. */\n isBusy(): boolean {\n return this._jobs.size > 0;\n }\n\n clear(reason?: Error): void {\n const cancelledGeneration = this._generation;\n this._generation++;\n const cancelReason = reason ?? new Error('Job cancelled: queue was cleared');\n this._generationCancelReasons.set(cancelledGeneration, cancelReason);\n for (const generation of this._generationCancelReasons.keys()) {\n if (generation < this._generation - 10) {\n this._generationCancelReasons.delete(generation);\n }\n }\n if (this._active) {\n this._active.abortController.abort(cancelReason);\n }\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 /**\n * Physical transport this device was discovered on. Mirrors Trezor\n * Connect's `descriptor.apiType` — when several transports are fused behind\n * one connector (see `createCombinedConnector`), the merged device list\n * carries this so the host can tell a USB entry from a BLE one and route\n * `connect()` back to the owning transport. Single-transport connectors may\n * leave it undefined.\n */\n connectionType?: ConnectionType;\n /** Machine model id (e.g. \"nanoX\"). */\n model?: string;\n /** Human-readable model name (e.g. \"Ledger Nano X\"). */\n modelName?: string;\n /** BLE signal strength (BLE only). */\n rssi?: number | null;\n /** BLE connectable flag (BLE only). */\n isConnectable?: boolean | null;\n /** USB serial number (USB only). */\n serialNumber?: string;\n\n /** Device capabilities — available from scan time */\n capabilities?: DeviceCapabilities;\n\n /**\n * Vendor-specific raw blob from the transport descriptor (USB / BLE).\n * Populated by `descriptorToConnectorDevice` in each connector. Treat as\n * informational; promote any field consumed by the app layer onto the\n * typed surface above.\n */\n raw?: Record<string, unknown>;\n}\n\nexport interface ConnectorSession {\n sessionId: string;\n deviceInfo: DeviceInfo;\n}\n\nexport type ConnectorEventType =\n | 'device-connect'\n | 'device-disconnect'\n | 'device-trezor-thp-credentials-changed'\n | 'ui-request'\n | 'ui-event'\n | 'app-install-progress';\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 /** Adapter is actively searching for the device (no session yet) */\n Searching = 'searching',\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\n// All variants share the same payload shape so that emit sites where the\n// `type` is a broad `EConnectorInteraction` value (e.g. piped through\n// `collapseSignerInteraction`) still type-check. Searching has no session\n// yet so it carries an empty `sessionId`.\nexport type ConnectorUiEvent =\n | { type: EConnectorInteraction.Searching; payload: { sessionId: string } }\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 'device-trezor-thp-credentials-changed': {\n connectId: string;\n deviceId?: string;\n credentials: Record<string, unknown>[];\n };\n 'ui-request': { type: string; payload?: unknown };\n 'ui-event': ConnectorUiEvent;\n // OS-level Ledger app install progress. Emitted from inside the connector\n // so the callback ref never has to cross the IHardwareBridge boundary.\n // `progress` is a 0..1 fraction reported by DMK's InstallOrUpdateAppsDeviceAction.\n 'app-install-progress': { sessionId: string; appName: string; progress: number };\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 // Vendor-specific opt-in: warm-load persisted credentials before the first\n // session. Trezor uses this for THP `knownCredentials` (host-stored pairing\n // credentials replayed in `ThpHandshakeInitRequest` to skip the CodeEntry /\n // QrCode / NFC pairing UX on every connect). Vendors without persistent\n // credentials (Ledger, etc.) simply don't implement it.\n setKnownCredentials?(credentials: unknown[]): 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 * Warm-load vendor-specific persisted credentials. Currently only Trezor\n * uses this (THP `knownCredentials`); the bridge implementation can\n * dispatch on `vendor` and route to the right connector instance.\n */\n setKnownCredentials?(params: {\n vendor: VendorType;\n credentials: unknown[];\n }): Promise<void> | 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 setKnownCredentials: bridge.setKnownCredentials\n ? credentials => {\n void bridge.setKnownCredentials!({ vendor, credentials });\n }\n : undefined,\n };\n}\n\n/**\n * Fuse several single-transport IConnectors (e.g. WebUSB + BLE for one\n * vendor) into one IConnector whose device list is the union of all of them.\n *\n * This mirrors how Trezor Connect's `DeviceList` keeps one `TransportManager`\n * per `apiType` running concurrently and merges their devices into a single\n * list: there is no \"switch\" between transports — both are always live, and\n * each discovered device carries its `connectionType` so the host knows which\n * channel it came in on. `connect()` routes back to the transport that owns\n * the chosen device; later calls route by `sessionId`.\n *\n * Notes / current limitations:\n * - `searchDevices()` fans out concurrently; a transport that throws while\n * scanning is treated as \"no devices\" so a dead/absent channel never sinks\n * the others.\n * - USB entries sort ahead of BLE ones (Trezor's `getPrioritizedDevices`).\n * - The same physical device reachable on two transports surfaces as two\n * entries with different `connectId`s — we do NOT dedup, so the host can\n * present (or pick) a channel explicitly.\n * - `uiResponse()` carries no sessionId, so it is broadcast to every child;\n * a child with no matching pending request ignores it.\n */\nexport function createCombinedConnector(connectors: IConnector[]): IConnector {\n if (connectors.length === 0) {\n throw new Error('createCombinedConnector: at least one connector is required');\n }\n\n // connectId -> the child connector that discovered it (set on searchDevices).\n const deviceOwner = new Map<string, IConnector>();\n // sessionId -> the child connector that owns the live session.\n const sessionOwner = new Map<string, IConnector>();\n // userHandler -> the per-child forwarders we attached, so off() can detach.\n type UserHandler = (data: ConnectorEventMap[ConnectorEventType]) => void;\n const forwarders = new Map<\n ConnectorEventType,\n Map<UserHandler, Array<{ child: IConnector; handler: UserHandler }>>\n >();\n\n // BLE ranks after USB — matches Trezor's getPrioritizedDevices().\n const rank = (device: ConnectorDevice): number =>\n device.connectionType === 'ble' ? 1 : 0;\n\n // Shared THP pairing credentials across all child transports. A credential is\n // keyed by the device's static public key (transport-agnostic, see\n // `findKnownPairingCredentials`), so a credential minted while pairing over\n // one transport (e.g. USB) must reach the sibling transports (e.g. BLE) or\n // they re-pair instead of autoconnecting. Each child keeps its OWN\n // knownCredentials array, so we maintain the union here and re-broadcast it to\n // every child whenever any child mints a fresh one.\n const sharedCredentials: Array<Record<string, unknown>> = [];\n const credentialKey = (c: Record<string, unknown>): string =>\n (c.credential as string) ?? JSON.stringify(c);\n const mergeShared = (\n incoming: ReadonlyArray<Record<string, unknown>>,\n ): boolean => {\n let changed = false;\n for (const cred of incoming) {\n const key = credentialKey(cred);\n if (!sharedCredentials.some(e => credentialKey(e) === key)) {\n sharedCredentials.push(cred);\n changed = true;\n }\n }\n return changed;\n };\n const broadcastCredentials = (): void => {\n for (const child of connectors) child.setKnownCredentials?.(sharedCredentials);\n };\n\n // Internal subscription (independent of user on()/off()): when any child mints\n // fresh pairing credentials, fold them into the shared union and push the\n // union down to every child so the next handshake on ANY transport\n // autoconnects rather than re-pairing.\n for (const child of connectors) {\n child.on('device-trezor-thp-credentials-changed', data => {\n if (mergeShared(data.credentials)) broadcastCredentials();\n });\n }\n\n const searchDevices = async (): Promise<ConnectorDevice[]> => {\n const perConnector = await Promise.all(\n connectors.map(async child => {\n try {\n const devices = await child.searchDevices();\n return devices.map(device => ({\n ...device,\n connectionType: device.connectionType ?? child.connectionType,\n }));\n } catch {\n // A transport that can't scan (powered off, unauthorized, absent)\n // must not fail the whole fused search.\n return [] as ConnectorDevice[];\n }\n }),\n );\n\n deviceOwner.clear();\n const merged: ConnectorDevice[] = [];\n perConnector.forEach((devices, index) => {\n for (const device of devices) {\n deviceOwner.set(device.connectId, connectors[index]);\n merged.push(device);\n }\n });\n return merged.sort((a, b) => rank(a) - rank(b));\n };\n\n const resolveOwner = async (deviceId?: string): Promise<{ owner: IConnector; deviceId?: string }> => {\n if (deviceId && deviceOwner.has(deviceId)) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return { owner: deviceOwner.get(deviceId)!, deviceId };\n }\n const devices = await searchDevices();\n if (deviceId) {\n const owner = deviceOwner.get(deviceId);\n if (!owner) throw new Error(`Combined connector: device not found: ${deviceId}`);\n return { owner, deviceId };\n }\n const first = devices[0];\n if (!first) throw new Error('Combined connector: no devices found');\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return { owner: deviceOwner.get(first.connectId)!, deviceId: first.connectId };\n };\n\n return {\n // Nominal value only — the per-device `connectionType` is authoritative\n // for a fused connector.\n connectionType: connectors[0].connectionType,\n\n searchDevices,\n\n connect: async deviceId => {\n const { owner, deviceId: resolved } = await resolveOwner(deviceId);\n const session = await owner.connect(resolved);\n sessionOwner.set(session.sessionId, owner);\n return session;\n },\n\n disconnect: async sessionId => {\n const owner = sessionOwner.get(sessionId);\n if (!owner) return;\n await owner.disconnect(sessionId);\n sessionOwner.delete(sessionId);\n },\n\n call: async (sessionId, method, params) => {\n const owner = sessionOwner.get(sessionId);\n if (!owner) throw new Error(`Combined connector: session not found: ${sessionId}`);\n return owner.call(sessionId, method, params);\n },\n\n cancel: async sessionId => {\n const owner = sessionOwner.get(sessionId);\n if (!owner) return;\n await owner.cancel(sessionId);\n },\n\n uiResponse: response => {\n // No sessionId on the response — broadcast; children without a matching\n // pending request ignore it.\n for (const child of connectors) child.uiResponse(response);\n },\n\n on: (event, handler) => {\n const attached = connectors.map(child => {\n const forward: UserHandler = data =>\n (handler as UserHandler)(data);\n child.on(event, forward as Parameters<IConnector['on']>[1]);\n return { child, handler: forward };\n });\n let inner = forwarders.get(event);\n if (!inner) {\n inner = new Map();\n forwarders.set(event, inner);\n }\n inner.set(handler as UserHandler, attached);\n },\n\n off: (event, handler) => {\n const inner = forwarders.get(event);\n const attached = inner?.get(handler as UserHandler);\n if (!attached || !inner) return;\n for (const { child, handler: forward } of attached) {\n child.off(event, forward as Parameters<IConnector['off']>[1]);\n }\n inner.delete(handler as UserHandler);\n if (inner.size === 0) forwarders.delete(event);\n },\n\n reset: () => {\n for (const child of connectors) child.reset();\n deviceOwner.clear();\n sessionOwner.clear();\n forwarders.clear();\n },\n\n setKnownCredentials: connectors.some(c => c.setKnownCredentials)\n ? credentials => {\n // Seed the shared union from the host (warm-load) and fan out to all\n // children so every transport starts from the same credential set.\n sharedCredentials.length = 0;\n mergeShared((credentials ?? []) as Array<Record<string, unknown>>);\n broadcastCredentials();\n }\n : undefined,\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 /** Number of listeners registered for `event`. 0 if none. */\n listenerCount(event: string): number {\n return this._listeners.get(event)?.size ?? 0;\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_BTC_HIGH_INDEX_CONFIRM]: UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM,\n [UI_RESPONSE.RECEIVE_PREEMPTION]: UI_REQUEST.REQUEST_PREEMPTION,\n [UI_RESPONSE.RECEIVE_TREZOR_THP_PAIRING]: UI_REQUEST.REQUEST_TREZOR_THP_PAIRING,\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 supersedes (rejects) the prior pending entry. With the\n * job queue running globally serially, cross-type collisions don't occur in\n * normal flow — same-type preemption is a defensive measure for callers\n * that fire the same request twice without waiting on the first.\n *\n * Unknown response types are dropped silently so the public `uiResponse`\n * 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 if (requestType) return this.pending.has(requestType);\n return this.pending.size > 0;\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.DeviceOneDeviceOnly:\n return `${originalMessage}. Disconnect the extra 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.AppNotInstalled:\n return `${originalMessage}. The required app is not installed on the device.`;\n case HardwareErrorCode.DeviceOutOfMemory:\n return `${originalMessage}. Not enough free space on the device. Please uninstall some apps and try again.`;\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"]}