0
# Device Discovery and Connection
1
2
Core functionality for discovering available Ledger devices and establishing transport connections. This includes both one-time device listing and continuous monitoring of device availability through the observer pattern.
3
4
## Capabilities
5
6
### Platform Support Check
7
8
Determines if the transport implementation is supported on the current platform/browser environment.
9
10
```typescript { .api }
11
/**
12
* Statically check if a transport is supported on the user's platform/browser
13
* @returns Promise resolving to true if supported, false otherwise
14
*/
15
static isSupported(): Promise<boolean>;
16
```
17
18
**Usage Example:**
19
20
```javascript
21
import MyTransport from "./my-transport";
22
23
const supported = await MyTransport.isSupported();
24
if (!supported) {
25
throw new Error("This transport is not supported on your platform");
26
}
27
```
28
29
### Device Listing
30
31
Lists all currently available device descriptors in a single snapshot. For real-time device monitoring, use `listen()` instead.
32
33
```typescript { .api }
34
/**
35
* List once all available descriptors. For better granularity, use listen()
36
* @returns Promise of array of descriptors that can be passed to open()
37
*/
38
static list(): Promise<Array<Descriptor>>;
39
```
40
41
**Usage Example:**
42
43
```javascript
44
import MyTransport from "./my-transport";
45
46
// Get all currently connected devices
47
const descriptors = await MyTransport.list();
48
console.log(`Found ${descriptors.length} devices`);
49
50
for (const descriptor of descriptors) {
51
try {
52
const transport = await MyTransport.open(descriptor);
53
// Use transport...
54
await transport.close();
55
} catch (error) {
56
console.error("Failed to open device:", error);
57
}
58
}
59
```
60
61
### Device Event Monitoring
62
63
Continuously monitors for device connection and disconnection events using the observer pattern. This is the recommended approach for responsive device management.
64
65
```typescript { .api }
66
/**
67
* Listen to all device events for a given Transport using observer pattern
68
* @param observer Object with next, error, and complete functions
69
* @returns Subscription object to unsubscribe from events
70
*/
71
static listen(observer: Observer<DescriptorEvent<Descriptor>>): Subscription;
72
```
73
74
**Usage Example:**
75
76
```javascript
77
import MyTransport from "./my-transport";
78
79
const subscription = MyTransport.listen({
80
next: (event) => {
81
if (event.type === "add") {
82
console.log("Device connected:", event.deviceModel?.productName);
83
// Open the device
84
MyTransport.open(event.descriptor).then(transport => {
85
// Device is ready to use
86
console.log("Transport opened successfully");
87
});
88
} else if (event.type === "remove") {
89
console.log("Device disconnected");
90
}
91
},
92
error: (error) => {
93
console.error("Device monitoring error:", error);
94
},
95
complete: () => {
96
console.log("Device monitoring completed");
97
}
98
});
99
100
// Stop listening after 30 seconds
101
setTimeout(() => {
102
subscription.unsubscribe();
103
}, 30000);
104
```
105
106
### Device Connection
107
108
Opens a transport connection to a specific device using its descriptor.
109
110
```typescript { .api }
111
/**
112
* Attempt to create a Transport instance with a descriptor
113
* @param descriptor The descriptor to open the transport with
114
* @param timeout Optional timeout in milliseconds
115
* @returns Promise of Transport instance
116
*/
117
static open(descriptor: Descriptor, timeout?: number): Promise<Transport<Descriptor>>;
118
```
119
120
**Usage Example:**
121
122
```javascript
123
import MyTransport from "./my-transport";
124
125
// Assuming you have a descriptor from list() or listen()
126
const transport = await MyTransport.open(descriptor, 5000); // 5 second timeout
127
128
try {
129
// Set up the transport
130
transport.setScrambleKey("BTC");
131
132
// Use the transport for communication
133
const response = await transport.send(0xB0, 0x01, 0x00, 0x00);
134
135
} finally {
136
// Always close the transport
137
await transport.close();
138
}
139
```
140
141
### Quick Device Creation
142
143
Convenience method that combines listening and opening the first available device. This is a simplified alternative to manually using `listen()` and `open()`.
144
145
```typescript { .api }
146
/**
147
* Create transport by opening the first descriptor available or throw if none found
148
* @param openTimeout Timeout for opening the device (default: 3000ms)
149
* @param listenTimeout Timeout for finding a device (optional)
150
* @returns Promise of Transport instance
151
*/
152
static create(openTimeout?: number = 3000, listenTimeout?: number): Promise<Transport<Descriptor>>;
153
```
154
155
**Usage Example:**
156
157
```javascript
158
import MyTransport from "./my-transport";
159
160
try {
161
// Wait up to 10 seconds to find a device, then 5 seconds to open it
162
const transport = await MyTransport.create(5000, 10000);
163
164
console.log("Connected to device:", transport.deviceModel?.productName);
165
166
// Use the transport
167
transport.setScrambleKey("BTC");
168
const response = await transport.send(0xB0, 0x01, 0x00, 0x00);
169
170
await transport.close();
171
172
} catch (error) {
173
if (error.id === "NoDeviceFound") {
174
console.error("No Ledger device found");
175
} else if (error.id === "ListenTimeout") {
176
console.error("Timeout waiting for device");
177
} else {
178
console.error("Failed to create transport:", error);
179
}
180
}
181
```
182
183
## Types
184
185
### DescriptorEvent
186
187
```typescript { .api }
188
interface DescriptorEvent<Descriptor> {
189
/** Event type: "add" when device connects, "remove" when disconnects */
190
type: "add" | "remove";
191
/** Descriptor that can be passed to open() */
192
descriptor: Descriptor;
193
/** Device model information (Nano S, Nano X, Blue) */
194
deviceModel?: DeviceModel | null;
195
/** Transport-specific device information */
196
device?: Device;
197
}
198
```
199
200
### Observer
201
202
```typescript { .api }
203
interface Observer<Event> {
204
/** Called when a new event occurs */
205
next(event: Event): void;
206
/** Called when an error occurs */
207
error(e: any): void;
208
/** Called when observation completes */
209
complete(): void;
210
}
211
```
212
213
### Subscription
214
215
```typescript { .api }
216
interface Subscription {
217
/** Stop listening to events */
218
unsubscribe(): void;
219
}
220
```
221
222
## Static Error Messages
223
224
The Transport class provides predefined error messages for common scenarios:
225
226
```typescript { .api }
227
class Transport<Descriptor> {
228
/** Error message for device not found scenarios */
229
static ErrorMessage_NoDeviceFound: "No Ledger device found";
230
231
/** Error message for listen timeout scenarios */
232
static ErrorMessage_ListenTimeout: "No Ledger device found (timeout)";
233
}
234
```
235
236
## Error Handling
237
238
Device management operations may throw various errors:
239
240
- **NoDeviceFound**: No devices available when calling `create()`
241
- **ListenTimeout**: Timeout reached while waiting for devices
242
- **TransportOpenUserCancelled**: User cancelled the device selection
243
- **TransportInterfaceNotAvailable**: Transport interface not available on platform