@bytezhang/hardware-ledger-connector-webhid 0.0.4 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -37,6 +37,11 @@ module.exports = __toCommonJS(index_exports);
37
37
 
38
38
  // src/LedgerWebHidConnector.ts
39
39
  var import_ledger_adapter = require("@bytezhang/ledger-adapter");
40
+ function extractBleHexId(name) {
41
+ if (!name) return void 0;
42
+ const match = name.match(/\b([0-9A-Fa-f]{4})$/);
43
+ return match ? match[1].toUpperCase() : void 0;
44
+ }
40
45
  function normalizePath(path) {
41
46
  return path.startsWith("m/") ? path.slice(2) : path;
42
47
  }
@@ -70,20 +75,16 @@ var LedgerWebHidConnector = class {
70
75
  }
71
76
  descriptors = await dm.enumerate();
72
77
  }
73
- console.log("[LedgerWebHidConnector] descriptors:", JSON.stringify(descriptors));
74
- const result = descriptors.map((d) => ({
75
- // d.path is a temporary DMK UUID (regenerated on each discovery).
76
- // Used internally for routing. NOT a persistent device ID.
77
- connectId: d.path,
78
- deviceId: d.path,
79
- name: d.type || "Ledger",
80
- model: d.type,
81
- capabilities: {
82
- // WebHID: DMK generates ephemeral UUIDs each session
83
- persistentDeviceIdentity: false
84
- }
85
- }));
86
- console.log("[LedgerWebHidConnector] searchDevices result:", JSON.stringify(result));
78
+ const result = descriptors.map((d) => {
79
+ const isBle = d.transport === "BLE";
80
+ const bleHexId = isBle ? extractBleHexId(d.name) : void 0;
81
+ return {
82
+ connectId: bleHexId || d.path,
83
+ deviceId: d.path,
84
+ name: d.name || d.type || "Ledger",
85
+ model: d.type
86
+ };
87
+ });
87
88
  return result;
88
89
  }
89
90
  // ---------------------------------------------------------------------------
@@ -185,6 +186,18 @@ var LedgerWebHidConnector = class {
185
186
  return this._btcGetAddress(sessionId, params);
186
187
  case "btcGetPublicKey":
187
188
  return this._btcGetPublicKey(sessionId, params);
189
+ case "btcSignTransaction":
190
+ return this._btcSignTransaction(sessionId, params);
191
+ case "btcSignMessage":
192
+ return this._btcSignMessage(sessionId, params);
193
+ case "btcGetMasterFingerprint":
194
+ return this._btcGetMasterFingerprint(sessionId, params);
195
+ case "solGetAddress":
196
+ return this._solGetAddress(sessionId, params);
197
+ case "solSignTransaction":
198
+ return this._solSignTransaction(sessionId, params);
199
+ case "solSignMessage":
200
+ return this._solSignMessage(sessionId, params);
188
201
  default:
189
202
  throw new Error(`LedgerWebHidConnector: unknown method "${method}"`);
190
203
  }
@@ -317,6 +330,47 @@ var LedgerWebHidConnector = class {
317
330
  throw this._wrapError(err);
318
331
  }
319
332
  }
333
+ async _btcSignTransaction(_sessionId, _params) {
334
+ throw new Error("LedgerWebHidConnector: btcSignTransaction is not yet implemented");
335
+ }
336
+ async _btcSignMessage(_sessionId, _params) {
337
+ throw new Error("LedgerWebHidConnector: btcSignMessage is not yet implemented");
338
+ }
339
+ async _btcGetMasterFingerprint(sessionId, params) {
340
+ const btcSigner = await this._createBtcSigner(sessionId);
341
+ try {
342
+ const fingerprint = await btcSigner.getMasterFingerprint({
343
+ skipOpenApp: params?.skipOpenApp
344
+ });
345
+ const hex = Array.from(fingerprint).map((b) => b.toString(16).padStart(2, "0")).join("");
346
+ return { masterFingerprint: hex };
347
+ } catch (err) {
348
+ this._invalidateSession(sessionId);
349
+ throw this._wrapError(err);
350
+ }
351
+ }
352
+ // ---------------------------------------------------------------------------
353
+ // Private — SOL methods
354
+ // ---------------------------------------------------------------------------
355
+ async _solGetAddress(sessionId, params) {
356
+ const solSigner = await this._createSolSigner(sessionId);
357
+ const path = normalizePath(params.path);
358
+ try {
359
+ const publicKey = await solSigner.getAddress(path, {
360
+ checkOnDevice: params.showOnDevice ?? false
361
+ });
362
+ return { address: publicKey, path: params.path };
363
+ } catch (err) {
364
+ this._invalidateSession(sessionId);
365
+ throw this._wrapError(err);
366
+ }
367
+ }
368
+ async _solSignTransaction(_sessionId, _params) {
369
+ throw new Error("LedgerWebHidConnector: solSignTransaction is not yet implemented");
370
+ }
371
+ async _solSignMessage(_sessionId, _params) {
372
+ throw new Error("LedgerWebHidConnector: solSignMessage is not yet implemented");
373
+ }
320
374
  // ---------------------------------------------------------------------------
321
375
  // Private — DMK / Manager lifecycle
322
376
  // ---------------------------------------------------------------------------
@@ -370,6 +424,15 @@ var LedgerWebHidConnector = class {
370
424
  }).build();
371
425
  return new import_ledger_adapter.SignerBtc(sdkSigner);
372
426
  }
