Skip to content

feat(wallets): add WebUSB diagnostics module#437

Open
bensig wants to merge 1 commit intocaravan-bitcoin:mainfrom
bensig:feat/webhid-diagnostics
Open

feat(wallets): add WebUSB diagnostics module#437
bensig wants to merge 1 commit intocaravan-bitcoin:mainfrom
bensig:feat/webhid-diagnostics

Conversation

@bensig
Copy link
Contributor

@bensig bensig commented Dec 30, 2025

Summary

Add a new webusb-diagnostics module to help users troubleshoot Ledger connection issues.

This was inspired by real-world debugging where connection failures gave cryptic errors. The module provides functions to diagnose common issues like:

  • Unsupported browsers (Safari, Firefox)
  • Insecure context (HTTP instead of HTTPS)
  • Missing device permissions
  • Device already in use by another application

New exports

Function Description
detectBrowser() Identifies browser name/version and WebUSB/WebHID support
isWebUSBAvailable() Checks if WebUSB API is available
isSecureContext() Checks if page is served over HTTPS
getConnectedLedgerDevices() Lists connected Ledger devices with their status
runWebUSBDiagnostics() Comprehensive diagnostics returning issues and steps
getDiagnosticReport() Human-readable diagnostic report string

Example usage

import { runWebUSBDiagnostics, getDiagnosticReport } from "@caravan/wallets";

// Get comprehensive diagnostics
const diagnostics = await runWebUSBDiagnostics();
if (diagnostics.issues.length > 0) {
  console.log("Issues found:", diagnostics.issues);
  console.log("Steps:", diagnostics.troubleshootingSteps);
}

// Or get a formatted report string
const report = await getDiagnosticReport();
console.log(report);

Test plan

  • 20 tests covering all diagnostic functions
  • Browser detection tests (Chrome, Firefox, Safari, Edge)
  • WebUSB availability tests
  • Secure context tests
  • Device filtering and error handling tests
  • Diagnostic report generation tests

Add new webusb-diagnostics module with functions to help users
troubleshoot Ledger connection issues:

- detectBrowser() - Identifies browser and WebUSB/WebHID support
- isWebUSBAvailable() - Checks if WebUSB API is available
- isSecureContext() - Checks if page is served over HTTPS
- getConnectedLedgerDevices() - Lists connected Ledger devices
- runWebUSBDiagnostics() - Comprehensive diagnostics
- getDiagnosticReport() - Human-readable diagnostic report

Includes 20 tests covering browser detection, WebUSB availability,
secure context checks, and diagnostic report generation.
@changeset-bot
Copy link

changeset-bot bot commented Dec 30, 2025

🦋 Changeset detected

Latest commit: 129a066

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@caravan/wallets Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Dec 30, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
caravan-coordinator Ready Ready Preview, Comment Dec 30, 2025 8:05pm

/**
* Ledger USB vendor ID
*/
const LEDGER_VENDOR_ID = 0x2c97;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move this into ledger.ts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

presumably this could be used for other vendors too

* Checks if the page is running in a secure context (required for WebUSB).
*/
export function isSecureContext(): boolean {
return typeof window !== "undefined" && window.isSecureContext === true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this not work?

Suggested change
return typeof window !== "undefined" && window.isSecureContext === true;
return typeof window !== "undefined" && window.isSecureContext ;

Comment on lines +130 to +138
export async function getConnectedLedgerDevices(): Promise<LedgerDeviceInfo[]> {
if (!isWebUSBAvailable()) {
return [];
}

try {
const devices = await (navigator as any).usb.getDevices();
return devices
.filter((d: any) => d.vendorId === LEDGER_VENDOR_ID)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about

Suggested change
export async function getConnectedLedgerDevices(): Promise<LedgerDeviceInfo[]> {
if (!isWebUSBAvailable()) {
return [];
}
try {
const devices = await (navigator as any).usb.getDevices();
return devices
.filter((d: any) => d.vendorId === LEDGER_VENDOR_ID)
export async function getCOnnectedDevices(vendorId): Promise<LedgerDeviceInfo[]> {
if (!isWebUSBAvailable()) {
return [];
}
try {
const devices = await (navigator as any).usb.getDevices();
return devices
.filter((d: any) => d.vendorId === vendorId)

let permissionGranted = false;

if (webUSBAvailable) {
devicesFound = await getConnectedLedgerDevices();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and then we can either make this even more generic or run through a list of vendorIds (which is just one right now).

/**
* Returns a human-readable diagnostic report as a string.
*/
export async function getDiagnosticReport(): Promise<string> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

neat!

@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

This pull request has been inactive for 30 days and has been marked as stale. It will be closed in 7 days if no further activity occurs. To keep this PR open, add the "long-lived" label or comment on it.

@github-actions github-actions bot added the stale label Feb 9, 2026
@bucko13
Copy link
Contributor

bucko13 commented Feb 9, 2026

@bensig curious if this was something you were interested in maintaining? I think this would be a great addition to the package if you're interested!

@github-actions github-actions bot removed the stale label Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants