@bytezhang/hardware-ledger-connector-webhid 0.0.4 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +15 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -48,6 +48,7 @@ declare class LedgerWebHidConnector implements IConnector {
|
|
|
48
48
|
private _evmSignTypedData;
|
|
49
49
|
private _btcGetAddress;
|
|
50
50
|
private _btcGetPublicKey;
|
|
51
|
+
private _btcGetMasterFingerprint;
|
|
51
52
|
/**
|
|
52
53
|
* Lazily create or return the DMK instance.
|
|
53
54
|
* If a DMK was provided via constructor, it is used directly.
|
package/dist/index.d.ts
CHANGED
|
@@ -48,6 +48,7 @@ declare class LedgerWebHidConnector implements IConnector {
|
|
|
48
48
|
private _evmSignTypedData;
|
|
49
49
|
private _btcGetAddress;
|
|
50
50
|
private _btcGetPublicKey;
|
|
51
|
+
private _btcGetMasterFingerprint;
|
|
51
52
|
/**
|
|
52
53
|
* Lazily create or return the DMK instance.
|
|
53
54
|
* If a DMK was provided via constructor, it is used directly.
|
package/dist/index.js
CHANGED
|
@@ -185,6 +185,8 @@ var LedgerWebHidConnector = class {
|
|
|
185
185
|
return this._btcGetAddress(sessionId, params);
|
|
186
186
|
case "btcGetPublicKey":
|
|
187
187
|
return this._btcGetPublicKey(sessionId, params);
|
|
188
|
+
case "btcGetMasterFingerprint":
|
|
189
|
+
return this._btcGetMasterFingerprint(sessionId, params);
|
|
188
190
|
default:
|
|
189
191
|
throw new Error(`LedgerWebHidConnector: unknown method "${method}"`);
|
|
190
192
|
}
|
|
@@ -317,6 +319,19 @@ var LedgerWebHidConnector = class {
|
|
|
317
319
|
throw this._wrapError(err);
|
|
318
320
|
}
|
|
319
321
|
}
|
|
322
|
+
async _btcGetMasterFingerprint(sessionId, params) {
|
|
323
|
+
const btcSigner = await this._createBtcSigner(sessionId);
|
|
324
|
+
try {
|
|
325
|
+
const fingerprint = await btcSigner.getMasterFingerprint({
|
|
326
|
+
skipOpenApp: params?.skipOpenApp
|
|
327
|
+
});
|
|
328
|
+
const hex = Array.from(fingerprint).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
329
|
+
return { masterFingerprint: hex };
|
|
330
|
+
} catch (err) {
|
|
331
|
+
this._invalidateSession(sessionId);
|
|
332
|
+
throw this._wrapError(err);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
320
335
|
// ---------------------------------------------------------------------------
|
|
321
336
|
// Private — DMK / Manager lifecycle
|
|
322
337
|
// ---------------------------------------------------------------------------
|
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 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 case 'btcGetMasterFingerprint':\n return this._btcGetMasterFingerprint(sessionId, params as { skipOpenApp?: boolean } | undefined);\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 _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 — 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,KAAK;AACH,eAAO,KAAK,yBAAyB,WAAW,MAA+C;AAAA,MACjG;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,EAEA,MAAc,yBACZ,WACA,QACwC;AACxC,UAAM,YAAY,MAAM,KAAK,iBAAiB,SAAS;AAEvD,QAAI;AACF,YAAM,cAA0B,MAAM,UAAU,qBAAqB;AAAA,QACnE,aAAa,QAAQ;AAAA,MACvB,CAAC;AAED,YAAM,MAAM,MAAM,KAAK,WAAW,EAC/B,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AACV,aAAO,EAAE,mBAAmB,IAAI;AAAA,IAClC,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;;;ADxlBO,SAAS,4BAA4B,KAAwB;AAClE,SAAO,IAAI,sBAAsB,EAAE,IAAI,CAAC;AAC1C;","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -153,6 +153,8 @@ var LedgerWebHidConnector = class {
|
|
|
153
153
|
return this._btcGetAddress(sessionId, params);
|
|
154
154
|
case "btcGetPublicKey":
|
|
155
155
|
return this._btcGetPublicKey(sessionId, params);
|
|
156
|
+
case "btcGetMasterFingerprint":
|
|
157
|
+
return this._btcGetMasterFingerprint(sessionId, params);
|
|
156
158
|
default:
|
|
157
159
|
throw new Error(`LedgerWebHidConnector: unknown method "${method}"`);
|
|
158
160
|
}
|
|
@@ -285,6 +287,19 @@ var LedgerWebHidConnector = class {
|
|
|
285
287
|
throw this._wrapError(err);
|
|
286
288
|
}
|
|
287
289
|
}
|
|
290
|
+
async _btcGetMasterFingerprint(sessionId, params) {
|
|
291
|
+
const btcSigner = await this._createBtcSigner(sessionId);
|
|
292
|
+
try {
|
|
293
|
+
const fingerprint = await btcSigner.getMasterFingerprint({
|
|
294
|
+
skipOpenApp: params?.skipOpenApp
|
|
295
|
+
});
|
|
296
|
+
const hex = Array.from(fingerprint).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
297
|
+
return { masterFingerprint: hex };
|
|
298
|
+
} catch (err) {
|
|
299
|
+
this._invalidateSession(sessionId);
|
|
300
|
+
throw this._wrapError(err);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
288
303
|
// ---------------------------------------------------------------------------
|
|
289
304
|
// Private — DMK / Manager lifecycle
|
|
290
305
|
// ---------------------------------------------------------------------------
|
package/dist/index.mjs.map
CHANGED
|
@@ -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 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 case 'btcGetMasterFingerprint':\n return this._btcGetMasterFingerprint(sessionId, params as { skipOpenApp?: boolean } | undefined);\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 _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 — 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":[]}
|