@ledgerhq/hw-transport-node-hid-singleton 6.30.2-nightly.1 → 6.30.2

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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @ledgerhq/hw-transport-node-hid-singleton@6.30.2-nightly.0 build /home/runner/work/ledger-live/ledger-live/libs/ledgerjs/packages/hw-transport-node-hid-singleton
2
+ > @ledgerhq/hw-transport-node-hid-singleton@6.30.2 build /home/runner/work/ledger-live/ledger-live/libs/ledgerjs/packages/hw-transport-node-hid-singleton
3
3
  > tsc && tsc -m ES6 --outDir lib-es
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,28 +1,24 @@
1
1
  # @ledgerhq/hw-transport-node-hid-singleton
2
2
 
3
- ## 6.30.2-nightly.1
3
+ ## 6.30.2
4
4
 
5
5
  ### Patch Changes
6
6
 
7
- - [#5749](https://github.com/LedgerHQ/ledger-live/pull/5749) [`eadebff`](https://github.com/LedgerHQ/ledger-live/commit/eadebff3fe58aef6a5befb033d5147afc49663d3) Thanks [@alexandremgo](https://github.com/alexandremgo)! - Fix: HID USB reconnection on LLD during the sync onboarding
8
-
9
- - Refactoring of the disconnect after inactivity of the transport implementation
10
- hw-transport-node-hid-singleton
11
- - Better logs and documentation
7
+ - [#5750](https://github.com/LedgerHQ/ledger-live/pull/5750) [`16b4d7a`](https://github.com/LedgerHQ/ledger-live/commit/16b4d7ab4702022d4967f3c054d3c62a76716947) Thanks [@aussedatlo](https://github.com/aussedatlo)! - Arrange verbosity and improve typing
12
8
 
13
- - Updated dependencies [[`eadebff`](https://github.com/LedgerHQ/ledger-live/commit/eadebff3fe58aef6a5befb033d5147afc49663d3)]:
14
- - @ledgerhq/hw-transport-node-hid-noevents@6.29.2-nightly.1
15
- - @ledgerhq/hw-transport@6.30.2-nightly.1
9
+ - Updated dependencies [[`16b4d7a`](https://github.com/LedgerHQ/ledger-live/commit/16b4d7ab4702022d4967f3c054d3c62a76716947)]:
10
+ - @ledgerhq/hw-transport@6.30.2
11
+ - @ledgerhq/hw-transport-node-hid-noevents@6.29.2
16
12
 
17
- ## 6.30.2-nightly.0
13
+ ## 6.30.2-next.0
18
14
 
19
15
  ### Patch Changes
20
16
 
21
17
  - [#5750](https://github.com/LedgerHQ/ledger-live/pull/5750) [`16b4d7a`](https://github.com/LedgerHQ/ledger-live/commit/16b4d7ab4702022d4967f3c054d3c62a76716947) Thanks [@aussedatlo](https://github.com/aussedatlo)! - Arrange verbosity and improve typing
22
18
 
23
19
  - Updated dependencies [[`16b4d7a`](https://github.com/LedgerHQ/ledger-live/commit/16b4d7ab4702022d4967f3c054d3c62a76716947)]:
24
- - @ledgerhq/hw-transport@6.30.2-nightly.0
25
- - @ledgerhq/hw-transport-node-hid-noevents@6.29.2-nightly.0
20
+ - @ledgerhq/hw-transport@6.30.2-next.0
21
+ - @ledgerhq/hw-transport-node-hid-noevents@6.29.2-next.0
26
22
 
27
23
  ## 6.30.1
28
24
 
package/README.md CHANGED
@@ -34,16 +34,14 @@ For a smooth and quick integration:
34
34
  * [Examples](#examples)
35
35
  * [exchange](#exchange)
36
36
  * [Parameters](#parameters-1)
37
- * [close](#close)
38
37
  * [isSupported](#issupported)
39
38
  * [list](#list)
40
39
  * [listen](#listen)
41
40
  * [Parameters](#parameters-2)
42
- * [setDisconnectAfterInactivityTimeout](#setdisconnectafterinactivitytimeout)
41
+ * [autoDisconnect](#autodisconnect)
43
42
  * [disconnect](#disconnect)
44
43
  * [open](#open)
45
44
  * [Parameters](#parameters-3)
46
- * [onDisconnect](#ondisconnect)
47
45
 
48
46
  ### TransportNodeHidSingleton
49
47
 
@@ -68,7 +66,7 @@ TransportNodeHid.create().then(transport => ...)
68
66
 
69
67
  #### exchange
70
68
 
71
- Exchanges with the device using APDU protocol
69
+ Exchange with the device using APDU protocol.
72
70
 
73
71
  ##### Parameters
74
72
 
@@ -76,15 +74,6 @@ Exchanges with the device using APDU protocol
76
74
 
77
75
  Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Buffer](https://nodejs.org/api/buffer.html)>** a promise of apdu response
78
76
 
79
- #### close
80
-
81
- Closes the transport instance by triggering a disconnection after some inactivity (no new `open`).
82
-
83
- Intentionally not disconnecting the device/closing the hid connection directly:
84
- The HID connection will only be closed after some inactivity.
85
-
86
- Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<void>**&#x20;
87
-
88
77
  #### isSupported
89
78
 
90
79
  #### list
@@ -97,18 +86,15 @@ Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/
97
86
 
98
87
  Returns **Subscription**&#x20;
99
88
 
100
- #### setDisconnectAfterInactivityTimeout
89
+ #### autoDisconnect
101
90
 
102
- Disconnects device from singleton instance after some inactivity (no new `open`).
91
+ convenience wrapper for auto-disconnect logic
103
92
 
104
- Currently, there is only one transport instance (for only one device connected via USB).
93
+ Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<void>**&#x20;
105
94
 
106
95
  #### disconnect
107
96
 
108
- Disconnects from the HID device associated to the transport singleton.
109
-
110
- If you want to try to re-use the same transport instance at the next action (when calling `open` again), you can use
111
- the transport instance `close` method: it will only enable a disconnect after some inactivity.
97
+ globally disconnect the transport singleton
112
98
 
113
99
  #### open
114
100
 
@@ -126,11 +112,3 @@ Legacy: `_descriptor` is needed to follow the Transport definition
126
112
  * `context` **TraceContext?**&#x20;
127
113
 
128
114
  Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[TransportNodeHidSingleton](#transportnodehidsingleton)>**&#x20;
129
-
130
- ### onDisconnect
131
-
132
- Disconnect event received from the transport instance.
133
-
134
- It could be after a disconnection coming from the HID library (e.g. device unplugged) or from the transport instance itself (e.g. close).
135
- Clearing the singleton instance.
136
- Currently, only 1 device at a time is supported.
@@ -3,7 +3,7 @@ import HID from "node-hid";
3
3
  import TransportNodeHidNoEvents from "@ledgerhq/hw-transport-node-hid-noevents";
4
4
  import type { Observer, DescriptorEvent, Subscription } from "@ledgerhq/hw-transport";
5
5
  import { TraceContext } from "@ledgerhq/logs";
6
- export type ListenDescriptorEvent = DescriptorEvent<string>;
6
+ export type ListenDescriptorEvent = DescriptorEvent<any>;
7
7
  /**
8
8
  * node-hid Transport implementation
9
9
  * @example
@@ -12,6 +12,7 @@ export type ListenDescriptorEvent = DescriptorEvent<string>;
12
12
  * TransportNodeHid.create().then(transport => ...)
13
13
  */
14
14
  export default class TransportNodeHidSingleton extends TransportNodeHidNoEvents {
15
+ preventAutoDisconnect: boolean;
15
16
  constructor(device: HID.HID, { context }?: {
16
17
  context?: TraceContext;
17
18
  });
@@ -26,21 +27,14 @@ export default class TransportNodeHidSingleton extends TransportNodeHidNoEvents
26
27
  /**
27
28
  */
28
29
  static listen: (observer: Observer<ListenDescriptorEvent>) => Subscription;
29
- static disconnectAfterInactivityTimeout: ReturnType<typeof setTimeout> | undefined;
30
- static clearDisconnectAfterInactivityTimeout(): void;
31
30
  /**
32
- * Disconnects device from singleton instance after some inactivity (no new `open`).
33
- *
34
- * Currently, there is only one transport instance (for only one device connected via USB).
31
+ * convenience wrapper for auto-disconnect logic
35
32
  */
36
- static setDisconnectAfterInactivityTimeout(): void;
33
+ static autoDisconnect(): Promise<void>;
37
34
  /**
38
- * Disconnects from the HID device associated to the transport singleton.
39
- *
40
- * If you want to try to re-use the same transport instance at the next action (when calling `open` again), you can use
41
- * the transport instance `close` method: it will only enable a disconnect after some inactivity.
35
+ * globally disconnect the transport singleton
42
36
  */
43
- static disconnect(): void;
37
+ static disconnect(): Promise<void>;
44
38
  /**
45
39
  * Connects to the first Ledger device connected via USB
46
40
  *
@@ -50,19 +44,14 @@ export default class TransportNodeHidSingleton extends TransportNodeHidNoEvents
50
44
  * Legacy: `_descriptor` is needed to follow the Transport definition
51
45
  */
52
46
  static open(_descriptor: string, _timeoutMs?: number, context?: TraceContext): Promise<TransportNodeHidSingleton>;
47
+ setAllowAutoDisconnect(allow: boolean): void;
53
48
  /**
54
- * Exchanges with the device using APDU protocol
49
+ * Exchange with the device using APDU protocol.
55
50
  *
56
51
  * @param apdu
57
52
  * @returns a promise of apdu response
58
53
  */
59
54
  exchange(apdu: Buffer): Promise<Buffer>;
60
- /**
61
- * Closes the transport instance by triggering a disconnection after some inactivity (no new `open`).
62
- *
63
- * Intentionally not disconnecting the device/closing the hid connection directly:
64
- * The HID connection will only be closed after some inactivity.
65
- */
66
55
  close(): Promise<void>;
67
56
  }
68
57
  //# sourceMappingURL=TransportNodeHid.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TransportNodeHid.d.ts","sourceRoot":"","sources":["../src/TransportNodeHid.ts"],"names":[],"mappings":";AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,wBAAwC,MAAM,0CAA0C,CAAC;AAChG,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAe,YAAY,EAAS,MAAM,gBAAgB,CAAC;AAWlE,MAAM,MAAM,qBAAqB,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AAE5D;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,OAAO,yBAA0B,SAAQ,wBAAwB;gBACjE,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,GAAE;QAAE,OAAO,CAAC,EAAE,YAAY,CAAA;KAAO;IAIzE;;OAEG;IACH,MAAM,CAAC,WAAW,yBAAwC;IAE1D;;OAEG;IACH,MAAM,CAAC,IAAI,qBAAiC;IAE5C;OACG;IACH,MAAM,CAAC,MAAM,aAAc,SAAS,qBAAqB,CAAC,KAAG,YAAY,CAqDvE;IAEF,MAAM,CAAC,gCAAgC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,SAAS,CAAC;IACnF,MAAM,CAAC,qCAAqC;IAM5C;;;;OAIG;IACH,MAAM,CAAC,mCAAmC;IAiB1C;;;;;OAKG;IACH,MAAM,CAAC,UAAU;IAsBjB;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,CACT,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,yBAAyB,CAAC;IAkErC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIvC;;;;;OAKG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAavB"}
1
+ {"version":3,"file":"TransportNodeHid.d.ts","sourceRoot":"","sources":["../src/TransportNodeHid.ts"],"names":[],"mappings":";AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,wBAAwC,MAAM,0CAA0C,CAAC;AAChG,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAe,YAAY,EAAO,MAAM,gBAAgB,CAAC;AAyBhE,MAAM,MAAM,qBAAqB,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,OAAO,yBAA0B,SAAQ,wBAAwB;IAC7E,qBAAqB,UAAS;gBAElB,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,GAAE;QAAE,OAAO,CAAC,EAAE,YAAY,CAAA;KAAO;IAIzE;;OAEG;IACH,MAAM,CAAC,WAAW,yBAAwC;IAE1D;;OAEG;IACH,MAAM,CAAC,IAAI,qBAAiC;IAE5C;OACG;IACH,MAAM,CAAC,MAAM,aAAc,SAAS,qBAAqB,CAAC,KAAG,YAAY,CAqDvE;IAEF;;OAEG;WACU,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5C;;OAEG;WACU,UAAU;IASvB;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,CACT,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,yBAAyB,CAAC;IAyCrC,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI5C;;;;;OAKG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAMvB"}
@@ -22,6 +22,15 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
25
34
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
36
  };
@@ -34,7 +43,17 @@ const errors_1 = require("@ledgerhq/errors");
34
43
  const listenDevices_1 = require("./listenDevices");
35
44
  const LOG_TYPE = "hid-verbose";
36
45
  let transportInstance = null;
37
- const DISCONNECT_AFTER_INACTIVITY_TIMEOUT_MS = 5000;
46
+ const DISCONNECT_TIMEOUT = 5000;
47
+ let disconnectTimeout;
48
+ const clearDisconnectTimeout = () => {
49
+ if (disconnectTimeout) {
50
+ clearTimeout(disconnectTimeout);
51
+ }
52
+ };
53
+ const setDisconnectTimeout = () => {
54
+ clearDisconnectTimeout();
55
+ disconnectTimeout = setTimeout(() => TransportNodeHidSingleton.autoDisconnect(), DISCONNECT_TIMEOUT);
56
+ };
38
57
  /**
39
58
  * node-hid Transport implementation
40
59
  * @example
@@ -45,56 +64,36 @@ const DISCONNECT_AFTER_INACTIVITY_TIMEOUT_MS = 5000;
45
64
  class TransportNodeHidSingleton extends hw_transport_node_hid_noevents_1.default {
46
65
  constructor(device, { context } = {}) {
47
66
  super(device, { context, logType: LOG_TYPE });
48
- }
49
- static clearDisconnectAfterInactivityTimeout() {
50
- if (TransportNodeHidSingleton.disconnectAfterInactivityTimeout) {
51
- clearTimeout(TransportNodeHidSingleton.disconnectAfterInactivityTimeout);
52
- }
67
+ this.preventAutoDisconnect = false;
53
68
  }
54
69
  /**
55
- * Disconnects device from singleton instance after some inactivity (no new `open`).
56
- *
57
- * Currently, there is only one transport instance (for only one device connected via USB).
70
+ * convenience wrapper for auto-disconnect logic
58
71
  */
59
- static setDisconnectAfterInactivityTimeout() {
60
- TransportNodeHidSingleton.clearDisconnectAfterInactivityTimeout();
61
- TransportNodeHidSingleton.disconnectAfterInactivityTimeout = setTimeout(() => {
62
- (0, logs_1.trace)({
63
- type: LOG_TYPE,
64
- message: "Disconnecting after inactivity, if not prevented",
65
- data: {
66
- hasInstance: Boolean(transportInstance),
67
- },
68
- });
69
- if (transportInstance) {
72
+ static autoDisconnect() {
73
+ return __awaiter(this, void 0, void 0, function* () {
74
+ if (transportInstance && !transportInstance.preventAutoDisconnect) {
75
+ (0, logs_1.log)("hid-verbose", "triggering auto disconnect");
70
76
  TransportNodeHidSingleton.disconnect();
71
77
  }
72
- }, DISCONNECT_AFTER_INACTIVITY_TIMEOUT_MS);
78
+ else if (transportInstance) {
79
+ // If we have disabled the auto-disconnect, try again in DISCONNECT_TIMEOUT
80
+ clearDisconnectTimeout();
81
+ setDisconnectTimeout();
82
+ }
83
+ });
73
84
  }
74
85
  /**
75
- * Disconnects from the HID device associated to the transport singleton.
76
- *
77
- * If you want to try to re-use the same transport instance at the next action (when calling `open` again), you can use
78
- * the transport instance `close` method: it will only enable a disconnect after some inactivity.
86
+ * globally disconnect the transport singleton
79
87
  */
80
88
  static disconnect() {
81
- (0, logs_1.trace)({
82
- type: LOG_TYPE,
83
- message: "Disconnecting from HID device",
84
- data: {
85
- hasInstance: Boolean(transportInstance),
86
- },
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ if (transportInstance) {
91
+ transportInstance.device.close();
92
+ transportInstance.emit("disconnect");
93
+ transportInstance = null;
94
+ }
95
+ clearDisconnectTimeout();
87
96
  });
88
- TransportNodeHidSingleton.clearDisconnectAfterInactivityTimeout();
89
- if (transportInstance) {
90
- transportInstance.device.close();
91
- (0, logs_1.trace)({
92
- type: LOG_TYPE,
93
- message: `Closed HID communication with device. Emitting "disconnect" event from static disconnect and clearing singleton instance`,
94
- });
95
- transportInstance.emit("disconnect");
96
- transportInstance = null;
97
- }
98
97
  }
99
98
  /**
100
99
  * Connects to the first Ledger device connected via USB
@@ -106,79 +105,61 @@ class TransportNodeHidSingleton extends hw_transport_node_hid_noevents_1.default
106
105
  */
107
106
  static open(_descriptor, _timeoutMs, context) {
108
107
  const tracer = new logs_1.LocalTracer(LOG_TYPE, context);
109
- TransportNodeHidSingleton.clearDisconnectAfterInactivityTimeout();
110
- if (transportInstance) {
111
- tracer.trace("Reusing already opened transport instance");
112
- return Promise.resolve(transportInstance);
113
- }
114
- const devicesDetectedDuringOpen = (0, hw_transport_node_hid_noevents_1.getDevices)();
115
- tracer.trace(`Devices detected during open: ${devicesDetectedDuringOpen.length}`, {
116
- devicesDetectedDuringOpen,
117
- });
118
- if (devicesDetectedDuringOpen.length === 0) {
119
- return Promise.reject(new errors_1.CantOpenDevice("No device found"));
120
- }
121
- const device = devicesDetectedDuringOpen[0];
122
- tracer.trace("Found a device, creating HID transport instance ...", { device });
123
- let HIDDevice;
124
- try {
125
- HIDDevice = new node_hid_1.default.HID(device.path);
126
- }
127
- catch (error) {
128
- tracer.trace(`Error while connecting to device: ${error}`, { error });
129
- return Promise.reject(error);
130
- }
131
- transportInstance = new TransportNodeHidSingleton(HIDDevice, {
132
- context,
133
- });
134
- const clearDeviceEventsListener = (0, listenDevices_1.listenDevices)(() => { }, () => {
135
- // Assumes any ledger disconnection concerns current transport
108
+ clearDisconnectTimeout();
109
+ return Promise.resolve().then(() => {
136
110
  if (transportInstance) {
137
- tracer.trace("Listened to on remove device event. Emitting a disconnect");
138
- transportInstance.emit("disconnect");
111
+ tracer.trace("Reusing already opened transport instance");
112
+ return transportInstance;
139
113
  }
114
+ const device = (0, hw_transport_node_hid_noevents_1.getDevices)()[0];
115
+ if (!device)
116
+ throw new errors_1.CantOpenDevice("no device found");
117
+ tracer.trace("Found a device, creating HID transport instance ...", { device });
118
+ transportInstance = new TransportNodeHidSingleton(new node_hid_1.default.HID(device.path), {
119
+ context,
120
+ });
121
+ const unlisten = (0, listenDevices_1.listenDevices)(() => { }, () => {
122
+ // Assumes any ledger disconnection concerns current transport
123
+ if (transportInstance) {
124
+ transportInstance.emit("disconnect");
125
+ }
126
+ });
127
+ const onDisconnect = () => {
128
+ if (!transportInstance)
129
+ return;
130
+ tracer.trace("Device was disconnected, clearing transport instance ...");
131
+ transportInstance.off("disconnect", onDisconnect);
132
+ transportInstance = null;
133
+ unlisten();
134
+ };
135
+ transportInstance.on("disconnect", onDisconnect);
136
+ return transportInstance;
140
137
  });
141
- /**
142
- * Disconnect event received from the transport instance.
143
- *
144
- * It could be after a disconnection coming from the HID library (e.g. device unplugged) or from the transport instance itself (e.g. close).
145
- * Clearing the singleton instance.
146
- * Currently, only 1 device at a time is supported.
147
- */
148
- const onDisconnect = () => {
149
- if (!transportInstance) {
150
- tracer.trace("disconnect event without transport instance, ignoring ...");
151
- return;
152
- }
153
- this.clearDisconnectAfterInactivityTimeout();
154
- transportInstance.off("disconnect", onDisconnect);
155
- transportInstance = null;
156
- clearDeviceEventsListener();
157
- };
158
- transportInstance.on("disconnect", onDisconnect);
159
- return Promise.resolve(transportInstance);
138
+ }
139
+ setAllowAutoDisconnect(allow) {
140
+ this.preventAutoDisconnect = !allow;
160
141
  }
161
142
  /**
162
- * Exchanges with the device using APDU protocol
143
+ * Exchange with the device using APDU protocol.
163
144
  *
164
145
  * @param apdu
165
146
  * @returns a promise of apdu response
166
147
  */
167
148
  exchange(apdu) {
168
- return super.exchange(apdu);
149
+ const _super = Object.create(null, {
150
+ exchange: { get: () => super.exchange }
151
+ });
152
+ return __awaiter(this, void 0, void 0, function* () {
153
+ clearDisconnectTimeout();
154
+ const result = yield _super.exchange.call(this, apdu);
155
+ setDisconnectTimeout();
156
+ return result;
157
+ });
169
158
  }
170
- /**
171
- * Closes the transport instance by triggering a disconnection after some inactivity (no new `open`).
172
- *
173
- * Intentionally not disconnecting the device/closing the hid connection directly:
174
- * The HID connection will only be closed after some inactivity.
175
- */
176
159
  close() {
177
- this.tracer.trace("Closing transport instance by triggering a disconnection after some inactivity", {
178
- hasInstance: !!transportInstance,
179
- disconnectAfterInactivityTimeoutMs: DISCONNECT_AFTER_INACTIVITY_TIMEOUT_MS,
180
- });
181
- TransportNodeHidSingleton.setDisconnectAfterInactivityTimeout();
160
+ // intentionally, a close will not effectively close the hid connection but
161
+ // will allow an auto-disconnection after some inactivity
162
+ this.preventAutoDisconnect = false;
182
163
  return Promise.resolve();
183
164
  }
184
165
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TransportNodeHid.js","sourceRoot":"","sources":["../src/TransportNodeHid.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TransportNodeHid.js","sourceRoot":"","sources":["../src/TransportNodeHid.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ import HID from "node-hid";
3
3
  import TransportNodeHidNoEvents from "@ledgerhq/hw-transport-node-hid-noevents";
4
4
  import type { Observer, DescriptorEvent, Subscription } from "@ledgerhq/hw-transport";
5
5
  import { TraceContext } from "@ledgerhq/logs";
6
- export type ListenDescriptorEvent = DescriptorEvent<string>;
6
+ export type ListenDescriptorEvent = DescriptorEvent<any>;
7
7
  /**
8
8
  * node-hid Transport implementation
9
9
  * @example
@@ -12,6 +12,7 @@ export type ListenDescriptorEvent = DescriptorEvent<string>;
12
12
  * TransportNodeHid.create().then(transport => ...)
13
13
  */
14
14
  export default class TransportNodeHidSingleton extends TransportNodeHidNoEvents {
15
+ preventAutoDisconnect: boolean;
15
16
  constructor(device: HID.HID, { context }?: {
16
17
  context?: TraceContext;
17
18
  });
@@ -26,21 +27,14 @@ export default class TransportNodeHidSingleton extends TransportNodeHidNoEvents
26
27
  /**
27
28
  */
28
29
  static listen: (observer: Observer<ListenDescriptorEvent>) => Subscription;
29
- static disconnectAfterInactivityTimeout: ReturnType<typeof setTimeout> | undefined;
30
- static clearDisconnectAfterInactivityTimeout(): void;
31
30
  /**
32
- * Disconnects device from singleton instance after some inactivity (no new `open`).
33
- *
34
- * Currently, there is only one transport instance (for only one device connected via USB).
31
+ * convenience wrapper for auto-disconnect logic
35
32
  */
36
- static setDisconnectAfterInactivityTimeout(): void;
33
+ static autoDisconnect(): Promise<void>;
37
34
  /**
38
- * Disconnects from the HID device associated to the transport singleton.
39
- *
40
- * If you want to try to re-use the same transport instance at the next action (when calling `open` again), you can use
41
- * the transport instance `close` method: it will only enable a disconnect after some inactivity.
35
+ * globally disconnect the transport singleton
42
36
  */
43
- static disconnect(): void;
37
+ static disconnect(): Promise<void>;
44
38
  /**
45
39
  * Connects to the first Ledger device connected via USB
46
40
  *
@@ -50,19 +44,14 @@ export default class TransportNodeHidSingleton extends TransportNodeHidNoEvents
50
44
  * Legacy: `_descriptor` is needed to follow the Transport definition
51
45
  */
52
46
  static open(_descriptor: string, _timeoutMs?: number, context?: TraceContext): Promise<TransportNodeHidSingleton>;
47
+ setAllowAutoDisconnect(allow: boolean): void;
53
48
  /**
54
- * Exchanges with the device using APDU protocol
49
+ * Exchange with the device using APDU protocol.
55
50
  *
56
51
  * @param apdu
57
52
  * @returns a promise of apdu response
58
53
  */
59
54
  exchange(apdu: Buffer): Promise<Buffer>;
60
- /**
61
- * Closes the transport instance by triggering a disconnection after some inactivity (no new `open`).
62
- *
63
- * Intentionally not disconnecting the device/closing the hid connection directly:
64
- * The HID connection will only be closed after some inactivity.
65
- */
66
55
  close(): Promise<void>;
67
56
  }
68
57
  //# sourceMappingURL=TransportNodeHid.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TransportNodeHid.d.ts","sourceRoot":"","sources":["../src/TransportNodeHid.ts"],"names":[],"mappings":";AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,wBAAwC,MAAM,0CAA0C,CAAC;AAChG,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAe,YAAY,EAAS,MAAM,gBAAgB,CAAC;AAWlE,MAAM,MAAM,qBAAqB,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AAE5D;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,OAAO,yBAA0B,SAAQ,wBAAwB;gBACjE,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,GAAE;QAAE,OAAO,CAAC,EAAE,YAAY,CAAA;KAAO;IAIzE;;OAEG;IACH,MAAM,CAAC,WAAW,yBAAwC;IAE1D;;OAEG;IACH,MAAM,CAAC,IAAI,qBAAiC;IAE5C;OACG;IACH,MAAM,CAAC,MAAM,aAAc,SAAS,qBAAqB,CAAC,KAAG,YAAY,CAqDvE;IAEF,MAAM,CAAC,gCAAgC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,SAAS,CAAC;IACnF,MAAM,CAAC,qCAAqC;IAM5C;;;;OAIG;IACH,MAAM,CAAC,mCAAmC;IAiB1C;;;;;OAKG;IACH,MAAM,CAAC,UAAU;IAsBjB;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,CACT,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,yBAAyB,CAAC;IAkErC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIvC;;;;;OAKG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAavB"}
1
+ {"version":3,"file":"TransportNodeHid.d.ts","sourceRoot":"","sources":["../src/TransportNodeHid.ts"],"names":[],"mappings":";AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,wBAAwC,MAAM,0CAA0C,CAAC;AAChG,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAe,YAAY,EAAO,MAAM,gBAAgB,CAAC;AAyBhE,MAAM,MAAM,qBAAqB,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,OAAO,yBAA0B,SAAQ,wBAAwB;IAC7E,qBAAqB,UAAS;gBAElB,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,GAAE;QAAE,OAAO,CAAC,EAAE,YAAY,CAAA;KAAO;IAIzE;;OAEG;IACH,MAAM,CAAC,WAAW,yBAAwC;IAE1D;;OAEG;IACH,MAAM,CAAC,IAAI,qBAAiC;IAE5C;OACG;IACH,MAAM,CAAC,MAAM,aAAc,SAAS,qBAAqB,CAAC,KAAG,YAAY,CAqDvE;IAEF;;OAEG;WACU,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5C;;OAEG;WACU,UAAU;IASvB;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,CACT,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,yBAAyB,CAAC;IAyCrC,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI5C;;;;;OAKG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAMvB"}
@@ -1,12 +1,31 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import HID from "node-hid";
2
11
  import TransportNodeHidNoEvents, { getDevices } from "@ledgerhq/hw-transport-node-hid-noevents";
3
- import { LocalTracer, trace } from "@ledgerhq/logs";
12
+ import { LocalTracer, log } from "@ledgerhq/logs";
4
13
  import { identifyUSBProductId } from "@ledgerhq/devices";
5
14
  import { CantOpenDevice } from "@ledgerhq/errors";
6
15
  import { listenDevices } from "./listenDevices";
7
16
  const LOG_TYPE = "hid-verbose";
8
17
  let transportInstance = null;
9
- const DISCONNECT_AFTER_INACTIVITY_TIMEOUT_MS = 5000;
18
+ const DISCONNECT_TIMEOUT = 5000;
19
+ let disconnectTimeout;
20
+ const clearDisconnectTimeout = () => {
21
+ if (disconnectTimeout) {
22
+ clearTimeout(disconnectTimeout);
23
+ }
24
+ };
25
+ const setDisconnectTimeout = () => {
26
+ clearDisconnectTimeout();
27
+ disconnectTimeout = setTimeout(() => TransportNodeHidSingleton.autoDisconnect(), DISCONNECT_TIMEOUT);
28
+ };
10
29
  /**
11
30
  * node-hid Transport implementation
12
31
  * @example
@@ -17,56 +36,36 @@ const DISCONNECT_AFTER_INACTIVITY_TIMEOUT_MS = 5000;
17
36
  class TransportNodeHidSingleton extends TransportNodeHidNoEvents {
18
37
  constructor(device, { context } = {}) {
19
38
  super(device, { context, logType: LOG_TYPE });
20
- }
21
- static clearDisconnectAfterInactivityTimeout() {
22
- if (TransportNodeHidSingleton.disconnectAfterInactivityTimeout) {
23
- clearTimeout(TransportNodeHidSingleton.disconnectAfterInactivityTimeout);
24
- }
39
+ this.preventAutoDisconnect = false;
25
40
  }
26
41
  /**
27
- * Disconnects device from singleton instance after some inactivity (no new `open`).
28
- *
29
- * Currently, there is only one transport instance (for only one device connected via USB).
42
+ * convenience wrapper for auto-disconnect logic
30
43
  */
31
- static setDisconnectAfterInactivityTimeout() {
32
- TransportNodeHidSingleton.clearDisconnectAfterInactivityTimeout();
33
- TransportNodeHidSingleton.disconnectAfterInactivityTimeout = setTimeout(() => {
34
- trace({
35
- type: LOG_TYPE,
36
- message: "Disconnecting after inactivity, if not prevented",
37
- data: {
38
- hasInstance: Boolean(transportInstance),
39
- },
40
- });
41
- if (transportInstance) {
44
+ static autoDisconnect() {
45
+ return __awaiter(this, void 0, void 0, function* () {
46
+ if (transportInstance && !transportInstance.preventAutoDisconnect) {
47
+ log("hid-verbose", "triggering auto disconnect");
42
48
  TransportNodeHidSingleton.disconnect();
43
49
  }
44
- }, DISCONNECT_AFTER_INACTIVITY_TIMEOUT_MS);
50
+ else if (transportInstance) {
51
+ // If we have disabled the auto-disconnect, try again in DISCONNECT_TIMEOUT
52
+ clearDisconnectTimeout();
53
+ setDisconnectTimeout();
54
+ }
55
+ });
45
56
  }
46
57
  /**
47
- * Disconnects from the HID device associated to the transport singleton.
48
- *
49
- * If you want to try to re-use the same transport instance at the next action (when calling `open` again), you can use
50
- * the transport instance `close` method: it will only enable a disconnect after some inactivity.
58
+ * globally disconnect the transport singleton
51
59
  */
52
60
  static disconnect() {
53
- trace({
54
- type: LOG_TYPE,
55
- message: "Disconnecting from HID device",
56
- data: {
57
- hasInstance: Boolean(transportInstance),
58
- },
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ if (transportInstance) {
63
+ transportInstance.device.close();
64
+ transportInstance.emit("disconnect");
65
+ transportInstance = null;
66
+ }
67
+ clearDisconnectTimeout();
59
68
  });
60
- TransportNodeHidSingleton.clearDisconnectAfterInactivityTimeout();
61
- if (transportInstance) {
62
- transportInstance.device.close();
63
- trace({
64
- type: LOG_TYPE,
65
- message: `Closed HID communication with device. Emitting "disconnect" event from static disconnect and clearing singleton instance`,
66
- });
67
- transportInstance.emit("disconnect");
68
- transportInstance = null;
69
- }
70
69
  }
71
70
  /**
72
71
  * Connects to the first Ledger device connected via USB
@@ -78,79 +77,61 @@ class TransportNodeHidSingleton extends TransportNodeHidNoEvents {
78
77
  */
79
78
  static open(_descriptor, _timeoutMs, context) {
80
79
  const tracer = new LocalTracer(LOG_TYPE, context);
81
- TransportNodeHidSingleton.clearDisconnectAfterInactivityTimeout();
82
- if (transportInstance) {
83
- tracer.trace("Reusing already opened transport instance");
84
- return Promise.resolve(transportInstance);
85
- }
86
- const devicesDetectedDuringOpen = getDevices();
87
- tracer.trace(`Devices detected during open: ${devicesDetectedDuringOpen.length}`, {
88
- devicesDetectedDuringOpen,
89
- });
90
- if (devicesDetectedDuringOpen.length === 0) {
91
- return Promise.reject(new CantOpenDevice("No device found"));
92
- }
93
- const device = devicesDetectedDuringOpen[0];
94
- tracer.trace("Found a device, creating HID transport instance ...", { device });
95
- let HIDDevice;
96
- try {
97
- HIDDevice = new HID.HID(device.path);
98
- }
99
- catch (error) {
100
- tracer.trace(`Error while connecting to device: ${error}`, { error });
101
- return Promise.reject(error);
102
- }
103
- transportInstance = new TransportNodeHidSingleton(HIDDevice, {
104
- context,
105
- });
106
- const clearDeviceEventsListener = listenDevices(() => { }, () => {
107
- // Assumes any ledger disconnection concerns current transport
80
+ clearDisconnectTimeout();
81
+ return Promise.resolve().then(() => {
108
82
  if (transportInstance) {
109
- tracer.trace("Listened to on remove device event. Emitting a disconnect");
110
- transportInstance.emit("disconnect");
83
+ tracer.trace("Reusing already opened transport instance");
84
+ return transportInstance;
111
85
  }
86
+ const device = getDevices()[0];
87
+ if (!device)
88
+ throw new CantOpenDevice("no device found");
89
+ tracer.trace("Found a device, creating HID transport instance ...", { device });
90
+ transportInstance = new TransportNodeHidSingleton(new HID.HID(device.path), {
91
+ context,
92
+ });
93
+ const unlisten = listenDevices(() => { }, () => {
94
+ // Assumes any ledger disconnection concerns current transport
95
+ if (transportInstance) {
96
+ transportInstance.emit("disconnect");
97
+ }
98
+ });
99
+ const onDisconnect = () => {
100
+ if (!transportInstance)
101
+ return;
102
+ tracer.trace("Device was disconnected, clearing transport instance ...");
103
+ transportInstance.off("disconnect", onDisconnect);
104
+ transportInstance = null;
105
+ unlisten();
106
+ };
107
+ transportInstance.on("disconnect", onDisconnect);
108
+ return transportInstance;
112
109
  });
113
- /**
114
- * Disconnect event received from the transport instance.
115
- *
116
- * It could be after a disconnection coming from the HID library (e.g. device unplugged) or from the transport instance itself (e.g. close).
117
- * Clearing the singleton instance.
118
- * Currently, only 1 device at a time is supported.
119
- */
120
- const onDisconnect = () => {
121
- if (!transportInstance) {
122
- tracer.trace("disconnect event without transport instance, ignoring ...");
123
- return;
124
- }
125
- this.clearDisconnectAfterInactivityTimeout();
126
- transportInstance.off("disconnect", onDisconnect);
127
- transportInstance = null;
128
- clearDeviceEventsListener();
129
- };
130
- transportInstance.on("disconnect", onDisconnect);
131
- return Promise.resolve(transportInstance);
110
+ }
111
+ setAllowAutoDisconnect(allow) {
112
+ this.preventAutoDisconnect = !allow;
132
113
  }
133
114
  /**
134
- * Exchanges with the device using APDU protocol
115
+ * Exchange with the device using APDU protocol.
135
116
  *
136
117
  * @param apdu
137
118
  * @returns a promise of apdu response
138
119
  */
139
120
  exchange(apdu) {
140
- return super.exchange(apdu);
121
+ const _super = Object.create(null, {
122
+ exchange: { get: () => super.exchange }
123
+ });
124
+ return __awaiter(this, void 0, void 0, function* () {
125
+ clearDisconnectTimeout();
126
+ const result = yield _super.exchange.call(this, apdu);
127
+ setDisconnectTimeout();
128
+ return result;
129
+ });
141
130
  }
142
- /**
143
- * Closes the transport instance by triggering a disconnection after some inactivity (no new `open`).
144
- *
145
- * Intentionally not disconnecting the device/closing the hid connection directly:
146
- * The HID connection will only be closed after some inactivity.
147
- */
148
131
  close() {
149
- this.tracer.trace("Closing transport instance by triggering a disconnection after some inactivity", {
150
- hasInstance: !!transportInstance,
151
- disconnectAfterInactivityTimeoutMs: DISCONNECT_AFTER_INACTIVITY_TIMEOUT_MS,
152
- });
153
- TransportNodeHidSingleton.setDisconnectAfterInactivityTimeout();
132
+ // intentionally, a close will not effectively close the hid connection but
133
+ // will allow an auto-disconnection after some inactivity
134
+ this.preventAutoDisconnect = false;
154
135
  return Promise.resolve();
155
136
  }
156
137
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TransportNodeHid.js","sourceRoot":"","sources":["../src/TransportNodeHid.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TransportNodeHid.js","sourceRoot":"","sources":["../src/TransportNodeHid.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/hw-transport-node-hid-singleton",
3
- "version": "6.30.2-nightly.1",
3
+ "version": "6.30.2",
4
4
  "description": "Ledger Hardware Wallet Node implementation of the communication layer, using node-hid and node-usb",
5
5
  "keywords": [
6
6
  "Ledger",
@@ -30,9 +30,9 @@
30
30
  "node-hid": "^2.1.2",
31
31
  "usb": "2.9.0",
32
32
  "@ledgerhq/devices": "^8.2.0",
33
+ "@ledgerhq/hw-transport": "^6.30.2",
33
34
  "@ledgerhq/errors": "^6.16.1",
34
- "@ledgerhq/hw-transport": "^6.30.2-nightly.1",
35
- "@ledgerhq/hw-transport-node-hid-noevents": "^6.29.2-nightly.1",
35
+ "@ledgerhq/hw-transport-node-hid-noevents": "^6.29.2",
36
36
  "@ledgerhq/logs": "^6.12.0"
37
37
  },
38
38
  "gitHead": "dd0dea64b58e5a9125c8a422dcffd29e5ef6abec",
@@ -1,7 +1,7 @@
1
1
  import HID from "node-hid";
2
2
  import TransportNodeHidNoEvents, { getDevices } from "@ledgerhq/hw-transport-node-hid-noevents";
3
3
  import type { Observer, DescriptorEvent, Subscription } from "@ledgerhq/hw-transport";
4
- import { LocalTracer, TraceContext, trace } from "@ledgerhq/logs";
4
+ import { LocalTracer, TraceContext, log } from "@ledgerhq/logs";
5
5
  import { identifyUSBProductId } from "@ledgerhq/devices";
6
6
  import { CantOpenDevice } from "@ledgerhq/errors";
7
7
  import { listenDevices } from "./listenDevices";
@@ -10,9 +10,23 @@ const LOG_TYPE = "hid-verbose";
10
10
 
11
11
  let transportInstance: TransportNodeHidSingleton | null = null;
12
12
 
13
- const DISCONNECT_AFTER_INACTIVITY_TIMEOUT_MS = 5000;
13
+ const DISCONNECT_TIMEOUT = 5000;
14
+ let disconnectTimeout;
15
+ const clearDisconnectTimeout = () => {
16
+ if (disconnectTimeout) {
17
+ clearTimeout(disconnectTimeout);
18
+ }
19
+ };
20
+
21
+ const setDisconnectTimeout = () => {
22
+ clearDisconnectTimeout();
23
+ disconnectTimeout = setTimeout(
24
+ () => TransportNodeHidSingleton.autoDisconnect(),
25
+ DISCONNECT_TIMEOUT,
26
+ );
27
+ };
14
28
 
15
- export type ListenDescriptorEvent = DescriptorEvent<string>;
29
+ export type ListenDescriptorEvent = DescriptorEvent<any>;
16
30
 
17
31
  /**
18
32
  * node-hid Transport implementation
@@ -22,6 +36,8 @@ export type ListenDescriptorEvent = DescriptorEvent<string>;
22
36
  * TransportNodeHid.create().then(transport => ...)
23
37
  */
24
38
  export default class TransportNodeHidSingleton extends TransportNodeHidNoEvents {
39
+ preventAutoDisconnect = false;
40
+
25
41
  constructor(device: HID.HID, { context }: { context?: TraceContext } = {}) {
26
42
  super(device, { context, logType: LOG_TYPE });
27
43
  }
@@ -93,61 +109,30 @@ export default class TransportNodeHidSingleton extends TransportNodeHidNoEvents
93
109
  };
94
110
  };
95
111
 
96
- static disconnectAfterInactivityTimeout: ReturnType<typeof setTimeout> | undefined;
97
- static clearDisconnectAfterInactivityTimeout() {
98
- if (TransportNodeHidSingleton.disconnectAfterInactivityTimeout) {
99
- clearTimeout(TransportNodeHidSingleton.disconnectAfterInactivityTimeout);
100
- }
101
- }
102
-
103
112
  /**
104
- * Disconnects device from singleton instance after some inactivity (no new `open`).
105
- *
106
- * Currently, there is only one transport instance (for only one device connected via USB).
113
+ * convenience wrapper for auto-disconnect logic
107
114
  */
108
- static setDisconnectAfterInactivityTimeout() {
109
- TransportNodeHidSingleton.clearDisconnectAfterInactivityTimeout();
110
- TransportNodeHidSingleton.disconnectAfterInactivityTimeout = setTimeout(() => {
111
- trace({
112
- type: LOG_TYPE,
113
- message: "Disconnecting after inactivity, if not prevented",
114
- data: {
115
- hasInstance: Boolean(transportInstance),
116
- },
117
- });
118
-
119
- if (transportInstance) {
120
- TransportNodeHidSingleton.disconnect();
121
- }
122
- }, DISCONNECT_AFTER_INACTIVITY_TIMEOUT_MS);
115
+ static async autoDisconnect(): Promise<void> {
116
+ if (transportInstance && !transportInstance.preventAutoDisconnect) {
117
+ log("hid-verbose", "triggering auto disconnect");
118
+ TransportNodeHidSingleton.disconnect();
119
+ } else if (transportInstance) {
120
+ // If we have disabled the auto-disconnect, try again in DISCONNECT_TIMEOUT
121
+ clearDisconnectTimeout();
122
+ setDisconnectTimeout();
123
+ }
123
124
  }
124
125
 
125
126
  /**
126
- * Disconnects from the HID device associated to the transport singleton.
127
- *
128
- * If you want to try to re-use the same transport instance at the next action (when calling `open` again), you can use
129
- * the transport instance `close` method: it will only enable a disconnect after some inactivity.
127
+ * globally disconnect the transport singleton
130
128
  */
131
- static disconnect() {
132
- trace({
133
- type: LOG_TYPE,
134
- message: "Disconnecting from HID device",
135
- data: {
136
- hasInstance: Boolean(transportInstance),
137
- },
138
- });
139
-
140
- TransportNodeHidSingleton.clearDisconnectAfterInactivityTimeout();
141
-
129
+ static async disconnect() {
142
130
  if (transportInstance) {
143
131
  transportInstance.device.close();
144
- trace({
145
- type: LOG_TYPE,
146
- message: `Closed HID communication with device. Emitting "disconnect" event from static disconnect and clearing singleton instance`,
147
- });
148
132
  transportInstance.emit("disconnect");
149
133
  transportInstance = null;
150
134
  }
135
+ clearDisconnectTimeout();
151
136
  }
152
137
 
153
138
  /**
@@ -164,97 +149,66 @@ export default class TransportNodeHidSingleton extends TransportNodeHidNoEvents
164
149
  context?: TraceContext,
165
150
  ): Promise<TransportNodeHidSingleton> {
166
151
  const tracer = new LocalTracer(LOG_TYPE, context);
167
- TransportNodeHidSingleton.clearDisconnectAfterInactivityTimeout();
168
-
169
- if (transportInstance) {
170
- tracer.trace("Reusing already opened transport instance");
171
- return Promise.resolve(transportInstance);
172
- }
152
+ clearDisconnectTimeout();
173
153
 
174
- const devicesDetectedDuringOpen = getDevices();
175
- tracer.trace(`Devices detected during open: ${devicesDetectedDuringOpen.length}`, {
176
- devicesDetectedDuringOpen,
177
- });
178
-
179
- if (devicesDetectedDuringOpen.length === 0) {
180
- return Promise.reject(new CantOpenDevice("No device found"));
181
- }
182
- const device = devicesDetectedDuringOpen[0];
154
+ return Promise.resolve().then(() => {
155
+ if (transportInstance) {
156
+ tracer.trace("Reusing already opened transport instance");
157
+ return transportInstance;
158
+ }
183
159
 
184
- tracer.trace("Found a device, creating HID transport instance ...", { device });
160
+ const device = getDevices()[0];
161
+ if (!device) throw new CantOpenDevice("no device found");
185
162
 
186
- let HIDDevice: HID | undefined;
187
- try {
188
- HIDDevice = new HID.HID(device.path as string);
189
- } catch (error) {
190
- tracer.trace(`Error while connecting to device: ${error}`, { error });
191
- return Promise.reject(error);
192
- }
163
+ tracer.trace("Found a device, creating HID transport instance ...", { device });
164
+ transportInstance = new TransportNodeHidSingleton(new HID.HID(device.path as string), {
165
+ context,
166
+ });
193
167
 
194
- transportInstance = new TransportNodeHidSingleton(HIDDevice, {
195
- context,
168
+ const unlisten = listenDevices(
169
+ () => {},
170
+ () => {
171
+ // Assumes any ledger disconnection concerns current transport
172
+ if (transportInstance) {
173
+ transportInstance.emit("disconnect");
174
+ }
175
+ },
176
+ );
177
+
178
+ const onDisconnect = () => {
179
+ if (!transportInstance) return;
180
+ tracer.trace("Device was disconnected, clearing transport instance ...");
181
+ transportInstance.off("disconnect", onDisconnect);
182
+ transportInstance = null;
183
+ unlisten();
184
+ };
185
+
186
+ transportInstance.on("disconnect", onDisconnect);
187
+ return transportInstance;
196
188
  });
189
+ }
197
190
 
198
- const clearDeviceEventsListener = listenDevices(
199
- () => {},
200
- () => {
201
- // Assumes any ledger disconnection concerns current transport
202
- if (transportInstance) {
203
- tracer.trace("Listened to on remove device event. Emitting a disconnect");
204
- transportInstance.emit("disconnect");
205
- }
206
- },
207
- );
208
-
209
- /**
210
- * Disconnect event received from the transport instance.
211
- *
212
- * It could be after a disconnection coming from the HID library (e.g. device unplugged) or from the transport instance itself (e.g. close).
213
- * Clearing the singleton instance.
214
- * Currently, only 1 device at a time is supported.
215
- */
216
- const onDisconnect = () => {
217
- if (!transportInstance) {
218
- tracer.trace("disconnect event without transport instance, ignoring ...");
219
- return;
220
- }
221
- this.clearDisconnectAfterInactivityTimeout();
222
- transportInstance.off("disconnect", onDisconnect);
223
- transportInstance = null;
224
- clearDeviceEventsListener();
225
- };
226
-
227
- transportInstance.on("disconnect", onDisconnect);
228
- return Promise.resolve(transportInstance);
191
+ setAllowAutoDisconnect(allow: boolean): void {
192
+ this.preventAutoDisconnect = !allow;
229
193
  }
230
194
 
231
195
  /**
232
- * Exchanges with the device using APDU protocol
196
+ * Exchange with the device using APDU protocol.
233
197
  *
234
198
  * @param apdu
235
199
  * @returns a promise of apdu response
236
200
  */
237
- exchange(apdu: Buffer): Promise<Buffer> {
238
- return super.exchange(apdu);
201
+ async exchange(apdu: Buffer): Promise<Buffer> {
202
+ clearDisconnectTimeout();
203
+ const result = await super.exchange(apdu);
204
+ setDisconnectTimeout();
205
+ return result;
239
206
  }
240
207
 
241
- /**
242
- * Closes the transport instance by triggering a disconnection after some inactivity (no new `open`).
243
- *
244
- * Intentionally not disconnecting the device/closing the hid connection directly:
245
- * The HID connection will only be closed after some inactivity.
246
- */
247
208
  close(): Promise<void> {
248
- this.tracer.trace(
249
- "Closing transport instance by triggering a disconnection after some inactivity",
250
- {
251
- hasInstance: !!transportInstance,
252
- disconnectAfterInactivityTimeoutMs: DISCONNECT_AFTER_INACTIVITY_TIMEOUT_MS,
253
- },
254
- );
255
-
256
- TransportNodeHidSingleton.setDisconnectAfterInactivityTimeout();
257
-
209
+ // intentionally, a close will not effectively close the hid connection but
210
+ // will allow an auto-disconnection after some inactivity
211
+ this.preventAutoDisconnect = false;
258
212
  return Promise.resolve();
259
213
  }
260
214
  }