From c3deb47808930581a25ae5e4ab51f1fc874dae88 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Mon, 18 May 2026 06:40:59 -0700 Subject: [PATCH] Extract disconnect function. --- src/lib/ledger/disconnect.ts | 19 +++++++++++++++++++ src/lib/ledger/index.ts | 36 ++++++++++++------------------------ 2 files changed, 31 insertions(+), 24 deletions(-) create mode 100644 src/lib/ledger/disconnect.ts diff --git a/src/lib/ledger/disconnect.ts b/src/lib/ledger/disconnect.ts new file mode 100644 index 0000000..4d32f9f --- /dev/null +++ b/src/lib/ledger/disconnect.ts @@ -0,0 +1,19 @@ +//! SPDX-FileCopyrightText: 2025 Chris Duncan +//! SPDX-License-Identifier: GPL-3.0-or-later + +import { ledgerVendorId } from '.' + +export async function _disconnect (): Promise { + try { + const hidDevices = await navigator?.hid?.getDevices?.() ?? [] + const usbDevices = await navigator?.usb?.getDevices?.() ?? [] + const devices = [...hidDevices, ...usbDevices] + .filter(device => device.vendorId === ledgerVendorId) + await Promise.allSettled(devices.map(device => device.forget?.() ?? Promise.resolve())) + } catch (err) { + console.warn('Ledger.disconnect()', err) + } finally { + await new Promise(r => setTimeout(r, 5000)) + console.log('Transient user activation period timed out') + } +} diff --git a/src/lib/ledger/index.ts b/src/lib/ledger/index.ts index 50ae83b..3ed6997 100644 --- a/src/lib/ledger/index.ts +++ b/src/lib/ledger/index.ts @@ -17,6 +17,7 @@ import { queue } from './queue' import { signBlock, signNonce } from './sign' import { _open } from './open' import { _close } from './close' +import { _disconnect } from './disconnect' export type LedgerStatus = 'UNSUPPORTED' | 'DISCONNECTED' | 'BUSY' | 'LOCKED' | 'CONNECTED' export type LedgerTransport = typeof TransportHID | typeof TransportBLE | typeof TransportUSB @@ -52,6 +53,12 @@ export const DERIVATION_PATH: Uint8Array = new Uint8Array([ ...dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4) ]) +/** + * Vendor ID assigned to Ledger for HID and USB interfaces. + * https://github.com/LedgerHQ/ledger-live/blob/develop/libs/ledgerjs/packages/devices/src/index.ts#L164 + */ +export const ledgerVendorId: 0x2c97 = 0x2c97 + export const STATUS_CODES: Readonly> = Object.freeze({ ...Object.fromEntries(Object.entries(StatusCodes).map(([k, v]) => [+v, k])), 0x6807: 'APPLICATION_NOT_INSTALLED', @@ -111,14 +118,6 @@ export class Ledger { return true } - /** - * Vendor ID assigned to Ledger for HID and USB interfaces. - * https://github.com/LedgerHQ/ledger-live/blob/develop/libs/ledgerjs/packages/devices/src/index.ts#L164 - */ - static get ledgerVendorId (): 0x2c97 { - return 0x2c97 - } - /** * Status of the Ledger device connection. * @@ -179,20 +178,9 @@ export class Ledger { */ static async disconnect (): Promise { queue(async () => { - try { - this.#isPolling = false - const hidDevices = await navigator?.hid?.getDevices?.() ?? [] - const usbDevices = await navigator?.usb?.getDevices?.() ?? [] - const devices = [...hidDevices, ...usbDevices] - .filter(device => device.vendorId === this.ledgerVendorId) - await Promise.allSettled(devices.map(device => device.forget?.() ?? Promise.resolve())) - this.#setStatus('DISCONNECTED') - } catch (err) { - console.warn('Ledger.disconnect()', err) - } finally { - await new Promise(r => setTimeout(r, 5000)) - console.log('Transient user activation period timed out') - } + _disconnect() + this.#isPolling = false + this.#setStatus('DISCONNECTED') }) } @@ -380,9 +368,9 @@ export class Ledger { static async #poll (): Promise { try { const isHidPaired = (await navigator.hid?.getDevices?.() ?? []) - .some(device => device.vendorId === this.ledgerVendorId) + .some(device => device.vendorId === ledgerVendorId) const isUsbPaired = (await navigator.usb?.getDevices?.() ?? []) - .some(device => device.vendorId === this.ledgerVendorId) + .some(device => device.vendorId === ledgerVendorId) if ((this.#transport === TransportHID && isHidPaired) || (this.#transport === TransportUSB && isUsbPaired)) { await this.connect() -- 2.47.3