@onekeyfe/hd-transport-usb 1.1.25-alpha.0

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.
@@ -0,0 +1,4 @@
1
+ export declare const PACKET_SIZE = 64;
2
+ export declare const REPORT_ID = 63;
3
+ export declare const HEADER_LENGTH = 6;
4
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,WAAW,KAAK,CAAC;AAG9B,eAAO,MAAM,SAAS,KAAO,CAAC;AAG9B,eAAO,MAAM,aAAa,IAAI,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { LowlevelTransportSharedPlugin } from '@onekeyfe/hd-transport';
2
+
3
+ declare const PACKET_SIZE = 64;
4
+
5
+ declare const UsbPlugin: LowlevelTransportSharedPlugin;
6
+
7
+ export { PACKET_SIZE, UsbPlugin, UsbPlugin as default };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAkB,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AAoG5F,eAAO,MAAM,SAAS,EAAE,6BAoLvB,CAAC;AAEF,eAAe,SAAS,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,262 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var ByteBuffer = require('bytebuffer');
6
+ var usb = require('usb');
7
+ var transport = require('@onekeyfe/hd-transport');
8
+ var hdShared = require('@onekeyfe/hd-shared');
9
+
10
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
+
12
+ function _interopNamespace(e) {
13
+ if (e && e.__esModule) return e;
14
+ var n = Object.create(null);
15
+ if (e) {
16
+ Object.keys(e).forEach(function (k) {
17
+ if (k !== 'default') {
18
+ var d = Object.getOwnPropertyDescriptor(e, k);
19
+ Object.defineProperty(n, k, d.get ? d : {
20
+ enumerable: true,
21
+ get: function () { return e[k]; }
22
+ });
23
+ }
24
+ });
25
+ }
26
+ n["default"] = e;
27
+ return Object.freeze(n);
28
+ }
29
+
30
+ var ByteBuffer__default = /*#__PURE__*/_interopDefaultLegacy(ByteBuffer);
31
+ var usb__namespace = /*#__PURE__*/_interopNamespace(usb);
32
+ var transport__default = /*#__PURE__*/_interopDefaultLegacy(transport);
33
+
34
+ /******************************************************************************
35
+ Copyright (c) Microsoft Corporation.
36
+
37
+ Permission to use, copy, modify, and/or distribute this software for any
38
+ purpose with or without fee is hereby granted.
39
+
40
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
41
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
42
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
43
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
44
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
45
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
46
+ PERFORMANCE OF THIS SOFTWARE.
47
+ ***************************************************************************** */
48
+
49
+ function __awaiter(thisArg, _arguments, P, generator) {
50
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
51
+ return new (P || (P = Promise))(function (resolve, reject) {
52
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
53
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
54
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
55
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
56
+ });
57
+ }
58
+
59
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
60
+ var e = new Error(message);
61
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
62
+ };
63
+
64
+ const PACKET_SIZE = 64;
65
+ const REPORT_ID = 0x3f;
66
+ const HEADER_LENGTH = 6;
67
+
68
+ const { decodeProtocol } = transport__default["default"];
69
+ const INTERFACE_NUMBER = 0;
70
+ const ENDPOINT_IN = 0x81;
71
+ const ENDPOINT_OUT = 0x01;
72
+ const TRANSFER_TIMEOUT_MS = 30000;
73
+ let activeDevice = null;
74
+ const openDevices = new Map();
75
+ function getDeviceId(dev) {
76
+ return `usb:${dev.busNumber}:${dev.deviceAddress}`;
77
+ }
78
+ function transferIn(ep, length) {
79
+ return new Promise((resolve, reject) => {
80
+ ep.transfer(length, (err, data) => {
81
+ if (err)
82
+ return reject(err);
83
+ if (!data || data.length === 0)
84
+ return reject(new Error('Empty USB transfer'));
85
+ resolve(data);
86
+ });
87
+ });
88
+ }
89
+ function transferOut(ep, data) {
90
+ return new Promise((resolve, reject) => {
91
+ ep.transfer(data, (err) => {
92
+ if (err)
93
+ return reject(err);
94
+ resolve();
95
+ });
96
+ });
97
+ }
98
+ function readPacket(dev) {
99
+ return __awaiter(this, void 0, void 0, function* () {
100
+ return transferIn(dev.epIn, PACKET_SIZE);
101
+ });
102
+ }
103
+ function skipReportByte(packet) {
104
+ if (packet[0] === REPORT_ID) {
105
+ return packet.subarray(1);
106
+ }
107
+ return packet;
108
+ }
109
+ function toArrayBuffer(buf) {
110
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
111
+ }
112
+ const UsbPlugin = {
113
+ version: '1.0.0',
114
+ init() {
115
+ return __awaiter(this, void 0, void 0, function* () {
116
+ });
117
+ },
118
+ enumerate() {
119
+ return __awaiter(this, void 0, void 0, function* () {
120
+ const allDevices = usb__namespace.getDeviceList();
121
+ const onekeyDevices = allDevices.filter(d => {
122
+ const { idVendor, idProduct } = d.deviceDescriptor;
123
+ return hdShared.ONEKEY_WEBUSB_FILTER.some(f => idVendor === f.vendorId && idProduct === f.productId);
124
+ });
125
+ return onekeyDevices.map(d => {
126
+ let name = 'OneKey';
127
+ try {
128
+ d.open();
129
+ const iface = d.interface(INTERFACE_NUMBER);
130
+ if (iface && iface.descriptor.bInterfaceClass === 255) {
131
+ name = 'OneKey';
132
+ }
133
+ d.close();
134
+ }
135
+ catch (_a) {
136
+ try {
137
+ d.close();
138
+ }
139
+ catch (_b) {
140
+ }
141
+ }
142
+ return {
143
+ id: getDeviceId(d),
144
+ name,
145
+ commType: 'usb',
146
+ };
147
+ });
148
+ });
149
+ },
150
+ connect(uuid) {
151
+ return __awaiter(this, void 0, void 0, function* () {
152
+ const existing = openDevices.get(uuid);
153
+ if (existing) {
154
+ activeDevice = existing;
155
+ return;
156
+ }
157
+ const allDevices = usb__namespace.getDeviceList();
158
+ const dev = allDevices.find(d => getDeviceId(d) === uuid);
159
+ if (!dev) {
160
+ throw new Error(`USB device not found: ${uuid}`);
161
+ }
162
+ dev.open();
163
+ dev.timeout = TRANSFER_TIMEOUT_MS;
164
+ const iface = dev.interface(INTERFACE_NUMBER);
165
+ if (process.platform === 'linux') {
166
+ try {
167
+ if (iface.isKernelDriverActive()) {
168
+ iface.detachKernelDriver();
169
+ }
170
+ }
171
+ catch (_a) {
172
+ }
173
+ }
174
+ iface.claim();
175
+ const epIn = iface.endpoints.find((e) => e.direction === 'in' && e.address === ENDPOINT_IN);
176
+ const epOut = iface.endpoints.find((e) => e.direction === 'out' && e.address === ENDPOINT_OUT);
177
+ if (!epIn || !epOut) {
178
+ dev.close();
179
+ throw new Error('USB endpoints not found (expected IN 0x81, OUT 0x01)');
180
+ }
181
+ epIn.timeout = TRANSFER_TIMEOUT_MS;
182
+ epOut.timeout = TRANSFER_TIMEOUT_MS;
183
+ const openDev = { device: dev, iface, epIn, epOut };
184
+ openDevices.set(uuid, openDev);
185
+ activeDevice = openDev;
186
+ });
187
+ },
188
+ disconnect(uuid) {
189
+ return __awaiter(this, void 0, void 0, function* () {
190
+ const openDev = openDevices.get(uuid);
191
+ if (openDev) {
192
+ try {
193
+ openDev.iface.release(() => {
194
+ try {
195
+ openDev.device.close();
196
+ }
197
+ catch (_a) {
198
+ }
199
+ });
200
+ }
201
+ catch (_a) {
202
+ try {
203
+ openDev.device.close();
204
+ }
205
+ catch (_b) {
206
+ }
207
+ }
208
+ openDevices.delete(uuid);
209
+ if (activeDevice === openDev) {
210
+ activeDevice = null;
211
+ }
212
+ }
213
+ });
214
+ },
215
+ send(uuid, data) {
216
+ return __awaiter(this, void 0, void 0, function* () {
217
+ const openDev = openDevices.get(uuid);
218
+ if (!openDev) {
219
+ throw new Error(`Device not connected: ${uuid}`);
220
+ }
221
+ activeDevice = openDev;
222
+ const dataBuffer = Buffer.from(data, 'hex');
223
+ yield transferOut(openDev.epOut, dataBuffer);
224
+ });
225
+ },
226
+ receive() {
227
+ return __awaiter(this, void 0, void 0, function* () {
228
+ if (!activeDevice) {
229
+ throw new Error('No active device for receive');
230
+ }
231
+ const dev = activeDevice;
232
+ const firstPacket = yield readPacket(dev);
233
+ const firstData = skipReportByte(firstPacket);
234
+ const { length, typeId, restBuffer } = decodeProtocol.decodeChunked(toArrayBuffer(firstData));
235
+ const lengthWithHeader = Number(length) + HEADER_LENGTH;
236
+ const decoded = new ByteBuffer__default["default"](lengthWithHeader);
237
+ decoded.writeUint16(typeId);
238
+ decoded.writeUint32(Number(length));
239
+ if (length) {
240
+ decoded.append(restBuffer);
241
+ }
242
+ while (decoded.offset < lengthWithHeader) {
243
+ const packet = yield readPacket(dev);
244
+ const pktData = skipReportByte(packet);
245
+ const buf = toArrayBuffer(pktData);
246
+ if (lengthWithHeader - decoded.offset >= PACKET_SIZE) {
247
+ decoded.append(buf);
248
+ }
249
+ else {
250
+ decoded.append(buf.slice(0, lengthWithHeader - decoded.offset));
251
+ }
252
+ }
253
+ decoded.reset();
254
+ const result = decoded.toBuffer();
255
+ return Buffer.from(result).toString('hex');
256
+ });
257
+ },
258
+ };
259
+
260
+ exports.PACKET_SIZE = PACKET_SIZE;
261
+ exports.UsbPlugin = UsbPlugin;
262
+ exports["default"] = UsbPlugin;
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@onekeyfe/hd-transport-usb",
3
+ "version": "1.1.25-alpha.0",
4
+ "description": "OneKey hardware wallet direct USB transport plugin (libusb)",
5
+ "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
6
+ "license": "MIT",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/OneKeyHQ/hardware-js-sdk.git"
15
+ },
16
+ "scripts": {
17
+ "dev": "rimraf dist && rollup -c ../../build/rollup.config.js -w",
18
+ "build": "rimraf dist && rollup -c ../../build/rollup.config.js",
19
+ "lint": "eslint .",
20
+ "lint:fix": "eslint . --fix"
21
+ },
22
+ "dependencies": {
23
+ "@onekeyfe/hd-shared": "1.1.25-alpha.0",
24
+ "@onekeyfe/hd-transport": "1.1.25-alpha.0",
25
+ "bytebuffer": "^5.0.1",
26
+ "usb": "^2.14.0"
27
+ },
28
+ "gitHead": "8cebdb9dea32ab8bfa39c51cd695f5cd9508defa"
29
+ }
@@ -0,0 +1,8 @@
1
+ /** USB packet size in bytes */
2
+ export const PACKET_SIZE = 64;
3
+
4
+ /** Protocol marker byte (0x3F = '?') — first byte of every packet */
5
+ export const REPORT_ID = 0x3f;
6
+
7
+ /** Protocol header length: typeId (2 bytes) + length (4 bytes) */
8
+ export const HEADER_LENGTH = 6;
package/src/index.ts ADDED
@@ -0,0 +1,291 @@
1
+ import ByteBuffer from 'bytebuffer';
2
+ import * as usb from 'usb';
3
+ import transport from '@onekeyfe/hd-transport';
4
+ import { ONEKEY_WEBUSB_FILTER } from '@onekeyfe/hd-shared';
5
+
6
+ import { HEADER_LENGTH, PACKET_SIZE, REPORT_ID } from './constants';
7
+
8
+ import type { LowLevelDevice, LowlevelTransportSharedPlugin } from '@onekeyfe/hd-transport';
9
+
10
+ const { decodeProtocol } = transport;
11
+
12
+ /** USB interface number for vendor-specific communication */
13
+ const INTERFACE_NUMBER = 0;
14
+ /** USB endpoint addresses */
15
+ const ENDPOINT_IN = 0x81;
16
+ const ENDPOINT_OUT = 0x01;
17
+
18
+ /** Transfer timeout in milliseconds */
19
+ const TRANSFER_TIMEOUT_MS = 30000;
20
+
21
+ /**
22
+ * Opened device state — holds the USB device, claimed interface, and endpoints.
23
+ */
24
+ interface OpenDevice {
25
+ device: usb.Device;
26
+ iface: usb.Interface;
27
+ epIn: usb.InEndpoint;
28
+ epOut: usb.OutEndpoint;
29
+ }
30
+
31
+ /**
32
+ * The currently active device — used by receive() since
33
+ * LowlevelTransportSharedPlugin.receive() takes no uuid parameter.
34
+ */
35
+ let activeDevice: OpenDevice | null = null;
36
+
37
+ /** Map of uuid → open device state */
38
+ const openDevices = new Map<string, OpenDevice>();
39
+
40
+ /**
41
+ * Build a unique identifier for a USB device.
42
+ * Uses bus number + device address which is stable within a session.
43
+ */
44
+ function getDeviceId(dev: usb.Device): string {
45
+ return `usb:${dev.busNumber}:${dev.deviceAddress}`;
46
+ }
47
+
48
+ /**
49
+ * Promisified USB IN transfer.
50
+ */
51
+ function transferIn(ep: usb.InEndpoint, length: number): Promise<Buffer> {
52
+ return new Promise((resolve, reject) => {
53
+ ep.transfer(length, (err: Error | undefined, data: Buffer | undefined) => {
54
+ if (err) return reject(err);
55
+ if (!data || data.length === 0) return reject(new Error('Empty USB transfer'));
56
+ resolve(data);
57
+ });
58
+ });
59
+ }
60
+
61
+ /**
62
+ * Promisified USB OUT transfer.
63
+ */
64
+ function transferOut(ep: usb.OutEndpoint, data: Buffer): Promise<void> {
65
+ return new Promise((resolve, reject) => {
66
+ ep.transfer(data, (err: Error | undefined) => {
67
+ if (err) return reject(err);
68
+ resolve();
69
+ });
70
+ });
71
+ }
72
+
73
+ /**
74
+ * Read a single 64-byte packet from the device via libusb bulk/interrupt transfer.
75
+ */
76
+ async function readPacket(dev: OpenDevice): Promise<Buffer> {
77
+ return transferIn(dev.epIn, PACKET_SIZE);
78
+ }
79
+
80
+ /**
81
+ * Skip the 0x3F protocol marker byte from a USB packet.
82
+ * The device sends 0x3F as the first byte of every response packet.
83
+ */
84
+ function skipReportByte(packet: Buffer): Buffer {
85
+ if (packet[0] === REPORT_ID) {
86
+ return packet.subarray(1);
87
+ }
88
+ return packet;
89
+ }
90
+
91
+ /**
92
+ * Convert a Buffer to ArrayBuffer (required by decodeChunked).
93
+ */
94
+ function toArrayBuffer(buf: Buffer): ArrayBuffer {
95
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
96
+ }
97
+
98
+ /**
99
+ * Node.js USB plugin for LowlevelTransport.
100
+ *
101
+ * Implements the 6-method LowlevelTransportSharedPlugin interface
102
+ * using the `usb` (libusb) library for direct USB communication
103
+ * with OneKey hardware wallets.
104
+ *
105
+ * Uses libusb to access the vendor-specific interface (class 255)
106
+ * which is NOT visible to the HID framework on macOS.
107
+ */
108
+ export const UsbPlugin: LowlevelTransportSharedPlugin = {
109
+ version: '1.0.0',
110
+
111
+ async init(): Promise<void> {
112
+ // libusb requires no global initialization
113
+ },
114
+
115
+ // eslint-disable-next-line @typescript-eslint/require-await
116
+ async enumerate(): Promise<LowLevelDevice[]> {
117
+ const allDevices = usb.getDeviceList();
118
+
119
+ const onekeyDevices = allDevices.filter(d => {
120
+ const { idVendor, idProduct } = d.deviceDescriptor;
121
+ return ONEKEY_WEBUSB_FILTER.some(f => idVendor === f.vendorId && idProduct === f.productId);
122
+ });
123
+
124
+ return onekeyDevices.map(d => {
125
+ // Try to get product name
126
+ let name = 'OneKey';
127
+ try {
128
+ d.open();
129
+ const iface = d.interface(INTERFACE_NUMBER);
130
+ // Check interface class is 255 (vendor-specific) — the communication interface
131
+ if (iface && iface.descriptor.bInterfaceClass === 255) {
132
+ name = 'OneKey';
133
+ }
134
+ d.close();
135
+ } catch {
136
+ // Can't open — might be in use, just return basic info
137
+ try {
138
+ d.close();
139
+ } catch {
140
+ /* ignore */
141
+ }
142
+ }
143
+
144
+ return {
145
+ id: getDeviceId(d),
146
+ name,
147
+ commType: 'usb' as const,
148
+ };
149
+ });
150
+ },
151
+
152
+ // eslint-disable-next-line @typescript-eslint/require-await
153
+ async connect(uuid: string): Promise<void> {
154
+ const existing = openDevices.get(uuid);
155
+ if (existing) {
156
+ activeDevice = existing;
157
+ return;
158
+ }
159
+
160
+ // Find the device by our uuid (bus:address)
161
+ const allDevices = usb.getDeviceList();
162
+ const dev = allDevices.find(d => getDeviceId(d) === uuid);
163
+ if (!dev) {
164
+ throw new Error(`USB device not found: ${uuid}`);
165
+ }
166
+
167
+ dev.open();
168
+ dev.timeout = TRANSFER_TIMEOUT_MS;
169
+
170
+ const iface = dev.interface(INTERFACE_NUMBER);
171
+
172
+ // On Linux, detach kernel driver if active
173
+ if (process.platform === 'linux') {
174
+ try {
175
+ if (iface.isKernelDriverActive()) {
176
+ iface.detachKernelDriver();
177
+ }
178
+ } catch {
179
+ // May not be supported — continue
180
+ }
181
+ }
182
+
183
+ iface.claim();
184
+
185
+ // Find IN and OUT endpoints
186
+ const epIn = iface.endpoints.find(
187
+ (e): e is usb.InEndpoint => e.direction === 'in' && e.address === ENDPOINT_IN
188
+ );
189
+ const epOut = iface.endpoints.find(
190
+ (e): e is usb.OutEndpoint => e.direction === 'out' && e.address === ENDPOINT_OUT
191
+ );
192
+
193
+ if (!epIn || !epOut) {
194
+ dev.close();
195
+ throw new Error('USB endpoints not found (expected IN 0x81, OUT 0x01)');
196
+ }
197
+
198
+ epIn.timeout = TRANSFER_TIMEOUT_MS;
199
+ epOut.timeout = TRANSFER_TIMEOUT_MS;
200
+
201
+ const openDev: OpenDevice = { device: dev, iface, epIn, epOut };
202
+ openDevices.set(uuid, openDev);
203
+ activeDevice = openDev;
204
+ },
205
+
206
+ // eslint-disable-next-line @typescript-eslint/require-await
207
+ async disconnect(uuid: string): Promise<void> {
208
+ const openDev = openDevices.get(uuid);
209
+ if (openDev) {
210
+ try {
211
+ openDev.iface.release(() => {
212
+ try {
213
+ openDev.device.close();
214
+ } catch {
215
+ /* ignore */
216
+ }
217
+ });
218
+ } catch {
219
+ try {
220
+ openDev.device.close();
221
+ } catch {
222
+ /* ignore */
223
+ }
224
+ }
225
+ openDevices.delete(uuid);
226
+ if (activeDevice === openDev) {
227
+ activeDevice = null;
228
+ }
229
+ }
230
+ },
231
+
232
+ async send(uuid: string, data: string): Promise<void> {
233
+ const openDev = openDevices.get(uuid);
234
+ if (!openDev) {
235
+ throw new Error(`Device not connected: ${uuid}`);
236
+ }
237
+ activeDevice = openDev;
238
+
239
+ // data is a hex string of a 64-byte packet (0x3F + 63 bytes payload),
240
+ // already framed by LowlevelTransport's buildBuffers().
241
+ const dataBuffer = Buffer.from(data, 'hex');
242
+
243
+ // libusb transfers the raw packet directly — no Report ID prepend needed
244
+ // (Report ID is a HID concept; libusb operates at USB level)
245
+ await transferOut(openDev.epOut, dataBuffer);
246
+ },
247
+
248
+ async receive(): Promise<string> {
249
+ if (!activeDevice) {
250
+ throw new Error('No active device for receive');
251
+ }
252
+ const dev = activeDevice;
253
+
254
+ // Mirrors WebUsbTransport.receiveData() exactly:
255
+ // 1. Read first 64-byte packet, skip byte[0] (0x3F marker)
256
+ const firstPacket = await readPacket(dev);
257
+ const firstData = skipReportByte(firstPacket);
258
+
259
+ // 2. Use SDK's decodeChunked to parse ## header → { typeId, length, restBuffer }
260
+ const { length, typeId, restBuffer } = decodeProtocol.decodeChunked(toArrayBuffer(firstData));
261
+
262
+ // 3. Allocate result buffer: typeId(2) + length(4) + payload(length)
263
+ const lengthWithHeader = Number(length) + HEADER_LENGTH;
264
+ const decoded = new ByteBuffer(lengthWithHeader);
265
+ decoded.writeUint16(typeId);
266
+ decoded.writeUint32(Number(length));
267
+ if (length) {
268
+ decoded.append(restBuffer);
269
+ }
270
+
271
+ // 4. Read subsequent packets until complete
272
+ while (decoded.offset < lengthWithHeader) {
273
+ const packet = await readPacket(dev);
274
+ const pktData = skipReportByte(packet);
275
+ const buf = toArrayBuffer(pktData);
276
+ if (lengthWithHeader - decoded.offset >= PACKET_SIZE) {
277
+ decoded.append(buf);
278
+ } else {
279
+ decoded.append(buf.slice(0, lengthWithHeader - decoded.offset));
280
+ }
281
+ }
282
+
283
+ // 5. Return as hex string
284
+ decoded.reset();
285
+ const result = decoded.toBuffer();
286
+ return Buffer.from(result as unknown as ArrayBuffer).toString('hex');
287
+ },
288
+ };
289
+
290
+ export default UsbPlugin;
291
+ export { PACKET_SIZE } from './constants';
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../tsconfig.lib.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist"
5
+ },
6
+ "include": ["./src"]
7
+ }