427
+ async _createSolSigner(sessionId) {
428
+ const dmk = await this._getOrCreateDmk();
429
+ const { SignerSolanaBuilder } = await import("@ledgerhq/device-signer-kit-solana");
430
+ const sdkSigner = new SignerSolanaBuilder({
431
+ dmk,
432
+ sessionId
433
+ }).build();
434
+ return new import_ledger_adapter.SignerSol(sdkSigner);
435
+ }
373
436
  _invalidateSession(sessionId) {
374
437
  this._signerManager?.invalidate(sessionId);
375
438
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/LedgerWebHidConnector.ts"],"sourcesContent":["import type { IConnector } from '@bytezhang/hardware-wallet-core';\nimport type { IDmk } from '@bytezhang/ledger-adapter';\n\nimport {\n LedgerWebHidConnector,\n} from './LedgerWebHidConnector';\nimport type { LedgerWebHidConnectorOptions } from './LedgerWebHidConnector';\n\nexport { LedgerWebHidConnector };\nexport type { LedgerWebHidConnectorOptions };\n\n/**\n * Create a LedgerWebHidConnector.\n *\n * @param dmk - Optional pre-built DMK instance. If omitted, the connector\n * will lazily create one using `@ledgerhq/device-management-kit`\n * and `@ledgerhq/device-transport-kit-web-hid`.\n */\nexport function createLedgerWebHidConnector(dmk?: IDmk): IConnector {\n return new LedgerWebHidConnector({ dmk });\n}\n","import type {\n IConnector,\n ConnectorDevice,\n ConnectorSession,\n ConnectorEventType,\n ConnectorEventMap,\n} from '@bytezhang/hardware-wallet-core';\nimport type { IDmk, SignerEvmSignature } from '@bytezhang/ledger-adapter';\nimport {\n LedgerDeviceManager,\n SignerManager,\n SignerBtc,\n mapLedgerError,\n} from '@bytezhang/ledger-adapter';\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\ntype EventHandler<K extends ConnectorEventType> = (\n data: ConnectorEventMap[K],\n) => void;\n\n/** Parameters for evmGetAddress */\ninterface EvmGetAddressCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for evmSignTransaction */\ninterface EvmSignTransactionCallParams {\n path: string;\n /** RLP-serialized transaction hex (0x-prefixed or plain) */\n serializedTx: string;\n}\n\n/** Parameters for evmSignMessage */\ninterface EvmSignMessageCallParams {\n path: string;\n message: string;\n}\n\n/** Parameters for evmSignTypedData */\ninterface EvmSignTypedDataCallParams {\n path: string;\n data: unknown;\n}\n\n/** Parameters for btcGetAddress */\ninterface BtcGetAddressCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for btcGetPublicKey */\ninterface BtcGetPublicKeyCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Strip the \"m/\" prefix from BIP-44 derivation paths. */\nfunction normalizePath(path: string): string {\n return path.startsWith('m/') ? path.slice(2) : path;\n}\n\n/** Remove `0x` prefix from a hex string if present. */\nfunction stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Ensure a hex string is `0x`-prefixed and zero-padded to 64 hex chars (32 bytes). */\nfunction padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n// ---------------------------------------------------------------------------\n// LedgerWebHidConnector\n// ---------------------------------------------------------------------------\n\nexport interface LedgerWebHidConnectorOptions {\n /**\n * Pre-built DMK instance. If not provided, a DMK will be created\n * lazily on first use via `@ledgerhq/device-management-kit` and\n * `@ledgerhq/device-transport-kit-web-hid`.\n */\n dmk?: IDmk;\n}\n\n/**\n * IConnector implementation for Ledger hardware wallets via WebHID.\n *\n * Wraps the Ledger DMK (Device Management Kit) and signer kits into\n * the unified IConnector interface used by the adapter layer.\n *\n * Design:\n * - Constructor accepts an optional pre-built DMK instance (or creates one lazily).\n * - searchDevices() uses DMK's listenToAvailableDevices() observable.\n * - connect() calls dmk.connect({ device }), returns a ConnectorSession.\n * - call() dispatches to chain-specific signer methods (EVM, BTC).\n * - Internally uses LedgerDeviceManager for session tracking and\n * SignerManager for per-session signer caching.\n */\nexport class LedgerWebHidConnector implements IConnector {\n private _deviceManager: LedgerDeviceManager | null = null;\n private _signerManager: SignerManager | null = null;\n private _dmk: IDmk | null = null;\n\n private readonly _eventHandlers = new Map<\n ConnectorEventType,\n Set<EventHandler<ConnectorEventType>>\n >();\n\n private readonly _providedDmk: IDmk | undefined;\n\n constructor(options?: LedgerWebHidConnectorOptions) {\n this._providedDmk = options?.dmk;\n if (this._providedDmk) {\n this._initManagers(this._providedDmk);\n }\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Device discovery\n // ---------------------------------------------------------------------------\n\n async searchDevices(): Promise<ConnectorDevice[]> {\n const dm = await this._getDeviceManager();\n\n let descriptors = await dm.enumerate();\n\n // If no devices found, trigger browser permission dialog via startDiscovering\n if (descriptors.length === 0) {\n try {\n await dm.requestDevice();\n } catch {\n // User may cancel the permission dialog — that's OK\n }\n descriptors = await dm.enumerate();\n }\n\n console.log('[LedgerWebHidConnector] descriptors:', JSON.stringify(descriptors));\n const result: ConnectorDevice[] = descriptors.map((d) => ({\n // d.path is a temporary DMK UUID (regenerated on each discovery).\n // Used internally for routing. NOT a persistent device ID.\n connectId: d.path,\n deviceId: d.path,\n name: d.type || 'Ledger',\n model: d.type,\n capabilities: {\n // WebHID: DMK generates ephemeral UUIDs each session\n persistentDeviceIdentity: false,\n },\n }));\n console.log('[LedgerWebHidConnector] searchDevices result:', JSON.stringify(result));\n return result;\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Connection\n // ---------------------------------------------------------------------------\n\n async connect(deviceId?: string): Promise<ConnectorSession> {\n const dm = await this._getDeviceManager();\n\n // Ensure we have fresh device list\n await this.searchDevices();\n\n let resolvedDeviceId = deviceId;\n\n // Empty or missing deviceId — use first available device's DMK path\n if (!resolvedDeviceId) {\n // Use the first available device\n const descriptors = await dm.enumerate();\n if (descriptors.length === 0) {\n throw new Error(\n 'No Ledger device found. Make sure the device is connected via USB and unlocked.',\n );\n }\n resolvedDeviceId = descriptors[0].path;\n }\n\n try {\n const sessionId = await dm.connect(resolvedDeviceId);\n\n const session: ConnectorSession = {\n sessionId,\n deviceInfo: {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: 'unknown',\n deviceId: resolvedDeviceId,\n connectId: resolvedDeviceId,\n connectionType: 'usb',\n capabilities: {\n persistentDeviceIdentity: false,\n },\n },\n };\n\n this._emit('device-connect', {\n device: {\n connectId: resolvedDeviceId,\n deviceId: resolvedDeviceId,\n name: 'Ledger',\n },\n });\n\n return session;\n } catch (err) {\n // Retry once: reset and re-discover\n this._resetManagers();\n const dm2 = await this._getDeviceManager();\n await this.searchDevices();\n\n const descriptors = await dm2.enumerate();\n const retryId = deviceId\n ? descriptors.find((d) => d.path === deviceId)?.path\n : descriptors[0]?.path;\n\n if (!retryId) {\n throw new Error(\n 'No Ledger device found after retry. Make sure the device is connected via USB and unlocked.',\n );\n }\n\n const sessionId = await dm2.connect(retryId);\n\n const session: ConnectorSession = {\n sessionId,\n deviceInfo: {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: 'unknown',\n deviceId: retryId,\n connectId: retryId,\n connectionType: 'usb',\n },\n };\n\n this._emit('device-connect', {\n device: {\n connectId: retryId,\n deviceId: retryId,\n name: 'Ledger',\n },\n });\n\n return session;\n }\n }\n\n async disconnect(sessionId: string): Promise<void> {\n if (!this._deviceManager) return;\n\n const deviceId = this._deviceManager.getDeviceId(sessionId);\n this._signerManager?.invalidate(sessionId);\n await this._deviceManager.disconnect(sessionId);\n\n if (deviceId) {\n this._emit('device-disconnect', { connectId: deviceId });\n }\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Method dispatch\n // ---------------------------------------------------------------------------\n\n async call(\n sessionId: string,\n method: string,\n params: unknown,\n ): Promise<unknown> {\n switch (method) {\n case 'evmGetAddress':\n return this._evmGetAddress(sessionId, params as EvmGetAddressCallParams);\n case 'evmSignTransaction':\n return this._evmSignTransaction(sessionId, params as EvmSignTransactionCallParams);\n case 'evmSignMessage':\n return this._evmSignMessage(sessionId, params as EvmSignMessageCallParams);\n case 'evmSignTypedData':\n return this._evmSignTypedData(sessionId, params as EvmSignTypedDataCallParams);\n case 'btcGetAddress':\n return this._btcGetAddress(sessionId, params as BtcGetAddressCallParams);\n case 'btcGetPublicKey':\n return this._btcGetPublicKey(sessionId, params as BtcGetPublicKeyCallParams);\n default:\n throw new Error(`LedgerWebHidConnector: unknown method \"${method}\"`);\n }\n }\n\n async cancel(_sessionId: string): Promise<void> {\n // Ledger DMK doesn't expose a generic cancel mechanism\n }\n\n uiResponse(_response: { type: string; payload: unknown }): void {\n // Ledger does not use interactive UI responses (PIN/passphrase)\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Events\n // ---------------------------------------------------------------------------\n\n on<K extends ConnectorEventType>(\n event: K,\n handler: (data: ConnectorEventMap[K]) => void,\n ): void {\n if (!this._eventHandlers.has(event)) {\n this._eventHandlers.set(event, new Set());\n }\n this._eventHandlers\n .get(event)!\n .add(handler as EventHandler<ConnectorEventType>);\n }\n\n off<K extends ConnectorEventType>(\n event: K,\n handler: (data: ConnectorEventMap[K]) => void,\n ): void {\n this._eventHandlers\n .get(event)\n ?.delete(handler as EventHandler<ConnectorEventType>);\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Reset\n // ---------------------------------------------------------------------------\n\n reset(): void {\n this._resetManagers();\n }\n\n // ---------------------------------------------------------------------------\n // Private — EVM methods\n // ---------------------------------------------------------------------------\n\n private async _evmGetAddress(\n sessionId: string,\n params: EvmGetAddressCallParams,\n ): Promise<{ address: string; publicKey?: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result = await signer.getAddress(path, {\n checkOnDevice: params.showOnDevice ?? false,\n });\n return { address: result.address, publicKey: result.publicKey };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignTransaction(\n sessionId: string,\n params: EvmSignTransactionCallParams,\n ): Promise<{ v: string; r: string; s: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signTransaction(\n path,\n params.serializedTx,\n );\n return {\n v: `0x${result.v.toString(16)}`,\n r: padHex64(result.r),\n s: padHex64(result.s),\n };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignMessage(\n sessionId: string,\n params: EvmSignMessageCallParams,\n ): Promise<{ signature: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signMessage(\n path,\n params.message,\n );\n const rHex = stripHex(result.r).padStart(64, '0');\n const sHex = stripHex(result.s).padStart(64, '0');\n const vHex = result.v.toString(16).padStart(2, '0');\n return { signature: `0x${rHex}${sHex}${vHex}` };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignTypedData(\n sessionId: string,\n params: EvmSignTypedDataCallParams,\n ): Promise<{ signature: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signTypedData(\n path,\n params.data,\n );\n const rHex = stripHex(result.r).padStart(64, '0');\n const sHex = stripHex(result.s).padStart(64, '0');\n const vHex = result.v.toString(16).padStart(2, '0');\n return { signature: `0x${rHex}${sHex}${vHex}` };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — BTC methods\n // ---------------------------------------------------------------------------\n\n private async _btcGetAddress(\n sessionId: string,\n params: BtcGetAddressCallParams,\n ): Promise<{ address: string; path: string }> {\n const btcSigner = await this._createBtcSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const { DefaultWallet, DefaultDescriptorTemplate } = await import(\n '@ledgerhq/device-signer-kit-bitcoin'\n );\n const purpose = path.split('/')[0]?.replace(\"'\", '');\n let template = DefaultDescriptorTemplate.NATIVE_SEGWIT;\n if (purpose === '44') template = DefaultDescriptorTemplate.LEGACY;\n else if (purpose === '49')\n template = DefaultDescriptorTemplate.NESTED_SEGWIT;\n else if (purpose === '86') template = DefaultDescriptorTemplate.TAPROOT;\n const wallet = new DefaultWallet(path, template);\n\n const result = await btcSigner.getWalletAddress(wallet, 0, {\n checkOnDevice: params.showOnDevice ?? false,\n change: false,\n });\n return { address: result.address, path: params.path };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _btcGetPublicKey(\n sessionId: string,\n params: BtcGetPublicKeyCallParams,\n ): Promise<{ xpub: string; path: string }> {\n const btcSigner = await this._createBtcSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const xpub = await btcSigner.getExtendedPublicKey(path, {\n checkOnDevice: params.showOnDevice ?? false,\n });\n return { xpub, path: params.path };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — DMK / Manager lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Lazily create or return the DMK instance.\n * If a DMK was provided via constructor, it is used directly.\n * Otherwise, one is created via dynamic import of the Ledger SDK.\n */\n private async _getOrCreateDmk(): Promise<IDmk> {\n if (this._dmk) return this._dmk;\n\n if (this._providedDmk) {\n this._dmk = this._providedDmk;\n return this._dmk;\n }\n\n const { DeviceManagementKitBuilder } = await import(\n '@ledgerhq/device-management-kit'\n );\n const { webHidTransportFactory } = await import(\n '@ledgerhq/device-transport-kit-web-hid'\n );\n\n this._dmk = new DeviceManagementKitBuilder()\n .addTransport(webHidTransportFactory)\n .build() as unknown as IDmk;\n\n return this._dmk;\n }\n\n private _initManagers(dmk: IDmk): void {\n this._dmk = dmk;\n this._deviceManager = new LedgerDeviceManager(dmk);\n this._signerManager = new SignerManager(dmk);\n }\n\n private async _getDeviceManager(): Promise<LedgerDeviceManager> {\n if (this._deviceManager) return this._deviceManager;\n\n const dmk = await this._getOrCreateDmk();\n this._initManagers(dmk);\n return this._deviceManager!;\n }\n\n private async _getEthSigner(sessionId: string) {\n if (!this._signerManager) {\n const dmk = await this._getOrCreateDmk();\n this._initManagers(dmk);\n }\n const signer = await this._signerManager!.getOrCreate(sessionId);\n\n // Wire up interaction events (open-app, unlock, verify-address, sign, etc.)\n signer.onInteraction = (interaction: string) => {\n this._emit('ui-event', {\n type: interaction,\n payload: { sessionId },\n });\n };\n\n return signer;\n }\n\n private async _createBtcSigner(sessionId: string): Promise<SignerBtc> {\n const dmk = await this._getOrCreateDmk();\n const { SignerBtcBuilder } = await import(\n '@ledgerhq/device-signer-kit-bitcoin'\n );\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sdkSigner = new SignerBtcBuilder({\n dmk: dmk as any,\n sessionId,\n }).build();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new SignerBtc(sdkSigner as any);\n }\n\n private _invalidateSession(sessionId: string): void {\n this._signerManager?.invalidate(sessionId);\n }\n\n private _resetManagers(): void {\n this._signerManager?.clearAll();\n this._deviceManager?.dispose();\n this._deviceManager = null;\n this._signerManager = null;\n this._dmk = null;\n }\n\n // ---------------------------------------------------------------------------\n // Private — Events\n // ---------------------------------------------------------------------------\n\n private _emit<K extends ConnectorEventType>(\n event: K,\n data: ConnectorEventMap[K],\n ): void {\n const handlers = this._eventHandlers.get(event);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(data);\n } catch {\n // Don't let listener errors break the connector\n }\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — Error handling\n // ---------------------------------------------------------------------------\n\n private _wrapError(err: unknown): Error {\n const mapped = mapLedgerError(err);\n const error = new Error(mapped.message);\n (error as any).code = mapped.code;\n return error;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQA,4BAKO;AAoDP,SAAS,cAAc,MAAsB;AAC3C,SAAO,KAAK,WAAW,IAAI,IAAI,KAAK,MAAM,CAAC,IAAI;AACjD;AAGA,SAAS,SAAS,KAAqB;AACrC,SAAO,IAAI,WAAW,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI;AAC/C;AAGA,SAAS,SAAS,KAAqB;AACrC,SAAO,KAAK,SAAS,GAAG,EAAE,SAAS,IAAI,GAAG,CAAC;AAC7C;AA6BO,IAAM,wBAAN,MAAkD;AAAA,EAYvD,YAAY,SAAwC;AAXpD,SAAQ,iBAA6C;AACrD,SAAQ,iBAAuC;AAC/C,SAAQ,OAAoB;AAE5B,SAAiB,iBAAiB,oBAAI,IAGpC;AAKA,SAAK,eAAe,SAAS;AAC7B,QAAI,KAAK,cAAc;AACrB,WAAK,cAAc,KAAK,YAAY;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAA4C;AAChD,UAAM,KAAK,MAAM,KAAK,kBAAkB;AAExC,QAAI,cAAc,MAAM,GAAG,UAAU;AAGrC,QAAI,YAAY,WAAW,GAAG;AAC5B,UAAI;AACF,cAAM,GAAG,cAAc;AAAA,MACzB,QAAQ;AAAA,MAER;AACA,oBAAc,MAAM,GAAG,UAAU;AAAA,IACnC;AAEA,YAAQ,IAAI,wCAAwC,KAAK,UAAU,WAAW,CAAC;AAC/E,UAAM,SAA4B,YAAY,IAAI,CAAC,OAAO;AAAA;AAAA;AAAA,MAGxD,WAAW,EAAE;AAAA,MACb,UAAU,EAAE;AAAA,MACZ,MAAM,EAAE,QAAQ;AAAA,MAChB,OAAO,EAAE;AAAA,MACT,cAAc;AAAA;AAAA,QAEZ,0BAA0B;AAAA,MAC5B;AAAA,IACF,EAAE;AACF,YAAQ,IAAI,iDAAiD,KAAK,UAAU,MAAM,CAAC;AACnF,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ,UAA8C;AAC1D,UAAM,KAAK,MAAM,KAAK,kBAAkB;AAGxC,UAAM,KAAK,cAAc;AAEzB,QAAI,mBAAmB;AAGvB,QAAI,CAAC,kBAAkB;AAErB,YAAM,cAAc,MAAM,GAAG,UAAU;AACvC,UAAI,YAAY,WAAW,GAAG;AAC5B,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,yBAAmB,YAAY,CAAC,EAAE;AAAA,IACpC;AAEA,QAAI;AACF,YAAM,YAAY,MAAM,GAAG,QAAQ,gBAAgB;AAEnD,YAAM,UAA4B;AAAA,QAChC;AAAA,QACA,YAAY;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,iBAAiB;AAAA,UACjB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,gBAAgB;AAAA,UAChB,cAAc;AAAA,YACZ,0BAA0B;AAAA,UAC5B;AAAA,QACF;AAAA,MACF;AAEA,WAAK,MAAM,kBAAkB;AAAA,QAC3B,QAAQ;AAAA,UACN,WAAW;AAAA,UACX,UAAU;AAAA,UACV,MAAM;AAAA,QACR;AAAA,MACF,CAAC;AAED,aAAO;AAAA,IACT,SAAS,KAAK;AAEZ,WAAK,eAAe;AACpB,YAAM,MAAM,MAAM,KAAK,kBAAkB;AACzC,YAAM,KAAK,cAAc;AAEzB,YAAM,cAAc,MAAM,IAAI,UAAU;AACxC,YAAM,UAAU,WACZ,YAAY,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,GAAG,OAC9C,YAAY,CAAC,GAAG;AAEpB,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAEA,YAAM,YAAY,MAAM,IAAI,QAAQ,OAAO;AAE3C,YAAM,UAA4B;AAAA,QAChC;AAAA,QACA,YAAY;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,iBAAiB;AAAA,UACjB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,gBAAgB;AAAA,QAClB;AAAA,MACF;AAEA,WAAK,MAAM,kBAAkB;AAAA,QAC3B,QAAQ;AAAA,UACN,WAAW;AAAA,UACX,UAAU;AAAA,UACV,MAAM;AAAA,QACR;AAAA,MACF,CAAC;AAED,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,WAAkC;AACjD,QAAI,CAAC,KAAK,eAAgB;AAE1B,UAAM,WAAW,KAAK,eAAe,YAAY,SAAS;AAC1D,SAAK,gBAAgB,WAAW,SAAS;AACzC,UAAM,KAAK,eAAe,WAAW,SAAS;AAE9C,QAAI,UAAU;AACZ,WAAK,MAAM,qBAAqB,EAAE,WAAW,SAAS,CAAC;AAAA,IACzD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,KACJ,WACA,QACA,QACkB;AAClB,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,eAAO,KAAK,eAAe,WAAW,MAAiC;AAAA,MACzE,KAAK;AACH,eAAO,KAAK,oBAAoB,WAAW,MAAsC;AAAA,MACnF,KAAK;AACH,eAAO,KAAK,gBAAgB,WAAW,MAAkC;AAAA,MAC3E,KAAK;AACH,eAAO,KAAK,kBAAkB,WAAW,MAAoC;AAAA,MAC/E,KAAK;AACH,eAAO,KAAK,eAAe,WAAW,MAAiC;AAAA,MACzE,KAAK;AACH,eAAO,KAAK,iBAAiB,WAAW,MAAmC;AAAA,MAC7E;AACE,cAAM,IAAI,MAAM,0CAA0C,MAAM,GAAG;AAAA,IACvE;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,YAAmC;AAAA,EAEhD;AAAA,EAEA,WAAW,WAAqD;AAAA,EAEhE;AAAA;AAAA;AAAA;AAAA,EAMA,GACE,OACA,SACM;AACN,QAAI,CAAC,KAAK,eAAe,IAAI,KAAK,GAAG;AACnC,WAAK,eAAe,IAAI,OAAO,oBAAI,IAAI,CAAC;AAAA,IAC1C;AACA,SAAK,eACF,IAAI,KAAK,EACT,IAAI,OAA2C;AAAA,EACpD;AAAA,EAEA,IACE,OACA,SACM;AACN,SAAK,eACF,IAAI,KAAK,GACR,OAAO,OAA2C;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAMA,QAAc;AACZ,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,eACZ,WACA,QACkD;AAClD,UAAM,SAAS,MAAM,KAAK,cAAc,SAAS;AACjD,UAAM,OAAO,cAAc,OAAO,IAAI;AAEtC,QAAI;AACF,YAAM,SAAS,MAAM,OAAO,WAAW,MAAM;AAAA,QAC3C,eAAe,OAAO,gBAAgB;AAAA,MACxC,CAAC;AACD,aAAO,EAAE,SAAS,OAAO,SAAS,WAAW,OAAO,UAAU;AAAA,IAChE,SAAS,KAAK;AACZ,WAAK,mBAAmB,SAAS;AACjC,YAAM,KAAK,WAAW,GAAG;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,MAAc,oBACZ,WACA,QAC8C;AAC9C,UAAM,SAAS,MAAM,KAAK,cAAc,SAAS;AACjD,UAAM,OAAO,cAAc,OAAO,IAAI;AAEtC,QAAI;AACF,YAAM,SAA6B,MAAM,OAAO;AAAA,QAC9C;AAAA,QACA,OAAO;AAAA,MACT;AACA,aAAO;AAAA,QACL,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,CAAC;AAAA,QAC7B,GAAG,SAAS,OAAO,CAAC;AAAA,QACpB,GAAG,SAAS,OAAO,CAAC;AAAA,MACtB;AAAA,IACF,SAAS,KAAK;AACZ,WAAK,mBAAmB,SAAS;AACjC,YAAM,KAAK,WAAW,GAAG;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,MAAc,gBACZ,WACA,QACgC;AAChC,UAAM,SAAS,MAAM,KAAK,cAAc,SAAS;AACjD,UAAM,OAAO,cAAc,OAAO,IAAI;AAEtC,QAAI;AACF,YAAM,SAA6B,MAAM,OAAO;AAAA,QAC9C;AAAA,QACA,OAAO;AAAA,MACT;AACA,YAAM,OAAO,SAAS,OAAO,CAAC,EAAE,SAAS,IAAI,GAAG;AAChD,YAAM,OAAO,SAAS,OAAO,CAAC,EAAE,SAAS,IAAI,GAAG;AAChD,YAAM,OAAO,OAAO,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAClD,aAAO,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AAAA,IAChD,SAAS,KAAK;AACZ,WAAK,mBAAmB,SAAS;AACjC,YAAM,KAAK,WAAW,GAAG;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,MAAc,kBACZ,WACA,QACgC;AAChC,UAAM,SAAS,MAAM,KAAK,cAAc,SAAS;AACjD,UAAM,OAAO,cAAc,OAAO,IAAI;AAEtC,QAAI;AACF,YAAM,SAA6B,MAAM,OAAO;AAAA,QAC9C;AAAA,QACA,OAAO;AAAA,MACT;AACA,YAAM,OAAO,SAAS,OAAO,CAAC,EAAE,SAAS,IAAI,GAAG;AAChD,YAAM,OAAO,SAAS,OAAO,CAAC,EAAE,SAAS,IAAI,GAAG;AAChD,YAAM,OAAO,OAAO,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAClD,aAAO,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AAAA,IAChD,SAAS,KAAK;AACZ,WAAK,mBAAmB,SAAS;AACjC,YAAM,KAAK,WAAW,GAAG;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,eACZ,WACA,QAC4C;AAC5C,UAAM,YAAY,MAAM,KAAK,iBAAiB,SAAS;AACvD,UAAM,OAAO,cAAc,OAAO,IAAI;AAEtC,QAAI;AACF,YAAM,EAAE,eAAe,0BAA0B,IAAI,MAAM,OACzD,qCACF;AACA,YAAM,UAAU,KAAK,MAAM,GAAG,EAAE,CAAC,GAAG,QAAQ,KAAK,EAAE;AACnD,UAAI,WAAW,0BAA0B;AACzC,UAAI,YAAY,KAAM,YAAW,0BAA0B;AAAA,eAClD,YAAY;AACnB,mBAAW,0BAA0B;AAAA,eAC9B,YAAY,KAAM,YAAW,0BAA0B;AAChE,YAAM,SAAS,IAAI,cAAc,MAAM,QAAQ;AAE/C,YAAM,SAAS,MAAM,UAAU,iBAAiB,QAAQ,GAAG;AAAA,QACzD,eAAe,OAAO,gBAAgB;AAAA,QACtC,QAAQ;AAAA,MACV,CAAC;AACD,aAAO,EAAE,SAAS,OAAO,SAAS,MAAM,OAAO,KAAK;AAAA,IACtD,SAAS,KAAK;AACZ,WAAK,mBAAmB,SAAS;AACjC,YAAM,KAAK,WAAW,GAAG;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,MAAc,iBACZ,WACA,QACyC;AACzC,UAAM,YAAY,MAAM,KAAK,iBAAiB,SAAS;AACvD,UAAM,OAAO,cAAc,OAAO,IAAI;AAEtC,QAAI;AACF,YAAM,OAAO,MAAM,UAAU,qBAAqB,MAAM;AAAA,QACtD,eAAe,OAAO,gBAAgB;AAAA,MACxC,CAAC;AACD,aAAO,EAAE,MAAM,MAAM,OAAO,KAAK;AAAA,IACnC,SAAS,KAAK;AACZ,WAAK,mBAAmB,SAAS;AACjC,YAAM,KAAK,WAAW,GAAG;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAc,kBAAiC;AAC7C,QAAI,KAAK,KAAM,QAAO,KAAK;AAE3B,QAAI,KAAK,cAAc;AACrB,WAAK,OAAO,KAAK;AACjB,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,EAAE,2BAA2B,IAAI,MAAM,OAC3C,iCACF;AACA,UAAM,EAAE,uBAAuB,IAAI,MAAM,OACvC,wCACF;AAEA,SAAK,OAAO,IAAI,2BAA2B,EACxC,aAAa,sBAAsB,EACnC,MAAM;AAET,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,cAAc,KAAiB;AACrC,SAAK,OAAO;AACZ,SAAK,iBAAiB,IAAI,0CAAoB,GAAG;AACjD,SAAK,iBAAiB,IAAI,oCAAc,GAAG;AAAA,EAC7C;AAAA,EAEA,MAAc,oBAAkD;AAC9D,QAAI,KAAK,eAAgB,QAAO,KAAK;AAErC,UAAM,MAAM,MAAM,KAAK,gBAAgB;AACvC,SAAK,cAAc,GAAG;AACtB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,cAAc,WAAmB;AAC7C,QAAI,CAAC,KAAK,gBAAgB;AACxB,YAAM,MAAM,MAAM,KAAK,gBAAgB;AACvC,WAAK,cAAc,GAAG;AAAA,IACxB;AACA,UAAM,SAAS,MAAM,KAAK,eAAgB,YAAY,SAAS;AAG/D,WAAO,gBAAgB,CAAC,gBAAwB;AAC9C,WAAK,MAAM,YAAY;AAAA,QACrB,MAAM;AAAA,QACN,SAAS,EAAE,UAAU;AAAA,MACvB,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,iBAAiB,WAAuC;AACpE,UAAM,MAAM,MAAM,KAAK,gBAAgB;AACvC,UAAM,EAAE,iBAAiB,IAAI,MAAM,OACjC,qCACF;AAEA,UAAM,YAAY,IAAI,iBAAiB;AAAA,MACrC;AAAA,MACA;AAAA,IACF,CAAC,EAAE,MAAM;AAET,WAAO,IAAI,gCAAU,SAAgB;AAAA,EACvC;AAAA,EAEQ,mBAAmB,WAAyB;AAClD,SAAK,gBAAgB,WAAW,SAAS;AAAA,EAC3C;AAAA,EAEQ,iBAAuB;AAC7B,SAAK,gBAAgB,SAAS;AAC9B,SAAK,gBAAgB,QAAQ;AAC7B,SAAK,iBAAiB;AACtB,SAAK,iBAAiB;AACtB,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAMQ,MACN,OACA,MACM;AACN,UAAM,WAAW,KAAK,eAAe,IAAI,KAAK;AAC9C,QAAI,UAAU;AACZ,iBAAW,WAAW,UAAU;AAC9B,YAAI;AACF,kBAAQ,IAAI;AAAA,QACd,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,WAAW,KAAqB;AACtC,UAAM,aAAS,sCAAe,GAAG;AACjC,UAAM,QAAQ,IAAI,MAAM,OAAO,OAAO;AACtC,IAAC,MAAc,OAAO,OAAO;AAC7B,WAAO;AAAA,EACT;AACF;;;ADjkBO,SAAS,4BAA4B,KAAwB;AAClE,SAAO,IAAI,sBAAsB,EAAE,IAAI,CAAC;AAC1C;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/LedgerWebHidConnector.ts"],"sourcesContent":["import type { IConnector } from '@bytezhang/hardware-wallet-core';\nimport type { IDmk } from '@bytezhang/ledger-adapter';\n\nimport {\n LedgerWebHidConnector,\n} from './LedgerWebHidConnector';\nimport type { LedgerWebHidConnectorOptions } from './LedgerWebHidConnector';\n\nexport { LedgerWebHidConnector };\nexport type { LedgerWebHidConnectorOptions };\n\n/**\n * Create a LedgerWebHidConnector.\n *\n * @param dmk - Optional pre-built DMK instance. If omitted, the connector\n * will lazily create one using `@ledgerhq/device-management-kit`\n * and `@ledgerhq/device-transport-kit-web-hid`.\n */\nexport function createLedgerWebHidConnector(dmk?: IDmk): IConnector {\n return new LedgerWebHidConnector({ dmk });\n}\n","import type {\n IConnector,\n ConnectorDevice,\n ConnectorSession,\n ConnectorEventType,\n ConnectorEventMap,\n} from '@bytezhang/hardware-wallet-core';\nimport type { IDmk, SignerEvmSignature } from '@bytezhang/ledger-adapter';\nimport {\n LedgerDeviceManager,\n SignerManager,\n SignerBtc,\n SignerSol,\n mapLedgerError,\n} from '@bytezhang/ledger-adapter';\n\n// ---------------------------------------------------------------------------\n// Utilities\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the stable 4-digit HEX identifier from a Ledger BLE device name.\n * e.g., \"Nano X 123A\" → \"123A\", \"Ledger Nano X AB12\" → \"AB12\"\n * Returns undefined if no valid HEX suffix found.\n */\nfunction extractBleHexId(name?: string): string | undefined {\n if (!name) return undefined;\n const match = name.match(/\\b([0-9A-Fa-f]{4})$/);\n return match ? match[1].toUpperCase() : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\ntype EventHandler<K extends ConnectorEventType> = (\n data: ConnectorEventMap[K],\n) => void;\n\n/** Parameters for evmGetAddress */\ninterface EvmGetAddressCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for evmSignTransaction */\ninterface EvmSignTransactionCallParams {\n path: string;\n /** RLP-serialized transaction hex (0x-prefixed or plain) */\n serializedTx: string;\n}\n\n/** Parameters for evmSignMessage */\ninterface EvmSignMessageCallParams {\n path: string;\n message: string;\n}\n\n/** Parameters for evmSignTypedData */\ninterface EvmSignTypedDataCallParams {\n path: string;\n data: unknown;\n}\n\n/** Parameters for btcGetAddress */\ninterface BtcGetAddressCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for btcGetPublicKey */\ninterface BtcGetPublicKeyCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for btcSignTransaction */\ninterface BtcSignTransactionCallParams {\n psbt?: string;\n coin: string;\n}\n\n/** Parameters for btcSignMessage */\ninterface BtcSignMessageCallParams {\n path: string;\n message: string;\n coin?: string;\n}\n\n/** Parameters for solGetAddress */\ninterface SolGetAddressCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for solSignTransaction */\ninterface SolSignTransactionCallParams {\n path: string;\n /** Hex-encoded serialized transaction bytes (no 0x prefix) */\n serializedTx: string;\n}\n\n/** Parameters for solSignMessage */\ninterface SolSignMessageCallParams {\n path: string;\n /** Message bytes as hex string (no 0x prefix) */\n message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Strip the \"m/\" prefix from BIP-44 derivation paths. */\nfunction normalizePath(path: string): string {\n return path.startsWith('m/') ? path.slice(2) : path;\n}\n\n/** Remove `0x` prefix from a hex string if present. */\nfunction stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Ensure a hex string is `0x`-prefixed and zero-padded to 64 hex chars (32 bytes). */\nfunction padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n// ---------------------------------------------------------------------------\n// LedgerWebHidConnector\n// ---------------------------------------------------------------------------\n\nexport interface LedgerWebHidConnectorOptions {\n /**\n * Pre-built DMK instance. If not provided, a DMK will be created\n * lazily on first use via `@ledgerhq/device-management-kit` and\n * `@ledgerhq/device-transport-kit-web-hid`.\n */\n dmk?: IDmk;\n}\n\n/**\n * IConnector implementation for Ledger hardware wallets via WebHID.\n *\n * Wraps the Ledger DMK (Device Management Kit) and signer kits into\n * the unified IConnector interface used by the adapter layer.\n *\n * Design:\n * - Constructor accepts an optional pre-built DMK instance (or creates one lazily).\n * - searchDevices() uses DMK's listenToAvailableDevices() observable.\n * - connect() calls dmk.connect({ device }), returns a ConnectorSession.\n * - call() dispatches to chain-specific signer methods (EVM, BTC).\n * - Internally uses LedgerDeviceManager for session tracking and\n * SignerManager for per-session signer caching.\n */\nexport class LedgerWebHidConnector implements IConnector {\n private _deviceManager: LedgerDeviceManager | null = null;\n private _signerManager: SignerManager | null = null;\n private _dmk: IDmk | null = null;\n\n private readonly _eventHandlers = new Map<\n ConnectorEventType,\n Set<EventHandler<ConnectorEventType>>\n >();\n\n private readonly _providedDmk: IDmk | undefined;\n\n constructor(options?: LedgerWebHidConnectorOptions) {\n this._providedDmk = options?.dmk;\n if (this._providedDmk) {\n this._initManagers(this._providedDmk);\n }\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Device discovery\n // ---------------------------------------------------------------------------\n\n async searchDevices(): Promise<ConnectorDevice[]> {\n const dm = await this._getDeviceManager();\n\n let descriptors = await dm.enumerate();\n\n // If no devices found, trigger browser permission dialog via startDiscovering\n if (descriptors.length === 0) {\n try {\n await dm.requestDevice();\n } catch {\n // User may cancel the permission dialog — that's OK\n }\n descriptors = await dm.enumerate();\n }\n\n const result: ConnectorDevice[] = descriptors.map((d) => {\n // For BLE: extract stable 4-digit HEX from device name (e.g., \"Nano X 123A\" → \"123A\")\n // For USB: d.path is a temporary DMK UUID, not persistent\n const isBle = d.transport === 'BLE';\n const bleHexId = isBle ? extractBleHexId(d.name) : undefined;\n\n return {\n connectId: bleHexId || d.path,\n deviceId: d.path,\n name: d.name || d.type || 'Ledger',\n model: d.type,\n };\n });\n return result;\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Connection\n // ---------------------------------------------------------------------------\n\n async connect(deviceId?: string): Promise<ConnectorSession> {\n const dm = await this._getDeviceManager();\n\n // Ensure we have fresh device list\n await this.searchDevices();\n\n let resolvedDeviceId = deviceId;\n\n // Empty or missing deviceId — use first available device's DMK path\n if (!resolvedDeviceId) {\n // Use the first available device\n const descriptors = await dm.enumerate();\n if (descriptors.length === 0) {\n throw new Error(\n 'No Ledger device found. Make sure the device is connected via USB and unlocked.',\n );\n }\n resolvedDeviceId = descriptors[0].path;\n }\n\n try {\n const sessionId = await dm.connect(resolvedDeviceId);\n\n const session: ConnectorSession = {\n sessionId,\n deviceInfo: {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: 'unknown',\n deviceId: resolvedDeviceId,\n connectId: resolvedDeviceId,\n connectionType: 'usb',\n capabilities: {\n persistentDeviceIdentity: false,\n },\n },\n };\n\n this._emit('device-connect', {\n device: {\n connectId: resolvedDeviceId,\n deviceId: resolvedDeviceId,\n name: 'Ledger',\n },\n });\n\n return session;\n } catch (err) {\n // Retry once: reset and re-discover\n this._resetManagers();\n const dm2 = await this._getDeviceManager();\n await this.searchDevices();\n\n const descriptors = await dm2.enumerate();\n const retryId = deviceId\n ? descriptors.find((d) => d.path === deviceId)?.path\n : descriptors[0]?.path;\n\n if (!retryId) {\n throw new Error(\n 'No Ledger device found after retry. Make sure the device is connected via USB and unlocked.',\n );\n }\n\n const sessionId = await dm2.connect(retryId);\n\n const session: ConnectorSession = {\n sessionId,\n deviceInfo: {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: 'unknown',\n deviceId: retryId,\n connectId: retryId,\n connectionType: 'usb',\n },\n };\n\n this._emit('device-connect', {\n device: {\n connectId: retryId,\n deviceId: retryId,\n name: 'Ledger',\n },\n });\n\n return session;\n }\n }\n\n async disconnect(sessionId: string): Promise<void> {\n if (!this._deviceManager) return;\n\n const deviceId = this._deviceManager.getDeviceId(sessionId);\n this._signerManager?.invalidate(sessionId);\n await this._deviceManager.disconnect(sessionId);\n\n if (deviceId) {\n this._emit('device-disconnect', { connectId: deviceId });\n }\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Method dispatch\n // ---------------------------------------------------------------------------\n\n async call(\n sessionId: string,\n method: string,\n params: unknown,\n ): Promise<unknown> {\n switch (method) {\n case 'evmGetAddress':\n return this._evmGetAddress(sessionId, params as EvmGetAddressCallParams);\n case 'evmSignTransaction':\n return this._evmSignTransaction(sessionId, params as EvmSignTransactionCallParams);\n case 'evmSignMessage':\n return this._evmSignMessage(sessionId, params as EvmSignMessageCallParams);\n case 'evmSignTypedData':\n return this._evmSignTypedData(sessionId, params as EvmSignTypedDataCallParams);\n case 'btcGetAddress':\n return this._btcGetAddress(sessionId, params as BtcGetAddressCallParams);\n case 'btcGetPublicKey':\n return this._btcGetPublicKey(sessionId, params as BtcGetPublicKeyCallParams);\n case 'btcSignTransaction':\n return this._btcSignTransaction(sessionId, params as BtcSignTransactionCallParams);\n case 'btcSignMessage':\n return this._btcSignMessage(sessionId, params as BtcSignMessageCallParams);\n case 'btcGetMasterFingerprint':\n return this._btcGetMasterFingerprint(sessionId, params as { skipOpenApp?: boolean } | undefined);\n case 'solGetAddress':\n return this._solGetAddress(sessionId, params as SolGetAddressCallParams);\n case 'solSignTransaction':\n return this._solSignTransaction(sessionId, params as SolSignTransactionCallParams);\n case 'solSignMessage':\n return this._solSignMessage(sessionId, params as SolSignMessageCallParams);\n default:\n throw new Error(`LedgerWebHidConnector: unknown method \"${method}\"`);\n }\n }\n\n async cancel(_sessionId: string): Promise<void> {\n // Ledger DMK doesn't expose a generic cancel mechanism\n }\n\n uiResponse(_response: { type: string; payload: unknown }): void {\n // Ledger does not use interactive UI responses (PIN/passphrase)\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Events\n // ---------------------------------------------------------------------------\n\n on<K extends ConnectorEventType>(\n event: K,\n handler: (data: ConnectorEventMap[K]) => void,\n ): void {\n if (!this._eventHandlers.has(event)) {\n this._eventHandlers.set(event, new Set());\n }\n this._eventHandlers\n .get(event)!\n .add(handler as EventHandler<ConnectorEventType>);\n }\n\n off<K extends ConnectorEventType>(\n event: K,\n handler: (data: ConnectorEventMap[K]) => void,\n ): void {\n this._eventHandlers\n .get(event)\n ?.delete(handler as EventHandler<ConnectorEventType>);\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Reset\n // ---------------------------------------------------------------------------\n\n reset(): void {\n this._resetManagers();\n }\n\n // ---------------------------------------------------------------------------\n // Private — EVM methods\n // ---------------------------------------------------------------------------\n\n private async _evmGetAddress(\n sessionId: string,\n params: EvmGetAddressCallParams,\n ): Promise<{ address: string; publicKey?: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result = await signer.getAddress(path, {\n checkOnDevice: params.showOnDevice ?? false,\n });\n return { address: result.address, publicKey: result.publicKey };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignTransaction(\n sessionId: string,\n params: EvmSignTransactionCallParams,\n ): Promise<{ v: string; r: string; s: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signTransaction(\n path,\n params.serializedTx,\n );\n return {\n v: `0x${result.v.toString(16)}`,\n r: padHex64(result.r),\n s: padHex64(result.s),\n };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignMessage(\n sessionId: string,\n params: EvmSignMessageCallParams,\n ): Promise<{ signature: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signMessage(\n path,\n params.message,\n );\n const rHex = stripHex(result.r).padStart(64, '0');\n const sHex = stripHex(result.s).padStart(64, '0');\n const vHex = result.v.toString(16).padStart(2, '0');\n return { signature: `0x${rHex}${sHex}${vHex}` };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignTypedData(\n sessionId: string,\n params: EvmSignTypedDataCallParams,\n ): Promise<{ signature: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signTypedData(\n path,\n params.data,\n );\n const rHex = stripHex(result.r).padStart(64, '0');\n const sHex = stripHex(result.s).padStart(64, '0');\n const vHex = result.v.toString(16).padStart(2, '0');\n return { signature: `0x${rHex}${sHex}${vHex}` };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — BTC methods\n // ---------------------------------------------------------------------------\n\n private async _btcGetAddress(\n sessionId: string,\n params: BtcGetAddressCallParams,\n ): Promise<{ address: string; path: string }> {\n const btcSigner = await this._createBtcSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const { DefaultWallet, DefaultDescriptorTemplate } = await import(\n '@ledgerhq/device-signer-kit-bitcoin'\n );\n const purpose = path.split('/')[0]?.replace(\"'\", '');\n let template = DefaultDescriptorTemplate.NATIVE_SEGWIT;\n if (purpose === '44') template = DefaultDescriptorTemplate.LEGACY;\n else if (purpose === '49')\n template = DefaultDescriptorTemplate.NESTED_SEGWIT;\n else if (purpose === '86') template = DefaultDescriptorTemplate.TAPROOT;\n const wallet = new DefaultWallet(path, template);\n\n const result = await btcSigner.getWalletAddress(wallet, 0, {\n checkOnDevice: params.showOnDevice ?? false,\n change: false,\n });\n return { address: result.address, path: params.path };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _btcGetPublicKey(\n sessionId: string,\n params: BtcGetPublicKeyCallParams,\n ): Promise<{ xpub: string; path: string }> {\n const btcSigner = await this._createBtcSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const xpub = await btcSigner.getExtendedPublicKey(path, {\n checkOnDevice: params.showOnDevice ?? false,\n });\n return { xpub, path: params.path };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _btcSignTransaction(\n _sessionId: string,\n _params: BtcSignTransactionCallParams,\n ): Promise<never> {\n throw new Error('LedgerWebHidConnector: btcSignTransaction is not yet implemented');\n }\n\n private async _btcSignMessage(\n _sessionId: string,\n _params: BtcSignMessageCallParams,\n ): Promise<never> {\n throw new Error('LedgerWebHidConnector: btcSignMessage is not yet implemented');\n }\n\n private async _btcGetMasterFingerprint(\n sessionId: string,\n params?: { skipOpenApp?: boolean },\n ): Promise<{ masterFingerprint: string }> {\n const btcSigner = await this._createBtcSigner(sessionId);\n\n try {\n const fingerprint: Uint8Array = await btcSigner.getMasterFingerprint({\n skipOpenApp: params?.skipOpenApp,\n });\n // Convert Uint8Array to hex string\n const hex = Array.from(fingerprint)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n return { masterFingerprint: hex };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — SOL methods\n // ---------------------------------------------------------------------------\n\n private async _solGetAddress(\n sessionId: string,\n params: SolGetAddressCallParams,\n ): Promise<{ address: string; path: string }> {\n const solSigner = await this._createSolSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n // Ledger Solana signer returns a base58-encoded Ed25519 public key (= Solana address)\n const publicKey = await solSigner.getAddress(path, {\n checkOnDevice: params.showOnDevice ?? false,\n });\n return { address: publicKey, path: params.path };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _solSignTransaction(\n _sessionId: string,\n _params: SolSignTransactionCallParams,\n ): Promise<never> {\n throw new Error('LedgerWebHidConnector: solSignTransaction is not yet implemented');\n }\n\n private async _solSignMessage(\n _sessionId: string,\n _params: SolSignMessageCallParams,\n ): Promise<never> {\n throw new Error('LedgerWebHidConnector: solSignMessage is not yet implemented');\n }\n\n // ---------------------------------------------------------------------------\n // Private — DMK / Manager lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Lazily create or return the DMK instance.\n * If a DMK was provided via constructor, it is used directly.\n * Otherwise, one is created via dynamic import of the Ledger SDK.\n */\n private async _getOrCreateDmk(): Promise<IDmk> {\n if (this._dmk) return this._dmk;\n\n if (this._providedDmk) {\n this._dmk = this._providedDmk;\n return this._dmk;\n }\n\n const { DeviceManagementKitBuilder } = await import(\n '@ledgerhq/device-management-kit'\n );\n const { webHidTransportFactory } = await import(\n '@ledgerhq/device-transport-kit-web-hid'\n );\n\n this._dmk = new DeviceManagementKitBuilder()\n .addTransport(webHidTransportFactory)\n .build() as unknown as IDmk;\n\n return this._dmk;\n }\n\n private _initManagers(dmk: IDmk): void {\n this._dmk = dmk;\n this._deviceManager = new LedgerDeviceManager(dmk);\n this._signerManager = new SignerManager(dmk);\n }\n\n private async _getDeviceManager(): Promise<LedgerDeviceManager> {\n if (this._deviceManager) return this._deviceManager;\n\n const dmk = await this._getOrCreateDmk();\n this._initManagers(dmk);\n return this._deviceManager!;\n }\n\n private async _getEthSigner(sessionId: string) {\n if (!this._signerManager) {\n const dmk = await this._getOrCreateDmk();\n this._initManagers(dmk);\n }\n const signer = await this._signerManager!.getOrCreate(sessionId);\n\n // Wire up interaction events (open-app, unlock, verify-address, sign, etc.)\n signer.onInteraction = (interaction: string) => {\n this._emit('ui-event', {\n type: interaction,\n payload: { sessionId },\n });\n };\n\n return signer;\n }\n\n private async _createBtcSigner(sessionId: string): Promise<SignerBtc> {\n const dmk = await this._getOrCreateDmk();\n const { SignerBtcBuilder } = await import(\n '@ledgerhq/device-signer-kit-bitcoin'\n );\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sdkSigner = new SignerBtcBuilder({\n dmk: dmk as any,\n sessionId,\n }).build();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new SignerBtc(sdkSigner as any);\n }\n\n private async _createSolSigner(sessionId: string): Promise<SignerSol> {\n const dmk = await this._getOrCreateDmk();\n const { SignerSolanaBuilder } = await import(\n '@ledgerhq/device-signer-kit-solana'\n );\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sdkSigner = new SignerSolanaBuilder({\n dmk: dmk as any,\n sessionId,\n }).build();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new SignerSol(sdkSigner as any);\n }\n\n private _invalidateSession(sessionId: string): void {\n this._signerManager?.invalidate(sessionId);\n }\n\n private _resetManagers(): void {\n this._signerManager?.clearAll();\n this._deviceManager?.dispose();\n this._deviceManager = null;\n this._signerManager = null;\n this._dmk = null;\n }\n\n // ---------------------------------------------------------------------------\n // Private — Events\n // ---------------------------------------------------------------------------\n\n private _emit<K extends ConnectorEventType>(\n event: K,\n data: ConnectorEventMap[K],\n ): void {\n const handlers = this._eventHandlers.get(event);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(data);\n } catch {\n // Don't let listener errors break the connector\n }\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — Error handling\n // ---------------------------------------------------------------------------\n\n private _wrapError(err: unknown): Error {\n const mapped = mapLedgerError(err);\n const error = new Error(mapped.message);\n (error as any).code = mapped.code;\n return error;\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -3,8 +3,14 @@ import {
3
3
  LedgerDeviceManager,
4
4
  SignerManager,
5
5
  SignerBtc,
6
+ SignerSol,
6
7
  mapLedgerError
7
8
  } from "@bytezhang/ledger-adapter";
9
+ function extractBleHexId(name) {
10
+ if (!name) return void 0;
11
+ const match = name.match(/\b([0-9A-Fa-f]{4})$/);
12
+ return match ? match[1].toUpperCase() : void 0;
13
+ }
8
14
  function normalizePath(path) {
9
15
  return path.startsWith("m/") ? path.slice(2) : path;
10
16
  }
@@ -38,20 +44,16 @@ var LedgerWebHidConnector = class {
38
44
  }
39
45
  descriptors = await dm.enumerate();
40
46
  }
41
- console.log("[LedgerWebHidConnector] descriptors:", JSON.stringify(descriptors));
42
- const result = descriptors.map((d) => ({
43
- // d.path is a temporary DMK UUID (regenerated on each discovery).
44
- // Used internally for routing. NOT a persistent device ID.
45
- connectId: d.path,
46
- deviceId: d.path,
47
- name: d.type || "Ledger",
48
- model: d.type,
49
- capabilities: {
50
- // WebHID: DMK generates ephemeral UUIDs each session
51
- persistentDeviceIdentity: false
52
- }
53
- }));
54
- console.log("[LedgerWebHidConnector] searchDevices result:", JSON.stringify(result));
47
+ const result = descriptors.map((d) => {
48
+ const isBle = d.transport === "BLE";
49
+ const bleHexId = isBle ? extractBleHexId(d.name) : void 0;
50
+ return {
51
+ connectId: bleHexId || d.path,
52
+ deviceId: d.path,
53
+ name: d.name || d.type || "Ledger",
54
+ model: d.type
55
+ };
56
+ });
55
57
  return result;
56
58
  }
57
59
  // ---------------------------------------------------------------------------
@@ -153,6 +155,18 @@ var LedgerWebHidConnector = class {
153
155
  return this._btcGetAddress(sessionId, params);
154
156
  case "btcGetPublicKey":
155
157
  return this._btcGetPublicKey(sessionId, params);
158
+ case "btcSignTransaction":
159
+ return this._btcSignTransaction(sessionId, params);
160
+ case "btcSignMessage":
161
+ return this._btcSignMessage(sessionId, params);
162
+ case "btcGetMasterFingerprint":
163
+ return this._btcGetMasterFingerprint(sessionId, params);
164
+ case "solGetAddress":
165
+ return this._solGetAddress(sessionId, params);
166
+ case "solSignTransaction":
167
+ return this._solSignTransaction(sessionId, params);
168
+ case "solSignMessage":
169
+ return this._solSignMessage(sessionId, params);
156
170
  default:
157
171
  throw new Error(`LedgerWebHidConnector: unknown method "${method}"`);
158
172
  }
@@ -285,6 +299,47 @@ var LedgerWebHidConnector = class {
285
299
  throw this._wrapError(err);
286
300
  }
287
301
  }
302
+ async _btcSignTransaction(_sessionId, _params) {
303
+ throw new Error("LedgerWebHidConnector: btcSignTransaction is not yet implemented");
304
+ }
305
+ async _btcSignMessage(_sessionId, _params) {
306
+ throw new Error("LedgerWebHidConnector: btcSignMessage is not yet implemented");
307
+ }
308
+ async _btcGetMasterFingerprint(sessionId, params) {
309
+ const btcSigner = await this._createBtcSigner(sessionId);
310
+ try {
311
+ const fingerprint = await btcSigner.getMasterFingerprint({
312
+ skipOpenApp: params?.skipOpenApp
313
+ });
314
+ const hex = Array.from(fingerprint).map((b) => b.toString(16).padStart(2, "0")).join("");
315
+ return { masterFingerprint: hex };
316
+ } catch (err) {
317
+ this._invalidateSession(sessionId);
318
+ throw this._wrapError(err);
319
+ }
320
+ }
321
+ // ---------------------------------------------------------------------------
322
+ // Private — SOL methods
323
+ // ---------------------------------------------------------------------------
324
+ async _solGetAddress(sessionId, params) {
325
+ const solSigner = await this._createSolSigner(sessionId);
326
+ const path = normalizePath(params.path);
327
+ try {
328
+ const publicKey = await solSigner.getAddress(path, {
329
+ checkOnDevice: params.showOnDevice ?? false
330
+ });
331
+ return { address: publicKey, path: params.path };
332
+ } catch (err) {
333
+ this._invalidateSession(sessionId);
334
+ throw this._wrapError(err);
335
+ }
336
+ }
337
+ async _solSignTransaction(_sessionId, _params) {
338
+ throw new Error("LedgerWebHidConnector: solSignTransaction is not yet implemented");
339
+ }
340
+ async _solSignMessage(_sessionId, _params) {
341
+ throw new Error("LedgerWebHidConnector: solSignMessage is not yet implemented");
342
+ }
288
343
  // ---------------------------------------------------------------------------
289
344
  // Private — DMK / Manager lifecycle
290
345
  // ---------------------------------------------------------------------------
@@ -338,6 +393,15 @@ var LedgerWebHidConnector = class {
338
393
  }).build();
339
394
  return new SignerBtc(sdkSigner);
340
395
  }
396
+ async _createSolSigner(sessionId) {
397
+ const dmk = await this._getOrCreateDmk();
398
+ const { SignerSolanaBuilder } = await import("@ledgerhq/device-signer-kit-solana");
399
+ const sdkSigner = new SignerSolanaBuilder({
400
+ dmk,
401
+ sessionId
402
+ }).build();
403
+ return new SignerSol(sdkSigner);
404
+ }
341
405
  _invalidateSession(sessionId) {
342
406
  this._signerManager?.invalidate(sessionId);
343
407
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/LedgerWebHidConnector.ts","../src/index.ts"],"sourcesContent":["import type {\n IConnector,\n ConnectorDevice,\n ConnectorSession,\n ConnectorEventType,\n ConnectorEventMap,\n} from '@bytezhang/hardware-wallet-core';\nimport type { IDmk, SignerEvmSignature } from '@bytezhang/ledger-adapter';\nimport {\n LedgerDeviceManager,\n SignerManager,\n SignerBtc,\n mapLedgerError,\n} from '@bytezhang/ledger-adapter';\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\ntype EventHandler<K extends ConnectorEventType> = (\n data: ConnectorEventMap[K],\n) => void;\n\n/** Parameters for evmGetAddress */\ninterface EvmGetAddressCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for evmSignTransaction */\ninterface EvmSignTransactionCallParams {\n path: string;\n /** RLP-serialized transaction hex (0x-prefixed or plain) */\n serializedTx: string;\n}\n\n/** Parameters for evmSignMessage */\ninterface EvmSignMessageCallParams {\n path: string;\n message: string;\n}\n\n/** Parameters for evmSignTypedData */\ninterface EvmSignTypedDataCallParams {\n path: string;\n data: unknown;\n}\n\n/** Parameters for btcGetAddress */\ninterface BtcGetAddressCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for btcGetPublicKey */\ninterface BtcGetPublicKeyCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Strip the \"m/\" prefix from BIP-44 derivation paths. */\nfunction normalizePath(path: string): string {\n return path.startsWith('m/') ? path.slice(2) : path;\n}\n\n/** Remove `0x` prefix from a hex string if present. */\nfunction stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Ensure a hex string is `0x`-prefixed and zero-padded to 64 hex chars (32 bytes). */\nfunction padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n// ---------------------------------------------------------------------------\n// LedgerWebHidConnector\n// ---------------------------------------------------------------------------\n\nexport interface LedgerWebHidConnectorOptions {\n /**\n * Pre-built DMK instance. If not provided, a DMK will be created\n * lazily on first use via `@ledgerhq/device-management-kit` and\n * `@ledgerhq/device-transport-kit-web-hid`.\n */\n dmk?: IDmk;\n}\n\n/**\n * IConnector implementation for Ledger hardware wallets via WebHID.\n *\n * Wraps the Ledger DMK (Device Management Kit) and signer kits into\n * the unified IConnector interface used by the adapter layer.\n *\n * Design:\n * - Constructor accepts an optional pre-built DMK instance (or creates one lazily).\n * - searchDevices() uses DMK's listenToAvailableDevices() observable.\n * - connect() calls dmk.connect({ device }), returns a ConnectorSession.\n * - call() dispatches to chain-specific signer methods (EVM, BTC).\n * - Internally uses LedgerDeviceManager for session tracking and\n * SignerManager for per-session signer caching.\n */\nexport class LedgerWebHidConnector implements IConnector {\n private _deviceManager: LedgerDeviceManager | null = null;\n private _signerManager: SignerManager | null = null;\n private _dmk: IDmk | null = null;\n\n private readonly _eventHandlers = new Map<\n ConnectorEventType,\n Set<EventHandler<ConnectorEventType>>\n >();\n\n private readonly _providedDmk: IDmk | undefined;\n\n constructor(options?: LedgerWebHidConnectorOptions) {\n this._providedDmk = options?.dmk;\n if (this._providedDmk) {\n this._initManagers(this._providedDmk);\n }\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Device discovery\n // ---------------------------------------------------------------------------\n\n async searchDevices(): Promise<ConnectorDevice[]> {\n const dm = await this._getDeviceManager();\n\n let descriptors = await dm.enumerate();\n\n // If no devices found, trigger browser permission dialog via startDiscovering\n if (descriptors.length === 0) {\n try {\n await dm.requestDevice();\n } catch {\n // User may cancel the permission dialog — that's OK\n }\n descriptors = await dm.enumerate();\n }\n\n console.log('[LedgerWebHidConnector] descriptors:', JSON.stringify(descriptors));\n const result: ConnectorDevice[] = descriptors.map((d) => ({\n // d.path is a temporary DMK UUID (regenerated on each discovery).\n // Used internally for routing. NOT a persistent device ID.\n connectId: d.path,\n deviceId: d.path,\n name: d.type || 'Ledger',\n model: d.type,\n capabilities: {\n // WebHID: DMK generates ephemeral UUIDs each session\n persistentDeviceIdentity: false,\n },\n }));\n console.log('[LedgerWebHidConnector] searchDevices result:', JSON.stringify(result));\n return result;\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Connection\n // ---------------------------------------------------------------------------\n\n async connect(deviceId?: string): Promise<ConnectorSession> {\n const dm = await this._getDeviceManager();\n\n // Ensure we have fresh device list\n await this.searchDevices();\n\n let resolvedDeviceId = deviceId;\n\n // Empty or missing deviceId — use first available device's DMK path\n if (!resolvedDeviceId) {\n // Use the first available device\n const descriptors = await dm.enumerate();\n if (descriptors.length === 0) {\n throw new Error(\n 'No Ledger device found. Make sure the device is connected via USB and unlocked.',\n );\n }\n resolvedDeviceId = descriptors[0].path;\n }\n\n try {\n const sessionId = await dm.connect(resolvedDeviceId);\n\n const session: ConnectorSession = {\n sessionId,\n deviceInfo: {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: 'unknown',\n deviceId: resolvedDeviceId,\n connectId: resolvedDeviceId,\n connectionType: 'usb',\n capabilities: {\n persistentDeviceIdentity: false,\n },\n },\n };\n\n this._emit('device-connect', {\n device: {\n connectId: resolvedDeviceId,\n deviceId: resolvedDeviceId,\n name: 'Ledger',\n },\n });\n\n return session;\n } catch (err) {\n // Retry once: reset and re-discover\n this._resetManagers();\n const dm2 = await this._getDeviceManager();\n await this.searchDevices();\n\n const descriptors = await dm2.enumerate();\n const retryId = deviceId\n ? descriptors.find((d) => d.path === deviceId)?.path\n : descriptors[0]?.path;\n\n if (!retryId) {\n throw new Error(\n 'No Ledger device found after retry. Make sure the device is connected via USB and unlocked.',\n );\n }\n\n const sessionId = await dm2.connect(retryId);\n\n const session: ConnectorSession = {\n sessionId,\n deviceInfo: {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: 'unknown',\n deviceId: retryId,\n connectId: retryId,\n connectionType: 'usb',\n },\n };\n\n this._emit('device-connect', {\n device: {\n connectId: retryId,\n deviceId: retryId,\n name: 'Ledger',\n },\n });\n\n return session;\n }\n }\n\n async disconnect(sessionId: string): Promise<void> {\n if (!this._deviceManager) return;\n\n const deviceId = this._deviceManager.getDeviceId(sessionId);\n this._signerManager?.invalidate(sessionId);\n await this._deviceManager.disconnect(sessionId);\n\n if (deviceId) {\n this._emit('device-disconnect', { connectId: deviceId });\n }\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Method dispatch\n // ---------------------------------------------------------------------------\n\n async call(\n sessionId: string,\n method: string,\n params: unknown,\n ): Promise<unknown> {\n switch (method) {\n case 'evmGetAddress':\n return this._evmGetAddress(sessionId, params as EvmGetAddressCallParams);\n case 'evmSignTransaction':\n return this._evmSignTransaction(sessionId, params as EvmSignTransactionCallParams);\n case 'evmSignMessage':\n return this._evmSignMessage(sessionId, params as EvmSignMessageCallParams);\n case 'evmSignTypedData':\n return this._evmSignTypedData(sessionId, params as EvmSignTypedDataCallParams);\n case 'btcGetAddress':\n return this._btcGetAddress(sessionId, params as BtcGetAddressCallParams);\n case 'btcGetPublicKey':\n return this._btcGetPublicKey(sessionId, params as BtcGetPublicKeyCallParams);\n default:\n throw new Error(`LedgerWebHidConnector: unknown method \"${method}\"`);\n }\n }\n\n async cancel(_sessionId: string): Promise<void> {\n // Ledger DMK doesn't expose a generic cancel mechanism\n }\n\n uiResponse(_response: { type: string; payload: unknown }): void {\n // Ledger does not use interactive UI responses (PIN/passphrase)\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Events\n // ---------------------------------------------------------------------------\n\n on<K extends ConnectorEventType>(\n event: K,\n handler: (data: ConnectorEventMap[K]) => void,\n ): void {\n if (!this._eventHandlers.has(event)) {\n this._eventHandlers.set(event, new Set());\n }\n this._eventHandlers\n .get(event)!\n .add(handler as EventHandler<ConnectorEventType>);\n }\n\n off<K extends ConnectorEventType>(\n event: K,\n handler: (data: ConnectorEventMap[K]) => void,\n ): void {\n this._eventHandlers\n .get(event)\n ?.delete(handler as EventHandler<ConnectorEventType>);\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Reset\n // ---------------------------------------------------------------------------\n\n reset(): void {\n this._resetManagers();\n }\n\n // ---------------------------------------------------------------------------\n // Private — EVM methods\n // ---------------------------------------------------------------------------\n\n private async _evmGetAddress(\n sessionId: string,\n params: EvmGetAddressCallParams,\n ): Promise<{ address: string; publicKey?: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result = await signer.getAddress(path, {\n checkOnDevice: params.showOnDevice ?? false,\n });\n return { address: result.address, publicKey: result.publicKey };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignTransaction(\n sessionId: string,\n params: EvmSignTransactionCallParams,\n ): Promise<{ v: string; r: string; s: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signTransaction(\n path,\n params.serializedTx,\n );\n return {\n v: `0x${result.v.toString(16)}`,\n r: padHex64(result.r),\n s: padHex64(result.s),\n };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignMessage(\n sessionId: string,\n params: EvmSignMessageCallParams,\n ): Promise<{ signature: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signMessage(\n path,\n params.message,\n );\n const rHex = stripHex(result.r).padStart(64, '0');\n const sHex = stripHex(result.s).padStart(64, '0');\n const vHex = result.v.toString(16).padStart(2, '0');\n return { signature: `0x${rHex}${sHex}${vHex}` };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignTypedData(\n sessionId: string,\n params: EvmSignTypedDataCallParams,\n ): Promise<{ signature: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signTypedData(\n path,\n params.data,\n );\n const rHex = stripHex(result.r).padStart(64, '0');\n const sHex = stripHex(result.s).padStart(64, '0');\n const vHex = result.v.toString(16).padStart(2, '0');\n return { signature: `0x${rHex}${sHex}${vHex}` };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — BTC methods\n // ---------------------------------------------------------------------------\n\n private async _btcGetAddress(\n sessionId: string,\n params: BtcGetAddressCallParams,\n ): Promise<{ address: string; path: string }> {\n const btcSigner = await this._createBtcSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const { DefaultWallet, DefaultDescriptorTemplate } = await import(\n '@ledgerhq/device-signer-kit-bitcoin'\n );\n const purpose = path.split('/')[0]?.replace(\"'\", '');\n let template = DefaultDescriptorTemplate.NATIVE_SEGWIT;\n if (purpose === '44') template = DefaultDescriptorTemplate.LEGACY;\n else if (purpose === '49')\n template = DefaultDescriptorTemplate.NESTED_SEGWIT;\n else if (purpose === '86') template = DefaultDescriptorTemplate.TAPROOT;\n const wallet = new DefaultWallet(path, template);\n\n const result = await btcSigner.getWalletAddress(wallet, 0, {\n checkOnDevice: params.showOnDevice ?? false,\n change: false,\n });\n return { address: result.address, path: params.path };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _btcGetPublicKey(\n sessionId: string,\n params: BtcGetPublicKeyCallParams,\n ): Promise<{ xpub: string; path: string }> {\n const btcSigner = await this._createBtcSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const xpub = await btcSigner.getExtendedPublicKey(path, {\n checkOnDevice: params.showOnDevice ?? false,\n });\n return { xpub, path: params.path };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — DMK / Manager lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Lazily create or return the DMK instance.\n * If a DMK was provided via constructor, it is used directly.\n * Otherwise, one is created via dynamic import of the Ledger SDK.\n */\n private async _getOrCreateDmk(): Promise<IDmk> {\n if (this._dmk) return this._dmk;\n\n if (this._providedDmk) {\n this._dmk = this._providedDmk;\n return this._dmk;\n }\n\n const { DeviceManagementKitBuilder } = await import(\n '@ledgerhq/device-management-kit'\n );\n const { webHidTransportFactory } = await import(\n '@ledgerhq/device-transport-kit-web-hid'\n );\n\n this._dmk = new DeviceManagementKitBuilder()\n .addTransport(webHidTransportFactory)\n .build() as unknown as IDmk;\n\n return this._dmk;\n }\n\n private _initManagers(dmk: IDmk): void {\n this._dmk = dmk;\n this._deviceManager = new LedgerDeviceManager(dmk);\n this._signerManager = new SignerManager(dmk);\n }\n\n private async _getDeviceManager(): Promise<LedgerDeviceManager> {\n if (this._deviceManager) return this._deviceManager;\n\n const dmk = await this._getOrCreateDmk();\n this._initManagers(dmk);\n return this._deviceManager!;\n }\n\n private async _getEthSigner(sessionId: string) {\n if (!this._signerManager) {\n const dmk = await this._getOrCreateDmk();\n this._initManagers(dmk);\n }\n const signer = await this._signerManager!.getOrCreate(sessionId);\n\n // Wire up interaction events (open-app, unlock, verify-address, sign, etc.)\n signer.onInteraction = (interaction: string) => {\n this._emit('ui-event', {\n type: interaction,\n payload: { sessionId },\n });\n };\n\n return signer;\n }\n\n private async _createBtcSigner(sessionId: string): Promise<SignerBtc> {\n const dmk = await this._getOrCreateDmk();\n const { SignerBtcBuilder } = await import(\n '@ledgerhq/device-signer-kit-bitcoin'\n );\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sdkSigner = new SignerBtcBuilder({\n dmk: dmk as any,\n sessionId,\n }).build();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new SignerBtc(sdkSigner as any);\n }\n\n private _invalidateSession(sessionId: string): void {\n this._signerManager?.invalidate(sessionId);\n }\n\n private _resetManagers(): void {\n this._signerManager?.clearAll();\n this._deviceManager?.dispose();\n this._deviceManager = null;\n this._signerManager = null;\n this._dmk = null;\n }\n\n // ---------------------------------------------------------------------------\n // Private — Events\n // ---------------------------------------------------------------------------\n\n private _emit<K extends ConnectorEventType>(\n event: K,\n data: ConnectorEventMap[K],\n ): void {\n const handlers = this._eventHandlers.get(event);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(data);\n } catch {\n // Don't let listener errors break the connector\n }\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — Error handling\n // ---------------------------------------------------------------------------\n\n private _wrapError(err: unknown): Error {\n const mapped = mapLedgerError(err);\n const error = new Error(mapped.message);\n (error as any).code = mapped.code;\n return error;\n }\n}\n","import type { IConnector } from '@bytezhang/hardware-wallet-core';\nimport type { IDmk } from '@bytezhang/ledger-adapter';\n\nimport {\n LedgerWebHidConnector,\n} from './LedgerWebHidConnector';\nimport type { LedgerWebHidConnectorOptions } from './LedgerWebHidConnector';\n\nexport { LedgerWebHidConnector };\nexport type { LedgerWebHidConnectorOptions };\n\n/**\n * Create a LedgerWebHidConnector.\n *\n * @param dmk - Optional pre-built DMK instance. If omitted, the connector\n * will lazily create one using `@ledgerhq/device-management-kit`\n * and `@ledgerhq/device-transport-kit-web-hid`.\n */\nexport function createLedgerWebHidConnector(dmk?: IDmk): IConnector {\n return new LedgerWebHidConnector({ dmk });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/LedgerWebHidConnector.ts","../src/index.ts"],"sourcesContent":["import type {\n IConnector,\n ConnectorDevice,\n ConnectorSession,\n ConnectorEventType,\n ConnectorEventMap,\n} from '@bytezhang/hardware-wallet-core';\nimport type { IDmk, SignerEvmSignature } from '@bytezhang/ledger-adapter';\nimport {\n LedgerDeviceManager,\n SignerManager,\n SignerBtc,\n SignerSol,\n mapLedgerError,\n} from '@bytezhang/ledger-adapter';\n\n// ---------------------------------------------------------------------------\n// Utilities\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the stable 4-digit HEX identifier from a Ledger BLE device name.\n * e.g., \"Nano X 123A\" → \"123A\", \"Ledger Nano X AB12\" → \"AB12\"\n * Returns undefined if no valid HEX suffix found.\n */\nfunction extractBleHexId(name?: string): string | undefined {\n if (!name) return undefined;\n const match = name.match(/\\b([0-9A-Fa-f]{4})$/);\n return match ? match[1].toUpperCase() : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\ntype EventHandler<K extends ConnectorEventType> = (\n data: ConnectorEventMap[K],\n) => void;\n\n/** Parameters for evmGetAddress */\ninterface EvmGetAddressCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for evmSignTransaction */\ninterface EvmSignTransactionCallParams {\n path: string;\n /** RLP-serialized transaction hex (0x-prefixed or plain) */\n serializedTx: string;\n}\n\n/** Parameters for evmSignMessage */\ninterface EvmSignMessageCallParams {\n path: string;\n message: string;\n}\n\n/** Parameters for evmSignTypedData */\ninterface EvmSignTypedDataCallParams {\n path: string;\n data: unknown;\n}\n\n/** Parameters for btcGetAddress */\ninterface BtcGetAddressCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for btcGetPublicKey */\ninterface BtcGetPublicKeyCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for btcSignTransaction */\ninterface BtcSignTransactionCallParams {\n psbt?: string;\n coin: string;\n}\n\n/** Parameters for btcSignMessage */\ninterface BtcSignMessageCallParams {\n path: string;\n message: string;\n coin?: string;\n}\n\n/** Parameters for solGetAddress */\ninterface SolGetAddressCallParams {\n path: string;\n showOnDevice?: boolean;\n}\n\n/** Parameters for solSignTransaction */\ninterface SolSignTransactionCallParams {\n path: string;\n /** Hex-encoded serialized transaction bytes (no 0x prefix) */\n serializedTx: string;\n}\n\n/** Parameters for solSignMessage */\ninterface SolSignMessageCallParams {\n path: string;\n /** Message bytes as hex string (no 0x prefix) */\n message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Strip the \"m/\" prefix from BIP-44 derivation paths. */\nfunction normalizePath(path: string): string {\n return path.startsWith('m/') ? path.slice(2) : path;\n}\n\n/** Remove `0x` prefix from a hex string if present. */\nfunction stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Ensure a hex string is `0x`-prefixed and zero-padded to 64 hex chars (32 bytes). */\nfunction padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n// ---------------------------------------------------------------------------\n// LedgerWebHidConnector\n// ---------------------------------------------------------------------------\n\nexport interface LedgerWebHidConnectorOptions {\n /**\n * Pre-built DMK instance. If not provided, a DMK will be created\n * lazily on first use via `@ledgerhq/device-management-kit` and\n * `@ledgerhq/device-transport-kit-web-hid`.\n */\n dmk?: IDmk;\n}\n\n/**\n * IConnector implementation for Ledger hardware wallets via WebHID.\n *\n * Wraps the Ledger DMK (Device Management Kit) and signer kits into\n * the unified IConnector interface used by the adapter layer.\n *\n * Design:\n * - Constructor accepts an optional pre-built DMK instance (or creates one lazily).\n * - searchDevices() uses DMK's listenToAvailableDevices() observable.\n * - connect() calls dmk.connect({ device }), returns a ConnectorSession.\n * - call() dispatches to chain-specific signer methods (EVM, BTC).\n * - Internally uses LedgerDeviceManager for session tracking and\n * SignerManager for per-session signer caching.\n */\nexport class LedgerWebHidConnector implements IConnector {\n private _deviceManager: LedgerDeviceManager | null = null;\n private _signerManager: SignerManager | null = null;\n private _dmk: IDmk | null = null;\n\n private readonly _eventHandlers = new Map<\n ConnectorEventType,\n Set<EventHandler<ConnectorEventType>>\n >();\n\n private readonly _providedDmk: IDmk | undefined;\n\n constructor(options?: LedgerWebHidConnectorOptions) {\n this._providedDmk = options?.dmk;\n if (this._providedDmk) {\n this._initManagers(this._providedDmk);\n }\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Device discovery\n // ---------------------------------------------------------------------------\n\n async searchDevices(): Promise<ConnectorDevice[]> {\n const dm = await this._getDeviceManager();\n\n let descriptors = await dm.enumerate();\n\n // If no devices found, trigger browser permission dialog via startDiscovering\n if (descriptors.length === 0) {\n try {\n await dm.requestDevice();\n } catch {\n // User may cancel the permission dialog — that's OK\n }\n descriptors = await dm.enumerate();\n }\n\n const result: ConnectorDevice[] = descriptors.map((d) => {\n // For BLE: extract stable 4-digit HEX from device name (e.g., \"Nano X 123A\" → \"123A\")\n // For USB: d.path is a temporary DMK UUID, not persistent\n const isBle = d.transport === 'BLE';\n const bleHexId = isBle ? extractBleHexId(d.name) : undefined;\n\n return {\n connectId: bleHexId || d.path,\n deviceId: d.path,\n name: d.name || d.type || 'Ledger',\n model: d.type,\n };\n });\n return result;\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Connection\n // ---------------------------------------------------------------------------\n\n async connect(deviceId?: string): Promise<ConnectorSession> {\n const dm = await this._getDeviceManager();\n\n // Ensure we have fresh device list\n await this.searchDevices();\n\n let resolvedDeviceId = deviceId;\n\n // Empty or missing deviceId — use first available device's DMK path\n if (!resolvedDeviceId) {\n // Use the first available device\n const descriptors = await dm.enumerate();\n if (descriptors.length === 0) {\n throw new Error(\n 'No Ledger device found. Make sure the device is connected via USB and unlocked.',\n );\n }\n resolvedDeviceId = descriptors[0].path;\n }\n\n try {\n const sessionId = await dm.connect(resolvedDeviceId);\n\n const session: ConnectorSession = {\n sessionId,\n deviceInfo: {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: 'unknown',\n deviceId: resolvedDeviceId,\n connectId: resolvedDeviceId,\n connectionType: 'usb',\n capabilities: {\n persistentDeviceIdentity: false,\n },\n },\n };\n\n this._emit('device-connect', {\n device: {\n connectId: resolvedDeviceId,\n deviceId: resolvedDeviceId,\n name: 'Ledger',\n },\n });\n\n return session;\n } catch (err) {\n // Retry once: reset and re-discover\n this._resetManagers();\n const dm2 = await this._getDeviceManager();\n await this.searchDevices();\n\n const descriptors = await dm2.enumerate();\n const retryId = deviceId\n ? descriptors.find((d) => d.path === deviceId)?.path\n : descriptors[0]?.path;\n\n if (!retryId) {\n throw new Error(\n 'No Ledger device found after retry. Make sure the device is connected via USB and unlocked.',\n );\n }\n\n const sessionId = await dm2.connect(retryId);\n\n const session: ConnectorSession = {\n sessionId,\n deviceInfo: {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: 'unknown',\n deviceId: retryId,\n connectId: retryId,\n connectionType: 'usb',\n },\n };\n\n this._emit('device-connect', {\n device: {\n connectId: retryId,\n deviceId: retryId,\n name: 'Ledger',\n },\n });\n\n return session;\n }\n }\n\n async disconnect(sessionId: string): Promise<void> {\n if (!this._deviceManager) return;\n\n const deviceId = this._deviceManager.getDeviceId(sessionId);\n this._signerManager?.invalidate(sessionId);\n await this._deviceManager.disconnect(sessionId);\n\n if (deviceId) {\n this._emit('device-disconnect', { connectId: deviceId });\n }\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Method dispatch\n // ---------------------------------------------------------------------------\n\n async call(\n sessionId: string,\n method: string,\n params: unknown,\n ): Promise<unknown> {\n switch (method) {\n case 'evmGetAddress':\n return this._evmGetAddress(sessionId, params as EvmGetAddressCallParams);\n case 'evmSignTransaction':\n return this._evmSignTransaction(sessionId, params as EvmSignTransactionCallParams);\n case 'evmSignMessage':\n return this._evmSignMessage(sessionId, params as EvmSignMessageCallParams);\n case 'evmSignTypedData':\n return this._evmSignTypedData(sessionId, params as EvmSignTypedDataCallParams);\n case 'btcGetAddress':\n return this._btcGetAddress(sessionId, params as BtcGetAddressCallParams);\n case 'btcGetPublicKey':\n return this._btcGetPublicKey(sessionId, params as BtcGetPublicKeyCallParams);\n case 'btcSignTransaction':\n return this._btcSignTransaction(sessionId, params as BtcSignTransactionCallParams);\n case 'btcSignMessage':\n return this._btcSignMessage(sessionId, params as BtcSignMessageCallParams);\n case 'btcGetMasterFingerprint':\n return this._btcGetMasterFingerprint(sessionId, params as { skipOpenApp?: boolean } | undefined);\n case 'solGetAddress':\n return this._solGetAddress(sessionId, params as SolGetAddressCallParams);\n case 'solSignTransaction':\n return this._solSignTransaction(sessionId, params as SolSignTransactionCallParams);\n case 'solSignMessage':\n return this._solSignMessage(sessionId, params as SolSignMessageCallParams);\n default:\n throw new Error(`LedgerWebHidConnector: unknown method \"${method}\"`);\n }\n }\n\n async cancel(_sessionId: string): Promise<void> {\n // Ledger DMK doesn't expose a generic cancel mechanism\n }\n\n uiResponse(_response: { type: string; payload: unknown }): void {\n // Ledger does not use interactive UI responses (PIN/passphrase)\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Events\n // ---------------------------------------------------------------------------\n\n on<K extends ConnectorEventType>(\n event: K,\n handler: (data: ConnectorEventMap[K]) => void,\n ): void {\n if (!this._eventHandlers.has(event)) {\n this._eventHandlers.set(event, new Set());\n }\n this._eventHandlers\n .get(event)!\n .add(handler as EventHandler<ConnectorEventType>);\n }\n\n off<K extends ConnectorEventType>(\n event: K,\n handler: (data: ConnectorEventMap[K]) => void,\n ): void {\n this._eventHandlers\n .get(event)\n ?.delete(handler as EventHandler<ConnectorEventType>);\n }\n\n // ---------------------------------------------------------------------------\n // IConnector — Reset\n // ---------------------------------------------------------------------------\n\n reset(): void {\n this._resetManagers();\n }\n\n // ---------------------------------------------------------------------------\n // Private — EVM methods\n // ---------------------------------------------------------------------------\n\n private async _evmGetAddress(\n sessionId: string,\n params: EvmGetAddressCallParams,\n ): Promise<{ address: string; publicKey?: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result = await signer.getAddress(path, {\n checkOnDevice: params.showOnDevice ?? false,\n });\n return { address: result.address, publicKey: result.publicKey };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignTransaction(\n sessionId: string,\n params: EvmSignTransactionCallParams,\n ): Promise<{ v: string; r: string; s: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signTransaction(\n path,\n params.serializedTx,\n );\n return {\n v: `0x${result.v.toString(16)}`,\n r: padHex64(result.r),\n s: padHex64(result.s),\n };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignMessage(\n sessionId: string,\n params: EvmSignMessageCallParams,\n ): Promise<{ signature: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signMessage(\n path,\n params.message,\n );\n const rHex = stripHex(result.r).padStart(64, '0');\n const sHex = stripHex(result.s).padStart(64, '0');\n const vHex = result.v.toString(16).padStart(2, '0');\n return { signature: `0x${rHex}${sHex}${vHex}` };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _evmSignTypedData(\n sessionId: string,\n params: EvmSignTypedDataCallParams,\n ): Promise<{ signature: string }> {\n const signer = await this._getEthSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const result: SignerEvmSignature = await signer.signTypedData(\n path,\n params.data,\n );\n const rHex = stripHex(result.r).padStart(64, '0');\n const sHex = stripHex(result.s).padStart(64, '0');\n const vHex = result.v.toString(16).padStart(2, '0');\n return { signature: `0x${rHex}${sHex}${vHex}` };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — BTC methods\n // ---------------------------------------------------------------------------\n\n private async _btcGetAddress(\n sessionId: string,\n params: BtcGetAddressCallParams,\n ): Promise<{ address: string; path: string }> {\n const btcSigner = await this._createBtcSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const { DefaultWallet, DefaultDescriptorTemplate } = await import(\n '@ledgerhq/device-signer-kit-bitcoin'\n );\n const purpose = path.split('/')[0]?.replace(\"'\", '');\n let template = DefaultDescriptorTemplate.NATIVE_SEGWIT;\n if (purpose === '44') template = DefaultDescriptorTemplate.LEGACY;\n else if (purpose === '49')\n template = DefaultDescriptorTemplate.NESTED_SEGWIT;\n else if (purpose === '86') template = DefaultDescriptorTemplate.TAPROOT;\n const wallet = new DefaultWallet(path, template);\n\n const result = await btcSigner.getWalletAddress(wallet, 0, {\n checkOnDevice: params.showOnDevice ?? false,\n change: false,\n });\n return { address: result.address, path: params.path };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _btcGetPublicKey(\n sessionId: string,\n params: BtcGetPublicKeyCallParams,\n ): Promise<{ xpub: string; path: string }> {\n const btcSigner = await this._createBtcSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n const xpub = await btcSigner.getExtendedPublicKey(path, {\n checkOnDevice: params.showOnDevice ?? false,\n });\n return { xpub, path: params.path };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _btcSignTransaction(\n _sessionId: string,\n _params: BtcSignTransactionCallParams,\n ): Promise<never> {\n throw new Error('LedgerWebHidConnector: btcSignTransaction is not yet implemented');\n }\n\n private async _btcSignMessage(\n _sessionId: string,\n _params: BtcSignMessageCallParams,\n ): Promise<never> {\n throw new Error('LedgerWebHidConnector: btcSignMessage is not yet implemented');\n }\n\n private async _btcGetMasterFingerprint(\n sessionId: string,\n params?: { skipOpenApp?: boolean },\n ): Promise<{ masterFingerprint: string }> {\n const btcSigner = await this._createBtcSigner(sessionId);\n\n try {\n const fingerprint: Uint8Array = await btcSigner.getMasterFingerprint({\n skipOpenApp: params?.skipOpenApp,\n });\n // Convert Uint8Array to hex string\n const hex = Array.from(fingerprint)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n return { masterFingerprint: hex };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — SOL methods\n // ---------------------------------------------------------------------------\n\n private async _solGetAddress(\n sessionId: string,\n params: SolGetAddressCallParams,\n ): Promise<{ address: string; path: string }> {\n const solSigner = await this._createSolSigner(sessionId);\n const path = normalizePath(params.path);\n\n try {\n // Ledger Solana signer returns a base58-encoded Ed25519 public key (= Solana address)\n const publicKey = await solSigner.getAddress(path, {\n checkOnDevice: params.showOnDevice ?? false,\n });\n return { address: publicKey, path: params.path };\n } catch (err) {\n this._invalidateSession(sessionId);\n throw this._wrapError(err);\n }\n }\n\n private async _solSignTransaction(\n _sessionId: string,\n _params: SolSignTransactionCallParams,\n ): Promise<never> {\n throw new Error('LedgerWebHidConnector: solSignTransaction is not yet implemented');\n }\n\n private async _solSignMessage(\n _sessionId: string,\n _params: SolSignMessageCallParams,\n ): Promise<never> {\n throw new Error('LedgerWebHidConnector: solSignMessage is not yet implemented');\n }\n\n // ---------------------------------------------------------------------------\n // Private — DMK / Manager lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Lazily create or return the DMK instance.\n * If a DMK was provided via constructor, it is used directly.\n * Otherwise, one is created via dynamic import of the Ledger SDK.\n */\n private async _getOrCreateDmk(): Promise<IDmk> {\n if (this._dmk) return this._dmk;\n\n if (this._providedDmk) {\n this._dmk = this._providedDmk;\n return this._dmk;\n }\n\n const { DeviceManagementKitBuilder } = await import(\n '@ledgerhq/device-management-kit'\n );\n const { webHidTransportFactory } = await import(\n '@ledgerhq/device-transport-kit-web-hid'\n );\n\n this._dmk = new DeviceManagementKitBuilder()\n .addTransport(webHidTransportFactory)\n .build() as unknown as IDmk;\n\n return this._dmk;\n }\n\n private _initManagers(dmk: IDmk): void {\n this._dmk = dmk;\n this._deviceManager = new LedgerDeviceManager(dmk);\n this._signerManager = new SignerManager(dmk);\n }\n\n private async _getDeviceManager(): Promise<LedgerDeviceManager> {\n if (this._deviceManager) return this._deviceManager;\n\n const dmk = await this._getOrCreateDmk();\n this._initManagers(dmk);\n return this._deviceManager!;\n }\n\n private async _getEthSigner(sessionId: string) {\n if (!this._signerManager) {\n const dmk = await this._getOrCreateDmk();\n this._initManagers(dmk);\n }\n const signer = await this._signerManager!.getOrCreate(sessionId);\n\n // Wire up interaction events (open-app, unlock, verify-address, sign, etc.)\n signer.onInteraction = (interaction: string) => {\n this._emit('ui-event', {\n type: interaction,\n payload: { sessionId },\n });\n };\n\n return signer;\n }\n\n private async _createBtcSigner(sessionId: string): Promise<SignerBtc> {\n const dmk = await this._getOrCreateDmk();\n const { SignerBtcBuilder } = await import(\n '@ledgerhq/device-signer-kit-bitcoin'\n );\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sdkSigner = new SignerBtcBuilder({\n dmk: dmk as any,\n sessionId,\n }).build();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new SignerBtc(sdkSigner as any);\n }\n\n private async _createSolSigner(sessionId: string): Promise<SignerSol> {\n const dmk = await this._getOrCreateDmk();\n const { SignerSolanaBuilder } = await import(\n '@ledgerhq/device-signer-kit-solana'\n );\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sdkSigner = new SignerSolanaBuilder({\n dmk: dmk as any,\n sessionId,\n }).build();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new SignerSol(sdkSigner as any);\n }\n\n private _invalidateSession(sessionId: string): void {\n this._signerManager?.invalidate(sessionId);\n }\n\n private _resetManagers(): void {\n this._signerManager?.clearAll();\n this._deviceManager?.dispose();\n this._deviceManager = null;\n this._signerManager = null;\n this._dmk = null;\n }\n\n // ---------------------------------------------------------------------------\n // Private — Events\n // ---------------------------------------------------------------------------\n\n private _emit<K extends ConnectorEventType>(\n event: K,\n data: ConnectorEventMap[K],\n ): void {\n const handlers = this._eventHandlers.get(event);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(data);\n } catch {\n // Don't let listener errors break the connector\n }\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — Error handling\n // ---------------------------------------------------------------------------\n\n private _wrapError(err: unknown): Error {\n const mapped = mapLedgerError(err);\n const error = new Error(mapped.message);\n (error as any).code = mapped.code;\n return error;\n }\n}\n","import type { IConnector } from '@bytezhang/hardware-wallet-core';\nimport type { IDmk } from '@bytezhang/ledger-adapter';\n\nimport {\n LedgerWebHidConnector,\n} from './LedgerWebHidConnector';\nimport type { LedgerWebHidConnectorOptions } from './LedgerWebHidConnector';\n\nexport { LedgerWebHidConnector };\nexport type { LedgerWebHidConnectorOptions };\n\n/**\n * Create a LedgerWebHidConnector.\n *\n * @param dmk - Optional pre-built DMK instance. If omitted, the connector\n * will lazily create one using `@ledgerhq/device-management-kit`\n * and `@ledgerhq/device-transport-kit-web-hid`.\n */\nexport function createLedgerWebHidConnector(dmk?: IDmk): IConnector {\n return new LedgerWebHidConnector({ dmk });\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytezhang/hardware-ledger-connector-webhid",
3
- "version": "0.0.4",
3
+ "version": "0.0.8",
4
4
  "description": "IConnector implementation for Ledger hardware wallets via WebHID (DMK)",
5
5
  "author": "OneKey",
6
6
  "license": "MIT",
@@ -51,17 +51,22 @@
51
51
  "@ledgerhq/device-management-kit": "^1.1.0",
52
52
  "@ledgerhq/device-signer-kit-ethereum": "^1.9.0",
53
53
  "@ledgerhq/device-signer-kit-bitcoin": "^1.0.0",
54
+ "@ledgerhq/device-signer-kit-solana": "^1.7.0",
54
55
  "@ledgerhq/device-transport-kit-web-hid": "^1.0.0"
55
56
  },
56
57
  "peerDependenciesMeta": {
57
58
  "@ledgerhq/device-signer-kit-bitcoin": {
58
59
  "optional": true
60
+ },
61
+ "@ledgerhq/device-signer-kit-solana": {
62
+ "optional": true
59
63
  }
60
64
  },
61
65
  "devDependencies": {
62
66
  "@ledgerhq/device-management-kit": "^1.1.0",
63
67
  "@ledgerhq/device-signer-kit-ethereum": "^1.9.0",
64
68
  "@ledgerhq/device-signer-kit-bitcoin": "^1.0.0",
69
+ "@ledgerhq/device-signer-kit-solana": "^1.7.0",
65
70
  "@ledgerhq/device-transport-kit-web-hid": "^1.0.0",
66
71
  "rimraf": "^5.0.0"
67
72
  }
package/dist/index.d.mts DELETED
@@ -1,76 +0,0 @@
1
- import { IConnector, ConnectorDevice, ConnectorSession, ConnectorEventType, ConnectorEventMap } from '@bytezhang/hardware-wallet-core';
2
- import { IDmk } from '@bytezhang/ledger-adapter';
3
-
4
- interface LedgerWebHidConnectorOptions {
5
- /**
6
- * Pre-built DMK instance. If not provided, a DMK will be created
7
- * lazily on first use via `@ledgerhq/device-management-kit` and
8
- * `@ledgerhq/device-transport-kit-web-hid`.
9
- */
10
- dmk?: IDmk;
11
- }
12
- /**
13
- * IConnector implementation for Ledger hardware wallets via WebHID.
14
- *
15
- * Wraps the Ledger DMK (Device Management Kit) and signer kits into
16
- * the unified IConnector interface used by the adapter layer.
17
- *
18
- * Design:
19
- * - Constructor accepts an optional pre-built DMK instance (or creates one lazily).
20
- * - searchDevices() uses DMK's listenToAvailableDevices() observable.
21
- * - connect() calls dmk.connect({ device }), returns a ConnectorSession.
22
- * - call() dispatches to chain-specific signer methods (EVM, BTC).
23
- * - Internally uses LedgerDeviceManager for session tracking and
24
- * SignerManager for per-session signer caching.
25
- */
26
- declare class LedgerWebHidConnector implements IConnector {
27
- private _deviceManager;
28
- private _signerManager;
29
- private _dmk;
30
- private readonly _eventHandlers;
31
- private readonly _providedDmk;
32
- constructor(options?: LedgerWebHidConnectorOptions);
33
- searchDevices(): Promise<ConnectorDevice[]>;
34
- connect(deviceId?: string): Promise<ConnectorSession>;
35
- disconnect(sessionId: string): Promise<void>;
36
- call(sessionId: string, method: string, params: unknown): Promise<unknown>;
37
- cancel(_sessionId: string): Promise<void>;
38
- uiResponse(_response: {
39
- type: string;
40
- payload: unknown;
41
- }): void;
42
- on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
43
- off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
44
- reset(): void;
45
- private _evmGetAddress;
46
- private _evmSignTransaction;
47
- private _evmSignMessage;
48
- private _evmSignTypedData;
49
- private _btcGetAddress;
50
- private _btcGetPublicKey;
51
- /**
52
- * Lazily create or return the DMK instance.
53
- * If a DMK was provided via constructor, it is used directly.
54
- * Otherwise, one is created via dynamic import of the Ledger SDK.
55
- */
56
- private _getOrCreateDmk;
57
- private _initManagers;
58
- private _getDeviceManager;
59
- private _getEthSigner;
60
- private _createBtcSigner;
61
- private _invalidateSession;
62
- private _resetManagers;
63
- private _emit;
64
- private _wrapError;
65
- }
66
-
67
- /**
68
- * Create a LedgerWebHidConnector.
69
- *
70
- * @param dmk - Optional pre-built DMK instance. If omitted, the connector
71
- * will lazily create one using `@ledgerhq/device-management-kit`
72
- * and `@ledgerhq/device-transport-kit-web-hid`.
73
- */
74
- declare function createLedgerWebHidConnector(dmk?: IDmk): IConnector;
75
-
76
- export { LedgerWebHidConnector, type LedgerWebHidConnectorOptions, createLedgerWebHidConnector };
package/dist/index.d.ts DELETED
@@ -1,76 +0,0 @@
1
- import { IConnector, ConnectorDevice, ConnectorSession, ConnectorEventType, ConnectorEventMap } from '@bytezhang/hardware-wallet-core';
2
- import { IDmk } from '@bytezhang/ledger-adapter';
3
-
4
- interface LedgerWebHidConnectorOptions {
5
- /**
6
- * Pre-built DMK instance. If not provided, a DMK will be created
7
- * lazily on first use via `@ledgerhq/device-management-kit` and
8
- * `@ledgerhq/device-transport-kit-web-hid`.
9
- */
10
- dmk?: IDmk;
11
- }
12
- /**
13
- * IConnector implementation for Ledger hardware wallets via WebHID.
14
- *
15
- * Wraps the Ledger DMK (Device Management Kit) and signer kits into
16
- * the unified IConnector interface used by the adapter layer.
17
- *
18
- * Design:
19
- * - Constructor accepts an optional pre-built DMK instance (or creates one lazily).
20
- * - searchDevices() uses DMK's listenToAvailableDevices() observable.
21
- * - connect() calls dmk.connect({ device }), returns a ConnectorSession.
22
- * - call() dispatches to chain-specific signer methods (EVM, BTC).
23
- * - Internally uses LedgerDeviceManager for session tracking and
24
- * SignerManager for per-session signer caching.
25
- */
26
- declare class LedgerWebHidConnector implements IConnector {
27
- private _deviceManager;
28
- private _signerManager;
29
- private _dmk;
30
- private readonly _eventHandlers;
31
- private readonly _providedDmk;
32
- constructor(options?: LedgerWebHidConnectorOptions);
33
- searchDevices(): Promise<ConnectorDevice[]>;
34
- connect(deviceId?: string): Promise<ConnectorSession>;
35
- disconnect(sessionId: string): Promise<void>;
36
- call(sessionId: string, method: string, params: unknown): Promise<unknown>;
37
- cancel(_sessionId: string): Promise<void>;
38
- uiResponse(_response: {
39
- type: string;
40
- payload: unknown;
41
- }): void;
42
- on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
43
- off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
44
- reset(): void;
45
- private _evmGetAddress;
46
- private _evmSignTransaction;
47
- private _evmSignMessage;
48
- private _evmSignTypedData;
49
- private _btcGetAddress;
50
- private _btcGetPublicKey;
51
- /**
52
- * Lazily create or return the DMK instance.
53
- * If a DMK was provided via constructor, it is used directly.
54
- * Otherwise, one is created via dynamic import of the Ledger SDK.
55
- */
56
- private _getOrCreateDmk;
57
- private _initManagers;
58
- private _getDeviceManager;
59
- private _getEthSigner;
60
- private _createBtcSigner;
61
- private _invalidateSession;
62
- private _resetManagers;
63
- private _emit;
64
- private _wrapError;
65
- }
66
-
67
- /**
68
- * Create a LedgerWebHidConnector.
69
- *
70
- * @param dmk - Optional pre-built DMK instance. If omitted, the connector
71
- * will lazily create one using `@ledgerhq/device-management-kit`
72
- * and `@ledgerhq/device-transport-kit-web-hid`.
73
- */
74
- declare function createLedgerWebHidConnector(dmk?: IDmk): IConnector;
75
-
76
- export { LedgerWebHidConnector, type LedgerWebHidConnectorOptions, createLedgerWebHidConnector };