@onekeyfe/hwk-trezor-connector-electron-ble 1.2.2-alpha.9 → 1.2.3-alpha.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.
- package/dist/index.d.mts +21 -7
- package/dist/index.d.ts +21 -7
- package/dist/index.js +38 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +30 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -25
- package/dist/chunk-CFZTAWFZ.mjs +0 -41
- package/dist/chunk-CFZTAWFZ.mjs.map +0 -1
- package/dist/constants.d.mts +0 -36
- package/dist/constants.d.ts +0 -36
- package/dist/constants.js +0 -62
- package/dist/constants.js.map +0 -1
- package/dist/constants.mjs +0 -17
- package/dist/constants.mjs.map +0 -1
- package/dist/desktop-api-DDNonbNW.d.mts +0 -77
- package/dist/desktop-api-DDNonbNW.d.ts +0 -77
- package/dist/main.d.mts +0 -260
- package/dist/main.d.ts +0 -260
- package/dist/main.js +0 -703
- package/dist/main.js.map +0 -1
- package/dist/main.mjs +0 -667
- package/dist/main.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { TrezorDebugLogger, TrezorConnectorBase, TrezorConnectorBaseOptions, TrezorConnectorByteTransport } from '@onekeyfe/hwk-trezor-connector';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { ConnectorDevice } from '@onekeyfe/hwk-adapter-core';
|
|
5
|
-
export { TREZOR_BLE_CHANNELS, TREZOR_BLE_POWER_ON_TIMEOUT_MS, TREZOR_BLE_SCAN_DURATION_MS, TREZOR_BLE_WRITE_CHUNK_DELAY_MS, TrezorBleChannel } from './constants.mjs';
|
|
2
|
+
import { ThirdPartyBleApi, ThirdPartyBleDeviceInfo } from '@onekeyfe/hwk-desktop-noble-ble';
|
|
3
|
+
import { ConnectorDevice, ElectronBleConnectOptions, ElectronBleMatch } from '@onekeyfe/hwk-adapter-core';
|
|
6
4
|
|
|
7
5
|
interface TrezorElectronBleTransportOptions {
|
|
8
6
|
/** The IPC bridge exposed by the main process (typically `window.desktopApi.trezorBle`). */
|
|
9
|
-
bridge?:
|
|
7
|
+
bridge?: ThirdPartyBleApi;
|
|
10
8
|
logger?: TrezorDebugLogger;
|
|
11
9
|
}
|
|
12
10
|
/**
|
|
@@ -24,7 +22,7 @@ declare class TrezorElectronBleTransport {
|
|
|
24
22
|
private _disposeDisconnectListener?;
|
|
25
23
|
private readonly _logger?;
|
|
26
24
|
constructor(options?: TrezorElectronBleTransportOptions);
|
|
27
|
-
scan(durationMs?: number): Promise<
|
|
25
|
+
scan(durationMs?: number): Promise<ThirdPartyBleDeviceInfo[]>;
|
|
28
26
|
stopScan(): Promise<void>;
|
|
29
27
|
/** Abandon the in-flight connect/pairing in the main process. */
|
|
30
28
|
cancelPairing(): Promise<void>;
|
|
@@ -62,4 +60,20 @@ declare class TrezorElectronBleConnector extends TrezorConnectorBase {
|
|
|
62
60
|
}
|
|
63
61
|
declare function createTrezorElectronBleConnector(options?: TrezorElectronBleConnectorOptions): TrezorElectronBleConnector;
|
|
64
62
|
|
|
65
|
-
|
|
63
|
+
/** Inter-chunk delay during write, matches OneKey's `UNIFIED_WRITE_DELAY`. */
|
|
64
|
+
declare const TREZOR_BLE_WRITE_CHUNK_DELAY_MS = 5;
|
|
65
|
+
declare const TREZOR_BLE_VENDOR = "trezor";
|
|
66
|
+
/**
|
|
67
|
+
* How the shared desktop handler recognizes a Trezor. The main process holds
|
|
68
|
+
* no vendor knowledge, so the name test that used to live there travels as
|
|
69
|
+
* data: a local name must satisfy every pattern, which reproduces
|
|
70
|
+
* `isTrezorSafe7BleName` — "Trezor" plus either "Safe 7" or "T3W1".
|
|
71
|
+
*/
|
|
72
|
+
declare const TREZOR_BLE_MATCH: ElectronBleMatch;
|
|
73
|
+
/**
|
|
74
|
+
* Trezor firmware expects fixed-size packets: a short final packet is silently
|
|
75
|
+
* dropped, so every write is padded to the full MTU.
|
|
76
|
+
*/
|
|
77
|
+
declare const TREZOR_BLE_CONNECT_PROFILE: ElectronBleConnectOptions;
|
|
78
|
+
|
|
79
|
+
export { TREZOR_BLE_CONNECT_PROFILE, TREZOR_BLE_MATCH, TREZOR_BLE_VENDOR, TREZOR_BLE_WRITE_CHUNK_DELAY_MS, TrezorElectronBleConnector, type TrezorElectronBleConnectorOptions, TrezorElectronBleTransport, type TrezorElectronBleTransportOptions, createTrezorElectronBleConnector, createTrezorElectronBleTransport };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { TrezorDebugLogger, TrezorConnectorBase, TrezorConnectorBaseOptions, TrezorConnectorByteTransport } from '@onekeyfe/hwk-trezor-connector';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { ConnectorDevice } from '@onekeyfe/hwk-adapter-core';
|
|
5
|
-
export { TREZOR_BLE_CHANNELS, TREZOR_BLE_POWER_ON_TIMEOUT_MS, TREZOR_BLE_SCAN_DURATION_MS, TREZOR_BLE_WRITE_CHUNK_DELAY_MS, TrezorBleChannel } from './constants.js';
|
|
2
|
+
import { ThirdPartyBleApi, ThirdPartyBleDeviceInfo } from '@onekeyfe/hwk-desktop-noble-ble';
|
|
3
|
+
import { ConnectorDevice, ElectronBleConnectOptions, ElectronBleMatch } from '@onekeyfe/hwk-adapter-core';
|
|
6
4
|
|
|
7
5
|
interface TrezorElectronBleTransportOptions {
|
|
8
6
|
/** The IPC bridge exposed by the main process (typically `window.desktopApi.trezorBle`). */
|
|
9
|
-
bridge?:
|
|
7
|
+
bridge?: ThirdPartyBleApi;
|
|
10
8
|
logger?: TrezorDebugLogger;
|
|
11
9
|
}
|
|
12
10
|
/**
|
|
@@ -24,7 +22,7 @@ declare class TrezorElectronBleTransport {
|
|
|
24
22
|
private _disposeDisconnectListener?;
|
|
25
23
|
private readonly _logger?;
|
|
26
24
|
constructor(options?: TrezorElectronBleTransportOptions);
|
|
27
|
-
scan(durationMs?: number): Promise<
|
|
25
|
+
scan(durationMs?: number): Promise<ThirdPartyBleDeviceInfo[]>;
|
|
28
26
|
stopScan(): Promise<void>;
|
|
29
27
|
/** Abandon the in-flight connect/pairing in the main process. */
|
|
30
28
|
cancelPairing(): Promise<void>;
|
|
@@ -62,4 +60,20 @@ declare class TrezorElectronBleConnector extends TrezorConnectorBase {
|
|
|
62
60
|
}
|
|
63
61
|
declare function createTrezorElectronBleConnector(options?: TrezorElectronBleConnectorOptions): TrezorElectronBleConnector;
|
|
64
62
|
|
|
65
|
-
|
|
63
|
+
/** Inter-chunk delay during write, matches OneKey's `UNIFIED_WRITE_DELAY`. */
|
|
64
|
+
declare const TREZOR_BLE_WRITE_CHUNK_DELAY_MS = 5;
|
|
65
|
+
declare const TREZOR_BLE_VENDOR = "trezor";
|
|
66
|
+
/**
|
|
67
|
+
* How the shared desktop handler recognizes a Trezor. The main process holds
|
|
68
|
+
* no vendor knowledge, so the name test that used to live there travels as
|
|
69
|
+
* data: a local name must satisfy every pattern, which reproduces
|
|
70
|
+
* `isTrezorSafe7BleName` — "Trezor" plus either "Safe 7" or "T3W1".
|
|
71
|
+
*/
|
|
72
|
+
declare const TREZOR_BLE_MATCH: ElectronBleMatch;
|
|
73
|
+
/**
|
|
74
|
+
* Trezor firmware expects fixed-size packets: a short final packet is silently
|
|
75
|
+
* dropped, so every write is padded to the full MTU.
|
|
76
|
+
*/
|
|
77
|
+
declare const TREZOR_BLE_CONNECT_PROFILE: ElectronBleConnectOptions;
|
|
78
|
+
|
|
79
|
+
export { TREZOR_BLE_CONNECT_PROFILE, TREZOR_BLE_MATCH, TREZOR_BLE_VENDOR, TREZOR_BLE_WRITE_CHUNK_DELAY_MS, TrezorElectronBleConnector, type TrezorElectronBleConnectorOptions, TrezorElectronBleTransport, type TrezorElectronBleTransportOptions, createTrezorElectronBleConnector, createTrezorElectronBleTransport };
|
package/dist/index.js
CHANGED
|
@@ -20,9 +20,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
TREZOR_BLE_CONNECT_PROFILE: () => TREZOR_BLE_CONNECT_PROFILE,
|
|
24
|
+
TREZOR_BLE_MATCH: () => TREZOR_BLE_MATCH,
|
|
25
|
+
TREZOR_BLE_VENDOR: () => TREZOR_BLE_VENDOR,
|
|
26
26
|
TREZOR_BLE_WRITE_CHUNK_DELAY_MS: () => TREZOR_BLE_WRITE_CHUNK_DELAY_MS,
|
|
27
27
|
TrezorElectronBleConnector: () => TrezorElectronBleConnector,
|
|
28
28
|
TrezorElectronBleTransport: () => TrezorElectronBleTransport,
|
|
@@ -33,7 +33,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
33
33
|
|
|
34
34
|
// src/TrezorElectronBleConnector.ts
|
|
35
35
|
var import_buffer2 = require("buffer");
|
|
36
|
-
var
|
|
36
|
+
var import_hwk_trezor_adapter2 = require("@onekeyfe/hwk-trezor-adapter");
|
|
37
37
|
var import_hwk_adapter_core2 = require("@onekeyfe/hwk-adapter-core");
|
|
38
38
|
var import_hwk_trezor_connector2 = require("@onekeyfe/hwk-trezor-connector");
|
|
39
39
|
|
|
@@ -41,6 +41,28 @@ var import_hwk_trezor_connector2 = require("@onekeyfe/hwk-trezor-connector");
|
|
|
41
41
|
var import_buffer = require("buffer");
|
|
42
42
|
var import_hwk_adapter_core = require("@onekeyfe/hwk-adapter-core");
|
|
43
43
|
var import_hwk_trezor_connector = require("@onekeyfe/hwk-trezor-connector");
|
|
44
|
+
|
|
45
|
+
// src/bleProfile.ts
|
|
46
|
+
var import_hwk_trezor_adapter = require("@onekeyfe/hwk-trezor-adapter");
|
|
47
|
+
var TREZOR_BLE_WRITE_CHUNK_DELAY_MS = 5;
|
|
48
|
+
var TREZOR_BLE_VENDOR = "trezor";
|
|
49
|
+
var TREZOR_BLE_MATCH = {
|
|
50
|
+
serviceUuids: [import_hwk_trezor_adapter.TREZOR_BLE_UUIDS.service],
|
|
51
|
+
namePatterns: ["\\bTrezor\\b", "\\bSafe\\s*7\\b|\\bT3W1\\b"]
|
|
52
|
+
};
|
|
53
|
+
var TREZOR_BLE_CONNECT_PROFILE = {
|
|
54
|
+
vendor: TREZOR_BLE_VENDOR,
|
|
55
|
+
serviceUuid: import_hwk_trezor_adapter.TREZOR_BLE_UUIDS.service,
|
|
56
|
+
writeUuid: import_hwk_trezor_adapter.TREZOR_BLE_UUIDS.write,
|
|
57
|
+
notifyUuid: import_hwk_trezor_adapter.TREZOR_BLE_UUIDS.notify,
|
|
58
|
+
write: {
|
|
59
|
+
mode: "padded",
|
|
60
|
+
chunkSize: import_hwk_trezor_adapter.TREZOR_BLE_PACKET_SIZE,
|
|
61
|
+
chunkDelayMs: TREZOR_BLE_WRITE_CHUNK_DELAY_MS
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/TrezorElectronBleTransport.ts
|
|
44
66
|
var disconnectError = (message) => Object.assign(new Error(message), { code: import_hwk_adapter_core.HardwareErrorCode.DeviceDisconnected });
|
|
45
67
|
var notConnectedError = (id) => disconnectError(`Trezor Electron BLE device is not connected: ${id}`);
|
|
46
68
|
var resolveBridge = (options) => {
|
|
@@ -68,6 +90,8 @@ var TrezorElectronBleTransport = class {
|
|
|
68
90
|
async scan(durationMs) {
|
|
69
91
|
try {
|
|
70
92
|
return await this._bridge.scan({
|
|
93
|
+
vendor: TREZOR_BLE_VENDOR,
|
|
94
|
+
match: TREZOR_BLE_MATCH,
|
|
71
95
|
durationMs
|
|
72
96
|
});
|
|
73
97
|
} catch (error) {
|
|
@@ -86,7 +110,7 @@ var TrezorElectronBleTransport = class {
|
|
|
86
110
|
}
|
|
87
111
|
async connect(connectId) {
|
|
88
112
|
if (this._connected.has(connectId)) return;
|
|
89
|
-
await this._bridge.connect(connectId);
|
|
113
|
+
await this._bridge.connect(connectId, TREZOR_BLE_CONNECT_PROFILE);
|
|
90
114
|
try {
|
|
91
115
|
await this._bridge.subscribe(connectId);
|
|
92
116
|
} catch (error) {
|
|
@@ -198,7 +222,7 @@ var TrezorElectronBleConnector = class extends import_hwk_trezor_connector2.Trez
|
|
|
198
222
|
constructor(options) {
|
|
199
223
|
super({
|
|
200
224
|
connectionType: "ble",
|
|
201
|
-
chunkSize:
|
|
225
|
+
chunkSize: import_hwk_trezor_adapter2.TREZOR_BLE_PACKET_SIZE,
|
|
202
226
|
thp: options?.thp,
|
|
203
227
|
deviceSessionFactory: options?.deviceSessionFactory
|
|
204
228
|
});
|
|
@@ -209,13 +233,13 @@ var TrezorElectronBleConnector = class extends import_hwk_trezor_connector2.Trez
|
|
|
209
233
|
async enumerateDevices() {
|
|
210
234
|
const transport = this._ensureTransport();
|
|
211
235
|
const devices = await transport.scan();
|
|
212
|
-
const filtered = devices.filter(
|
|
236
|
+
const filtered = devices.filter(import_hwk_trezor_adapter2.isTrezorBleDescriptor);
|
|
213
237
|
if (filtered.length !== devices.length) {
|
|
214
238
|
this._log("info", "ble.connector.enumerate.filtered", {
|
|
215
239
|
transport: "electron-ble",
|
|
216
240
|
descriptorCount: devices.length,
|
|
217
241
|
filteredCount: filtered.length,
|
|
218
|
-
dropped: devices.filter((device) => !(0,
|
|
242
|
+
dropped: devices.filter((device) => !(0, import_hwk_trezor_adapter2.isTrezorBleDescriptor)(device)).map(toBleFilterLogSample),
|
|
219
243
|
kept: filtered.map(toBleFilterLogSample)
|
|
220
244
|
});
|
|
221
245
|
}
|
|
@@ -223,7 +247,7 @@ var TrezorElectronBleConnector = class extends import_hwk_trezor_connector2.Trez
|
|
|
223
247
|
connectId: d.id,
|
|
224
248
|
deviceId: "",
|
|
225
249
|
name: d.name ?? d.localName ?? "Trezor Safe 7",
|
|
226
|
-
model:
|
|
250
|
+
model: import_hwk_trezor_adapter2.TREZOR_SAFE_7_MODEL,
|
|
227
251
|
connectionType: "ble",
|
|
228
252
|
// Promote the typed BLE fields the device surface already has slots for.
|
|
229
253
|
rssi: d.rssi ?? null,
|
|
@@ -285,7 +309,7 @@ var TrezorElectronBleConnector = class extends import_hwk_trezor_connector2.Trez
|
|
|
285
309
|
connectId,
|
|
286
310
|
deviceId: "",
|
|
287
311
|
name: "Trezor Safe 7",
|
|
288
|
-
model:
|
|
312
|
+
model: import_hwk_trezor_adapter2.TREZOR_SAFE_7_MODEL,
|
|
289
313
|
capabilities: { persistentDeviceIdentity: false }
|
|
290
314
|
};
|
|
291
315
|
}
|
|
@@ -332,7 +356,7 @@ function toBleFilterLogSample(device) {
|
|
|
332
356
|
rssi: device.rssi,
|
|
333
357
|
isConnectable: device.isConnectable,
|
|
334
358
|
keys: Object.keys(device).sort(),
|
|
335
|
-
matchesTrezorService: (0,
|
|
359
|
+
matchesTrezorService: (0, import_hwk_trezor_adapter2.isTrezorBleDescriptor)(device),
|
|
336
360
|
serviceUUIDs: readStringArrayField(device, "serviceUUIDs"),
|
|
337
361
|
serviceUuids: readStringArrayField(device, "serviceUuids"),
|
|
338
362
|
advertisedServiceUuids: readStringArrayField(device, "advertisedServiceUuids"),
|
|
@@ -345,33 +369,11 @@ function toBleFilterLogSample(device) {
|
|
|
345
369
|
state: device.state
|
|
346
370
|
};
|
|
347
371
|
}
|
|
348
|
-
|
|
349
|
-
// src/constants.ts
|
|
350
|
-
var TREZOR_BLE_CHANNELS = {
|
|
351
|
-
scan: "$onekey-trezor-ble-scan",
|
|
352
|
-
stopScan: "$onekey-trezor-ble-stop-scan",
|
|
353
|
-
connect: "$onekey-trezor-ble-connect",
|
|
354
|
-
disconnect: "$onekey-trezor-ble-disconnect",
|
|
355
|
-
write: "$onekey-trezor-ble-write",
|
|
356
|
-
subscribe: "$onekey-trezor-ble-subscribe",
|
|
357
|
-
unsubscribe: "$onekey-trezor-ble-unsubscribe",
|
|
358
|
-
availability: "$onekey-trezor-ble-availability",
|
|
359
|
-
getDevice: "$onekey-trezor-ble-get-device",
|
|
360
|
-
readRssi: "$onekey-trezor-ble-read-rssi",
|
|
361
|
-
cancelPairing: "$onekey-trezor-ble-cancel-pairing",
|
|
362
|
-
/** push event: main → renderer with assembled BLE notification payload */
|
|
363
|
-
notification: "$onekey-trezor-ble-notification",
|
|
364
|
-
/** push event: main → renderer when device disconnects unexpectedly */
|
|
365
|
-
disconnected: "$onekey-trezor-ble-disconnected"
|
|
366
|
-
};
|
|
367
|
-
var TREZOR_BLE_SCAN_DURATION_MS = 5e3;
|
|
368
|
-
var TREZOR_BLE_POWER_ON_TIMEOUT_MS = 1e4;
|
|
369
|
-
var TREZOR_BLE_WRITE_CHUNK_DELAY_MS = 5;
|
|
370
372
|
// Annotate the CommonJS export names for ESM import in node:
|
|
371
373
|
0 && (module.exports = {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
374
|
+
TREZOR_BLE_CONNECT_PROFILE,
|
|
375
|
+
TREZOR_BLE_MATCH,
|
|
376
|
+
TREZOR_BLE_VENDOR,
|
|
375
377
|
TREZOR_BLE_WRITE_CHUNK_DELAY_MS,
|
|
376
378
|
TrezorElectronBleConnector,
|
|
377
379
|
TrezorElectronBleTransport,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/TrezorElectronBleConnector.ts","../src/TrezorElectronBleTransport.ts","../src/constants.ts"],"sourcesContent":["export {\n TrezorElectronBleConnector,\n createTrezorElectronBleConnector,\n} from './TrezorElectronBleConnector';\nexport type { TrezorElectronBleConnectorOptions } from './TrezorElectronBleConnector';\n\nexport {\n TrezorElectronBleTransport,\n createTrezorElectronBleTransport,\n} from './TrezorElectronBleTransport';\nexport type { TrezorElectronBleTransportOptions } from './TrezorElectronBleTransport';\n\nexport {\n TREZOR_BLE_CHANNELS,\n TREZOR_BLE_SCAN_DURATION_MS,\n TREZOR_BLE_POWER_ON_TIMEOUT_MS,\n TREZOR_BLE_WRITE_CHUNK_DELAY_MS,\n} from './constants';\nexport type { TrezorBleChannel } from './constants';\n\nexport type { TrezorBleApi, TrezorBleAvailability, TrezorBleDeviceInfo } from './types/desktop-api';\n","import { Buffer } from 'buffer';\nimport {\n TREZOR_BLE_PACKET_SIZE,\n TREZOR_SAFE_7_MODEL,\n isTrezorBleDescriptor,\n} from '@onekeyfe/hwk-trezor-adapter';\nimport { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport {\n TrezorConnectorBase,\n type TrezorConnectorBaseOptions,\n type TrezorConnectorByteTransport,\n type TrezorDebugLogLevel,\n type TrezorDebugLogger,\n filterTrezorDebugLogEntry,\n} from '@onekeyfe/hwk-trezor-connector';\n\nimport {\n TrezorElectronBleTransport,\n type TrezorElectronBleTransportOptions,\n} from './TrezorElectronBleTransport';\n\nimport type { ConnectorDevice } from '@onekeyfe/hwk-adapter-core';\nimport type { TrezorBleDeviceInfo } from './types/desktop-api';\n\nconst isStandardHwkError = (error: unknown): error is { code: number } =>\n typeof (error as { code?: unknown })?.code === 'number';\n\nexport interface TrezorElectronBleConnectorOptions {\n transport?: TrezorElectronBleTransport;\n transportOptions?: TrezorElectronBleTransportOptions;\n thp?: TrezorConnectorBaseOptions['thp'];\n deviceSessionFactory?: TrezorConnectorBaseOptions['deviceSessionFactory'];\n}\n\nexport class TrezorElectronBleConnector extends TrezorConnectorBase {\n private _transport: TrezorElectronBleTransport | undefined;\n\n private readonly _transportOptions?: TrezorElectronBleTransportOptions;\n\n private readonly _logger?: TrezorDebugLogger;\n\n constructor(options?: TrezorElectronBleConnectorOptions) {\n super({\n connectionType: 'ble',\n chunkSize: TREZOR_BLE_PACKET_SIZE,\n thp: options?.thp,\n deviceSessionFactory: options?.deviceSessionFactory,\n });\n this._transport = options?.transport;\n this._transportOptions = options?.transportOptions;\n this._logger = options?.transportOptions?.logger;\n }\n\n protected async enumerateDevices(): Promise<ConnectorDevice[]> {\n const transport = this._ensureTransport();\n const devices = await transport.scan();\n const filtered = devices.filter(isTrezorBleDescriptor);\n if (filtered.length !== devices.length) {\n this._log('info', 'ble.connector.enumerate.filtered', {\n transport: 'electron-ble',\n descriptorCount: devices.length,\n filteredCount: filtered.length,\n dropped: devices.filter(device => !isTrezorBleDescriptor(device)).map(toBleFilterLogSample),\n kept: filtered.map(toBleFilterLogSample),\n });\n }\n return filtered.map(d => ({\n connectId: d.id,\n deviceId: '',\n name: d.name ?? d.localName ?? 'Trezor Safe 7',\n model: TREZOR_SAFE_7_MODEL,\n connectionType: 'ble' as const,\n // Promote the typed BLE fields the device surface already has slots for.\n rssi: d.rssi ?? null,\n isConnectable: d.isConnectable ?? null,\n capabilities: { persistentDeviceIdentity: false },\n // Stash the FULL scan-time advertisement so the app/debug layer sees\n // everything the OS BLE stack exposed (mirrors the WebUSB connector's\n // `raw.descriptor`). This is where a cross-transport identity, if any,\n // would surface (manufacturerData / serviceData / localName).\n raw: {\n transport: 'electron-ble',\n descriptor: d,\n },\n }));\n }\n\n protected async createByteTransport(\n device: ConnectorDevice\n ): Promise<TrezorConnectorByteTransport> {\n const transport = this._ensureTransport();\n try {\n await transport.connect(device.connectId);\n } catch (error) {\n // Rethrowing the caught error (typed `unknown`) as-is is intentional.\n // eslint-disable-next-line @typescript-eslint/no-throw-literal\n if (isStandardHwkError(error)) throw error;\n const reason = error instanceof Error ? error.message : String(error);\n // The device wasn't found at all → DeviceNotFound. Otherwise the connect\n // itself failed: noble drops the real CoreBluetooth reason (hardcodes\n // \"connection failed\" / a timeout), so we CANNOT tell a stale bond from an\n // out-of-range / unresponsive device. Surface one honest, generic\n // BleConnectFailed instead of guessing a specific cause.\n if (/device not found/i.test(reason)) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Trezor BLE device not found: ${device.connectId}`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n // cancelPairing abandoned the connect. Reporting that as a connect failure\n // would tell the user the device is unreachable when they are the one who\n // stopped it.\n if (/connect cancelled/i.test(reason)) {\n throw createHwkError({\n code: HardwareErrorCode.BlePairingCancelled,\n message: `Trezor BLE pairing cancelled: ${device.connectId}`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n throw createHwkError({\n code: HardwareErrorCode.BleConnectFailed,\n message: `Trezor BLE connect failed: ${device.connectId} (${reason})`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n\n return {\n write: async (chunk: Buffer) => {\n await transport.write(device.connectId, Uint8Array.from(chunk));\n },\n read: async () => {\n const data = await transport.read(device.connectId);\n return Buffer.from(data);\n },\n close: () => transport.disconnect(device.connectId),\n onDisconnect: (handler: () => void) => transport.onDisconnect(device.connectId, handler),\n };\n }\n\n protected resolveUnlistedDevice(deviceId: string): ConnectorDevice | undefined {\n const connectId = deviceId.trim();\n if (!connectId) return undefined;\n return {\n connectId,\n deviceId: '',\n name: 'Trezor Safe 7',\n model: TREZOR_SAFE_7_MODEL,\n capabilities: { persistentDeviceIdentity: false },\n };\n }\n\n override async cancel(sessionId: string): Promise<void> {\n await super.cancel(sessionId);\n // Base cancel only settles UI waiters; a connect stuck in the main process\n // must be abandoned there.\n try {\n await this._transport?.cancelPairing();\n } catch {\n // Cancel must never throw.\n }\n }\n\n reset(): void {\n super.reset();\n this._transport?.reset();\n this._transport = undefined;\n }\n\n private _ensureTransport(): TrezorElectronBleTransport {\n if (!this._transport) {\n this._transport = new TrezorElectronBleTransport(this._transportOptions);\n }\n return this._transport;\n }\n\n private _log(level: TrezorDebugLogLevel, event: string, data?: Record<string, unknown>): void {\n const entry = filterTrezorDebugLogEntry({ level, scope: 'trezor-electron-ble', event, data });\n if (!entry) return;\n\n try {\n this._logger?.(entry);\n } catch {\n // Debug logging must not affect BLE connector behavior.\n }\n }\n}\n\nexport function createTrezorElectronBleConnector(\n options?: TrezorElectronBleConnectorOptions\n): TrezorElectronBleConnector {\n return new TrezorElectronBleConnector(options);\n}\n\nfunction readStringArrayField(source: TrezorBleDeviceInfo, key: string): string[] | undefined {\n const value = (source as unknown as Record<string, unknown>)[key];\n if (!Array.isArray(value)) return undefined;\n return value.filter((item): item is string => typeof item === 'string');\n}\n\nfunction toBleFilterLogSample(device: TrezorBleDeviceInfo): Record<string, unknown> {\n return {\n id: device.id,\n name: device.name,\n localName: device.localName,\n rssi: device.rssi,\n isConnectable: device.isConnectable,\n keys: Object.keys(device).sort(),\n matchesTrezorService: isTrezorBleDescriptor(device),\n serviceUUIDs: readStringArrayField(device, 'serviceUUIDs'),\n serviceUuids: readStringArrayField(device, 'serviceUuids'),\n advertisedServiceUuids: readStringArrayField(device, 'advertisedServiceUuids'),\n serviceSolicitationUuids: device.serviceSolicitationUuids,\n txPowerLevel: device.txPowerLevel,\n manufacturerDataHex: device.manufacturerDataHex,\n serviceData: device.serviceData,\n address: device.address,\n addressType: device.addressType,\n state: device.state,\n };\n}\n","import { Buffer } from 'buffer';\nimport { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport {\n type TrezorDebugLogLevel,\n type TrezorDebugLogger,\n filterTrezorDebugLogEntry,\n} from '@onekeyfe/hwk-trezor-connector';\n\nimport type { TrezorBleApi, TrezorBleDeviceInfo } from './types/desktop-api';\n\nexport interface TrezorElectronBleTransportOptions {\n /** The IPC bridge exposed by the main process (typically `window.desktopApi.trezorBle`). */\n bridge?: TrezorBleApi;\n logger?: TrezorDebugLogger;\n}\n\nconst disconnectError = (message: string): Error =>\n Object.assign(new Error(message), { code: HardwareErrorCode.DeviceDisconnected });\n\nconst notConnectedError = (id: string): Error =>\n disconnectError(`Trezor Electron BLE device is not connected: ${id}`);\n\nconst resolveBridge = (options?: TrezorElectronBleTransportOptions): TrezorBleApi => {\n if (options?.bridge) return options.bridge;\n const win =\n typeof window !== 'undefined'\n ? (window as unknown as { desktopApi?: { trezorBle?: TrezorBleApi } })\n : undefined;\n const bridge = win?.desktopApi?.trezorBle;\n if (!bridge) {\n throw createHwkError({\n code: HardwareErrorCode.BridgeNotFound,\n message:\n 'TrezorElectronBleTransport: no bridge found — pass `bridge` or expose `window.desktopApi.trezorBle` from your Electron preload script',\n });\n }\n return bridge;\n};\n\ninterface PendingRead {\n resolve(data: Uint8Array): void;\n reject(error: Error): void;\n}\n\n/**\n * Renderer-side wrapper around the main process's BLE handler. Buffers\n * notifications into a per-device read queue so callers can `read()`\n * sequentially without missing chunks that arrive between reads.\n */\nexport class TrezorElectronBleTransport {\n private readonly _bridge: TrezorBleApi;\n\n private readonly _connected = new Set<string>();\n\n private readonly _readQueues = new Map<string, Uint8Array[]>();\n\n private readonly _pendingReads = new Map<string, PendingRead[]>();\n\n private readonly _disconnectHandlers = new Map<string, Set<() => void>>();\n\n private _disposeNotificationListener?: () => void;\n\n private _disposeDisconnectListener?: () => void;\n\n private readonly _logger?: TrezorElectronBleTransportOptions['logger'];\n\n constructor(options: TrezorElectronBleTransportOptions = {}) {\n this._bridge = resolveBridge(options);\n this._logger = options.logger;\n this._wireGlobalListeners();\n }\n\n async scan(durationMs?: number): Promise<TrezorBleDeviceInfo[]> {\n // No serviceUuids filter: a native service-UUID scan filter drops a\n // Safe 7's ADV packets on Windows (its UUID travels in the scan response,\n // not the ADV packet), so the handler scans unfiltered and does the Trezor\n // matching itself in JS. Passing a filter here would at best be ignored by\n // a current handler and at worst re-break discovery on an older one.\n try {\n return await this._bridge.scan({\n durationMs,\n });\n } catch (error) {\n this._log('warn', 'ble.renderer.scan.error', {\n error: String(error),\n });\n throw error;\n }\n }\n\n async stopScan(): Promise<void> {\n await this._bridge.stopScan();\n }\n\n /** Abandon the in-flight connect/pairing in the main process. */\n async cancelPairing(): Promise<void> {\n await this._bridge.cancelPairing();\n }\n\n async connect(connectId: string): Promise<void> {\n if (this._connected.has(connectId)) return;\n await this._bridge.connect(connectId);\n try {\n await this._bridge.subscribe(connectId);\n } catch (error) {\n // Main process is already connected — tear it down so we don't leak a\n // main-side connection the renderer can no longer address.\n await this._bridge.disconnect(connectId).catch(() => undefined);\n throw error;\n }\n this._connected.add(connectId);\n this._readQueues.set(connectId, []);\n this._pendingReads.set(connectId, []);\n }\n\n async disconnect(connectId: string): Promise<void> {\n this._connected.delete(connectId);\n this._failPendingReads(connectId, notConnectedError(connectId));\n this._readQueues.delete(connectId);\n try {\n await this._bridge.unsubscribe(connectId);\n } catch (error) {\n this._log('warn', 'unsubscribe.error', { connectId, error: String(error) });\n }\n await this._bridge.disconnect(connectId);\n }\n\n async write(connectId: string, data: Uint8Array): Promise<void> {\n if (!this._connected.has(connectId)) throw notConnectedError(connectId);\n const hex = Buffer.from(data).toString('hex');\n await this._bridge.write(connectId, hex);\n }\n\n async read(connectId: string): Promise<Uint8Array> {\n if (!this._connected.has(connectId)) throw notConnectedError(connectId);\n const queue = this._readQueues.get(connectId);\n if (queue && queue.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return queue.shift()!;\n }\n return new Promise<Uint8Array>((resolve, reject) => {\n const pending = this._pendingReads.get(connectId);\n if (!pending) {\n reject(notConnectedError(connectId));\n return;\n }\n pending.push({ resolve, reject });\n });\n }\n\n onDisconnect(connectId: string, handler: () => void): () => void {\n const handlers = this._disconnectHandlers.get(connectId) ?? new Set<() => void>();\n handlers.add(handler);\n this._disconnectHandlers.set(connectId, handlers);\n return () => {\n handlers.delete(handler);\n if (handlers.size === 0) {\n this._disconnectHandlers.delete(connectId);\n }\n };\n }\n\n /** Tear down global listeners — called by the connector's `reset()`. */\n reset(): void {\n this._disposeNotificationListener?.();\n this._disposeDisconnectListener?.();\n this._disposeNotificationListener = undefined;\n this._disposeDisconnectListener = undefined;\n for (const handlers of this._disconnectHandlers.values()) handlers.clear();\n this._disconnectHandlers.clear();\n for (const id of this._connected) this._failPendingReads(id, notConnectedError(id));\n this._connected.clear();\n this._readQueues.clear();\n this._pendingReads.clear();\n }\n\n private _wireGlobalListeners(): void {\n this._disposeNotificationListener = this._bridge.onNotification((id, hex) => {\n const data = new Uint8Array(Buffer.from(hex, 'hex'));\n const pending = this._pendingReads.get(id);\n if (pending && pending.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n pending.shift()!.resolve(data);\n return;\n }\n const queue = this._readQueues.get(id);\n if (queue) queue.push(data);\n });\n this._disposeDisconnectListener = this._bridge.onDeviceDisconnected(id => {\n this._connected.delete(id);\n this._failPendingReads(id, disconnectError(`Trezor BLE device disconnected: ${id}`));\n this._readQueues.delete(id);\n this._disconnectHandlers.get(id)?.forEach(handler => {\n try {\n handler();\n } catch (error) {\n this._log('error', 'disconnect.handler.threw', { id, error: String(error) });\n }\n });\n });\n }\n\n private _failPendingReads(connectId: string, error: Error): void {\n const pending = this._pendingReads.get(connectId);\n if (!pending) return;\n for (const item of pending) item.reject(error);\n this._pendingReads.set(connectId, []);\n }\n\n private _log(level: TrezorDebugLogLevel, event: string, data?: Record<string, unknown>): void {\n const entry = filterTrezorDebugLogEntry({ level, scope: 'trezor-electron-ble', event, data });\n if (!entry) return;\n\n this._logger?.(entry);\n }\n}\n\nexport function createTrezorElectronBleTransport(\n options?: TrezorElectronBleTransportOptions\n): TrezorElectronBleTransport {\n return new TrezorElectronBleTransport(options);\n}\n","/**\n * IPC channel names exchanged between renderer and main process.\n * Namespaced under `$onekey-trezor-ble-…` to avoid clashing with the\n * existing OneKey BLE handler (`$onekey-noble-ble-…`) when both run in\n * the same Electron app.\n */\nexport const TREZOR_BLE_CHANNELS = {\n scan: '$onekey-trezor-ble-scan',\n stopScan: '$onekey-trezor-ble-stop-scan',\n connect: '$onekey-trezor-ble-connect',\n disconnect: '$onekey-trezor-ble-disconnect',\n write: '$onekey-trezor-ble-write',\n subscribe: '$onekey-trezor-ble-subscribe',\n unsubscribe: '$onekey-trezor-ble-unsubscribe',\n availability: '$onekey-trezor-ble-availability',\n getDevice: '$onekey-trezor-ble-get-device',\n readRssi: '$onekey-trezor-ble-read-rssi',\n cancelPairing: '$onekey-trezor-ble-cancel-pairing',\n /** push event: main → renderer with assembled BLE notification payload */\n notification: '$onekey-trezor-ble-notification',\n /** push event: main → renderer when device disconnects unexpectedly */\n disconnected: '$onekey-trezor-ble-disconnected',\n} as const;\n\nexport type TrezorBleChannel = (typeof TREZOR_BLE_CHANNELS)[keyof typeof TREZOR_BLE_CHANNELS];\n\n/** Reconnect scan window for `connect(id)`. */\nexport const TREZOR_BLE_SCAN_DURATION_MS = 5_000;\n\n/** Continuous scan auto-stops this long after the last poll (reset, not accumulated). */\nexport const TREZOR_BLE_SCAN_IDLE_STOP_MS = 10_000;\n\n/** Drop a device from the snapshot if it hasn't re-advertised within this window. */\nexport const TREZOR_BLE_DEVICE_TTL_MS = 5_000;\n\n/** Time we'll wait for noble to reach `poweredOn` before failing init. */\nexport const TREZOR_BLE_POWER_ON_TIMEOUT_MS = 10_000;\n\n/** Inter-chunk delay during write, matches OneKey's `UNIFIED_WRITE_DELAY`. */\nexport const TREZOR_BLE_WRITE_CHUNK_DELAY_MS = 5;\n"],"mappings":"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","names":["import_buffer","import_hwk_adapter_core","import_hwk_trezor_connector"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/TrezorElectronBleConnector.ts","../src/TrezorElectronBleTransport.ts","../src/bleProfile.ts"],"sourcesContent":["export {\n TrezorElectronBleConnector,\n createTrezorElectronBleConnector,\n} from './TrezorElectronBleConnector';\nexport type { TrezorElectronBleConnectorOptions } from './TrezorElectronBleConnector';\n\nexport {\n TrezorElectronBleTransport,\n createTrezorElectronBleTransport,\n} from './TrezorElectronBleTransport';\nexport type { TrezorElectronBleTransportOptions } from './TrezorElectronBleTransport';\n\nexport {\n TREZOR_BLE_VENDOR,\n TREZOR_BLE_MATCH,\n TREZOR_BLE_CONNECT_PROFILE,\n TREZOR_BLE_WRITE_CHUNK_DELAY_MS,\n} from './bleProfile';\n","import { Buffer } from 'buffer';\nimport {\n TREZOR_BLE_PACKET_SIZE,\n TREZOR_SAFE_7_MODEL,\n isTrezorBleDescriptor,\n} from '@onekeyfe/hwk-trezor-adapter';\nimport { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport {\n TrezorConnectorBase,\n type TrezorConnectorBaseOptions,\n type TrezorConnectorByteTransport,\n type TrezorDebugLogLevel,\n type TrezorDebugLogger,\n filterTrezorDebugLogEntry,\n} from '@onekeyfe/hwk-trezor-connector';\n\nimport {\n TrezorElectronBleTransport,\n type TrezorElectronBleTransportOptions,\n} from './TrezorElectronBleTransport';\n\nimport type { ConnectorDevice } from '@onekeyfe/hwk-adapter-core';\nimport type { ThirdPartyBleDeviceInfo } from '@onekeyfe/hwk-desktop-noble-ble';\n\nconst isStandardHwkError = (error: unknown): error is { code: number } =>\n typeof (error as { code?: unknown })?.code === 'number';\n\nexport interface TrezorElectronBleConnectorOptions {\n transport?: TrezorElectronBleTransport;\n transportOptions?: TrezorElectronBleTransportOptions;\n thp?: TrezorConnectorBaseOptions['thp'];\n deviceSessionFactory?: TrezorConnectorBaseOptions['deviceSessionFactory'];\n}\n\nexport class TrezorElectronBleConnector extends TrezorConnectorBase {\n private _transport: TrezorElectronBleTransport | undefined;\n\n private readonly _transportOptions?: TrezorElectronBleTransportOptions;\n\n private readonly _logger?: TrezorDebugLogger;\n\n constructor(options?: TrezorElectronBleConnectorOptions) {\n super({\n connectionType: 'ble',\n chunkSize: TREZOR_BLE_PACKET_SIZE,\n thp: options?.thp,\n deviceSessionFactory: options?.deviceSessionFactory,\n });\n this._transport = options?.transport;\n this._transportOptions = options?.transportOptions;\n this._logger = options?.transportOptions?.logger;\n }\n\n protected async enumerateDevices(): Promise<ConnectorDevice[]> {\n const transport = this._ensureTransport();\n const devices = await transport.scan();\n const filtered = devices.filter(isTrezorBleDescriptor);\n if (filtered.length !== devices.length) {\n this._log('info', 'ble.connector.enumerate.filtered', {\n transport: 'electron-ble',\n descriptorCount: devices.length,\n filteredCount: filtered.length,\n dropped: devices.filter(device => !isTrezorBleDescriptor(device)).map(toBleFilterLogSample),\n kept: filtered.map(toBleFilterLogSample),\n });\n }\n return filtered.map(d => ({\n connectId: d.id,\n deviceId: '',\n name: d.name ?? d.localName ?? 'Trezor Safe 7',\n model: TREZOR_SAFE_7_MODEL,\n connectionType: 'ble' as const,\n // Promote the typed BLE fields the device surface already has slots for.\n rssi: d.rssi ?? null,\n isConnectable: d.isConnectable ?? null,\n capabilities: { persistentDeviceIdentity: false },\n // Stash the FULL scan-time advertisement so the app/debug layer sees\n // everything the OS BLE stack exposed (mirrors the WebUSB connector's\n // `raw.descriptor`). This is where a cross-transport identity, if any,\n // would surface (manufacturerData / serviceData / localName).\n raw: {\n transport: 'electron-ble',\n descriptor: d,\n },\n }));\n }\n\n protected async createByteTransport(\n device: ConnectorDevice\n ): Promise<TrezorConnectorByteTransport> {\n const transport = this._ensureTransport();\n try {\n await transport.connect(device.connectId);\n } catch (error) {\n // Rethrowing the caught error (typed `unknown`) as-is is intentional.\n // eslint-disable-next-line @typescript-eslint/no-throw-literal\n if (isStandardHwkError(error)) throw error;\n const reason = error instanceof Error ? error.message : String(error);\n // The device wasn't found at all → DeviceNotFound. Otherwise the connect\n // itself failed: noble drops the real CoreBluetooth reason (hardcodes\n // \"connection failed\" / a timeout), so we CANNOT tell a stale bond from an\n // out-of-range / unresponsive device. Surface one honest, generic\n // BleConnectFailed instead of guessing a specific cause.\n if (/device not found/i.test(reason)) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Trezor BLE device not found: ${device.connectId}`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n // cancelPairing abandoned the connect. Reporting that as a connect failure\n // would tell the user the device is unreachable when they are the one who\n // stopped it.\n if (/connect cancelled/i.test(reason)) {\n throw createHwkError({\n code: HardwareErrorCode.BlePairingCancelled,\n message: `Trezor BLE pairing cancelled: ${device.connectId}`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n throw createHwkError({\n code: HardwareErrorCode.BleConnectFailed,\n message: `Trezor BLE connect failed: ${device.connectId} (${reason})`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n\n return {\n write: async (chunk: Buffer) => {\n await transport.write(device.connectId, Uint8Array.from(chunk));\n },\n read: async () => {\n const data = await transport.read(device.connectId);\n return Buffer.from(data);\n },\n close: () => transport.disconnect(device.connectId),\n onDisconnect: (handler: () => void) => transport.onDisconnect(device.connectId, handler),\n };\n }\n\n protected resolveUnlistedDevice(deviceId: string): ConnectorDevice | undefined {\n const connectId = deviceId.trim();\n if (!connectId) return undefined;\n return {\n connectId,\n deviceId: '',\n name: 'Trezor Safe 7',\n model: TREZOR_SAFE_7_MODEL,\n capabilities: { persistentDeviceIdentity: false },\n };\n }\n\n override async cancel(sessionId: string): Promise<void> {\n await super.cancel(sessionId);\n // Base cancel only settles UI waiters; a connect stuck in the main process\n // must be abandoned there.\n try {\n await this._transport?.cancelPairing();\n } catch {\n // Cancel must never throw.\n }\n }\n\n reset(): void {\n super.reset();\n this._transport?.reset();\n this._transport = undefined;\n }\n\n private _ensureTransport(): TrezorElectronBleTransport {\n if (!this._transport) {\n this._transport = new TrezorElectronBleTransport(this._transportOptions);\n }\n return this._transport;\n }\n\n private _log(level: TrezorDebugLogLevel, event: string, data?: Record<string, unknown>): void {\n const entry = filterTrezorDebugLogEntry({ level, scope: 'trezor-electron-ble', event, data });\n if (!entry) return;\n\n try {\n this._logger?.(entry);\n } catch {\n // Debug logging must not affect BLE connector behavior.\n }\n }\n}\n\nexport function createTrezorElectronBleConnector(\n options?: TrezorElectronBleConnectorOptions\n): TrezorElectronBleConnector {\n return new TrezorElectronBleConnector(options);\n}\n\nfunction readStringArrayField(source: ThirdPartyBleDeviceInfo, key: string): string[] | undefined {\n const value = (source as unknown as Record<string, unknown>)[key];\n if (!Array.isArray(value)) return undefined;\n return value.filter((item): item is string => typeof item === 'string');\n}\n\nfunction toBleFilterLogSample(device: ThirdPartyBleDeviceInfo): Record<string, unknown> {\n return {\n id: device.id,\n name: device.name,\n localName: device.localName,\n rssi: device.rssi,\n isConnectable: device.isConnectable,\n keys: Object.keys(device).sort(),\n matchesTrezorService: isTrezorBleDescriptor(device),\n serviceUUIDs: readStringArrayField(device, 'serviceUUIDs'),\n serviceUuids: readStringArrayField(device, 'serviceUuids'),\n advertisedServiceUuids: readStringArrayField(device, 'advertisedServiceUuids'),\n serviceSolicitationUuids: device.serviceSolicitationUuids,\n txPowerLevel: device.txPowerLevel,\n manufacturerDataHex: device.manufacturerDataHex,\n serviceData: device.serviceData,\n address: device.address,\n addressType: device.addressType,\n state: device.state,\n };\n}\n","import { Buffer } from 'buffer';\nimport { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport {\n type TrezorDebugLogLevel,\n type TrezorDebugLogger,\n filterTrezorDebugLogEntry,\n} from '@onekeyfe/hwk-trezor-connector';\n\nimport { TREZOR_BLE_CONNECT_PROFILE, TREZOR_BLE_MATCH, TREZOR_BLE_VENDOR } from './bleProfile';\n\nimport type { ThirdPartyBleApi, ThirdPartyBleDeviceInfo } from '@onekeyfe/hwk-desktop-noble-ble';\n\nexport interface TrezorElectronBleTransportOptions {\n /** The IPC bridge exposed by the main process (typically `window.desktopApi.trezorBle`). */\n bridge?: ThirdPartyBleApi;\n logger?: TrezorDebugLogger;\n}\n\nconst disconnectError = (message: string): Error =>\n Object.assign(new Error(message), { code: HardwareErrorCode.DeviceDisconnected });\n\nconst notConnectedError = (id: string): Error =>\n disconnectError(`Trezor Electron BLE device is not connected: ${id}`);\n\nconst resolveBridge = (options?: TrezorElectronBleTransportOptions): ThirdPartyBleApi => {\n if (options?.bridge) return options.bridge;\n const win =\n typeof window !== 'undefined'\n ? (window as unknown as { desktopApi?: { trezorBle?: ThirdPartyBleApi } })\n : undefined;\n const bridge = win?.desktopApi?.trezorBle;\n if (!bridge) {\n throw createHwkError({\n code: HardwareErrorCode.BridgeNotFound,\n message:\n 'TrezorElectronBleTransport: no bridge found — pass `bridge` or expose `window.desktopApi.trezorBle` from your Electron preload script',\n });\n }\n return bridge;\n};\n\ninterface PendingRead {\n resolve(data: Uint8Array): void;\n reject(error: Error): void;\n}\n\n/**\n * Renderer-side wrapper around the main process's BLE handler. Buffers\n * notifications into a per-device read queue so callers can `read()`\n * sequentially without missing chunks that arrive between reads.\n */\nexport class TrezorElectronBleTransport {\n private readonly _bridge: ThirdPartyBleApi;\n\n private readonly _connected = new Set<string>();\n\n private readonly _readQueues = new Map<string, Uint8Array[]>();\n\n private readonly _pendingReads = new Map<string, PendingRead[]>();\n\n private readonly _disconnectHandlers = new Map<string, Set<() => void>>();\n\n private _disposeNotificationListener?: () => void;\n\n private _disposeDisconnectListener?: () => void;\n\n private readonly _logger?: TrezorElectronBleTransportOptions['logger'];\n\n constructor(options: TrezorElectronBleTransportOptions = {}) {\n this._bridge = resolveBridge(options);\n this._logger = options.logger;\n this._wireGlobalListeners();\n }\n\n async scan(durationMs?: number): Promise<ThirdPartyBleDeviceInfo[]> {\n // `match` is applied in JS, after an unfiltered radio scan — it is not a\n // native scan filter. That distinction matters: a native service-UUID\n // filter drops a Safe 7's ADV packets on Windows, because its UUID travels\n // in the scan response rather than the ADV packet. Hence the name patterns,\n // which match what the ADV packet does carry.\n try {\n return await this._bridge.scan({\n vendor: TREZOR_BLE_VENDOR,\n match: TREZOR_BLE_MATCH,\n durationMs,\n });\n } catch (error) {\n this._log('warn', 'ble.renderer.scan.error', {\n error: String(error),\n });\n throw error;\n }\n }\n\n async stopScan(): Promise<void> {\n await this._bridge.stopScan();\n }\n\n /** Abandon the in-flight connect/pairing in the main process. */\n async cancelPairing(): Promise<void> {\n await this._bridge.cancelPairing();\n }\n\n async connect(connectId: string): Promise<void> {\n if (this._connected.has(connectId)) return;\n // The shared handler holds no vendor defaults: every GATT uuid and the\n // padded-write framing travel with the call.\n await this._bridge.connect(connectId, TREZOR_BLE_CONNECT_PROFILE);\n try {\n await this._bridge.subscribe(connectId);\n } catch (error) {\n // Main process is already connected — tear it down so we don't leak a\n // main-side connection the renderer can no longer address.\n await this._bridge.disconnect(connectId).catch(() => undefined);\n throw error;\n }\n this._connected.add(connectId);\n this._readQueues.set(connectId, []);\n this._pendingReads.set(connectId, []);\n }\n\n async disconnect(connectId: string): Promise<void> {\n this._connected.delete(connectId);\n this._failPendingReads(connectId, notConnectedError(connectId));\n this._readQueues.delete(connectId);\n try {\n await this._bridge.unsubscribe(connectId);\n } catch (error) {\n this._log('warn', 'unsubscribe.error', { connectId, error: String(error) });\n }\n await this._bridge.disconnect(connectId);\n }\n\n async write(connectId: string, data: Uint8Array): Promise<void> {\n if (!this._connected.has(connectId)) throw notConnectedError(connectId);\n const hex = Buffer.from(data).toString('hex');\n await this._bridge.write(connectId, hex);\n }\n\n async read(connectId: string): Promise<Uint8Array> {\n if (!this._connected.has(connectId)) throw notConnectedError(connectId);\n const queue = this._readQueues.get(connectId);\n if (queue && queue.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return queue.shift()!;\n }\n return new Promise<Uint8Array>((resolve, reject) => {\n const pending = this._pendingReads.get(connectId);\n if (!pending) {\n reject(notConnectedError(connectId));\n return;\n }\n pending.push({ resolve, reject });\n });\n }\n\n onDisconnect(connectId: string, handler: () => void): () => void {\n const handlers = this._disconnectHandlers.get(connectId) ?? new Set<() => void>();\n handlers.add(handler);\n this._disconnectHandlers.set(connectId, handlers);\n return () => {\n handlers.delete(handler);\n if (handlers.size === 0) {\n this._disconnectHandlers.delete(connectId);\n }\n };\n }\n\n /** Tear down global listeners — called by the connector's `reset()`. */\n reset(): void {\n this._disposeNotificationListener?.();\n this._disposeDisconnectListener?.();\n this._disposeNotificationListener = undefined;\n this._disposeDisconnectListener = undefined;\n for (const handlers of this._disconnectHandlers.values()) handlers.clear();\n this._disconnectHandlers.clear();\n for (const id of this._connected) this._failPendingReads(id, notConnectedError(id));\n this._connected.clear();\n this._readQueues.clear();\n this._pendingReads.clear();\n }\n\n private _wireGlobalListeners(): void {\n this._disposeNotificationListener = this._bridge.onNotification((id, hex) => {\n const data = new Uint8Array(Buffer.from(hex, 'hex'));\n const pending = this._pendingReads.get(id);\n if (pending && pending.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n pending.shift()!.resolve(data);\n return;\n }\n const queue = this._readQueues.get(id);\n if (queue) queue.push(data);\n });\n this._disposeDisconnectListener = this._bridge.onDeviceDisconnected(id => {\n this._connected.delete(id);\n this._failPendingReads(id, disconnectError(`Trezor BLE device disconnected: ${id}`));\n this._readQueues.delete(id);\n this._disconnectHandlers.get(id)?.forEach(handler => {\n try {\n handler();\n } catch (error) {\n this._log('error', 'disconnect.handler.threw', { id, error: String(error) });\n }\n });\n });\n }\n\n private _failPendingReads(connectId: string, error: Error): void {\n const pending = this._pendingReads.get(connectId);\n if (!pending) return;\n for (const item of pending) item.reject(error);\n this._pendingReads.set(connectId, []);\n }\n\n private _log(level: TrezorDebugLogLevel, event: string, data?: Record<string, unknown>): void {\n const entry = filterTrezorDebugLogEntry({ level, scope: 'trezor-electron-ble', event, data });\n if (!entry) return;\n\n this._logger?.(entry);\n }\n}\n\nexport function createTrezorElectronBleTransport(\n options?: TrezorElectronBleTransportOptions\n): TrezorElectronBleTransport {\n return new TrezorElectronBleTransport(options);\n}\n","import { TREZOR_BLE_PACKET_SIZE, TREZOR_BLE_UUIDS } from '@onekeyfe/hwk-trezor-adapter';\n\nimport type { ElectronBleConnectOptions, ElectronBleMatch } from '@onekeyfe/hwk-adapter-core';\n\n/** Inter-chunk delay during write, matches OneKey's `UNIFIED_WRITE_DELAY`. */\nexport const TREZOR_BLE_WRITE_CHUNK_DELAY_MS = 5;\n\nexport const TREZOR_BLE_VENDOR = 'trezor';\n\n/**\n * How the shared desktop handler recognizes a Trezor. The main process holds\n * no vendor knowledge, so the name test that used to live there travels as\n * data: a local name must satisfy every pattern, which reproduces\n * `isTrezorSafe7BleName` — \"Trezor\" plus either \"Safe 7\" or \"T3W1\".\n */\nexport const TREZOR_BLE_MATCH: ElectronBleMatch = {\n serviceUuids: [TREZOR_BLE_UUIDS.service],\n namePatterns: ['\\\\bTrezor\\\\b', '\\\\bSafe\\\\s*7\\\\b|\\\\bT3W1\\\\b'],\n};\n\n/**\n * Trezor firmware expects fixed-size packets: a short final packet is silently\n * dropped, so every write is padded to the full MTU.\n */\nexport const TREZOR_BLE_CONNECT_PROFILE: ElectronBleConnectOptions = {\n vendor: TREZOR_BLE_VENDOR,\n serviceUuid: TREZOR_BLE_UUIDS.service,\n writeUuid: TREZOR_BLE_UUIDS.write,\n notifyUuid: TREZOR_BLE_UUIDS.notify,\n write: {\n mode: 'padded',\n chunkSize: TREZOR_BLE_PACKET_SIZE,\n chunkDelayMs: TREZOR_BLE_WRITE_CHUNK_DELAY_MS,\n },\n};\n"],"mappings":"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","names":["import_buffer","import_hwk_trezor_adapter","import_hwk_adapter_core","import_hwk_trezor_connector"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
TREZOR_BLE_CHANNELS,
|
|
3
|
-
TREZOR_BLE_POWER_ON_TIMEOUT_MS,
|
|
4
|
-
TREZOR_BLE_SCAN_DURATION_MS,
|
|
5
|
-
TREZOR_BLE_WRITE_CHUNK_DELAY_MS
|
|
6
|
-
} from "./chunk-CFZTAWFZ.mjs";
|
|
7
|
-
|
|
8
1
|
// src/TrezorElectronBleConnector.ts
|
|
9
2
|
import { Buffer as Buffer2 } from "buffer";
|
|
10
3
|
import {
|
|
11
|
-
TREZOR_BLE_PACKET_SIZE,
|
|
4
|
+
TREZOR_BLE_PACKET_SIZE as TREZOR_BLE_PACKET_SIZE2,
|
|
12
5
|
TREZOR_SAFE_7_MODEL,
|
|
13
6
|
isTrezorBleDescriptor
|
|
14
7
|
} from "@onekeyfe/hwk-trezor-adapter";
|
|
@@ -24,6 +17,28 @@ import { HardwareErrorCode, createHwkError } from "@onekeyfe/hwk-adapter-core";
|
|
|
24
17
|
import {
|
|
25
18
|
filterTrezorDebugLogEntry
|
|
26
19
|
} from "@onekeyfe/hwk-trezor-connector";
|
|
20
|
+
|
|
21
|
+
// src/bleProfile.ts
|
|
22
|
+
import { TREZOR_BLE_PACKET_SIZE, TREZOR_BLE_UUIDS } from "@onekeyfe/hwk-trezor-adapter";
|
|
23
|
+
var TREZOR_BLE_WRITE_CHUNK_DELAY_MS = 5;
|
|
24
|
+
var TREZOR_BLE_VENDOR = "trezor";
|
|
25
|
+
var TREZOR_BLE_MATCH = {
|
|
26
|
+
serviceUuids: [TREZOR_BLE_UUIDS.service],
|
|
27
|
+
namePatterns: ["\\bTrezor\\b", "\\bSafe\\s*7\\b|\\bT3W1\\b"]
|
|
28
|
+
};
|
|
29
|
+
var TREZOR_BLE_CONNECT_PROFILE = {
|
|
30
|
+
vendor: TREZOR_BLE_VENDOR,
|
|
31
|
+
serviceUuid: TREZOR_BLE_UUIDS.service,
|
|
32
|
+
writeUuid: TREZOR_BLE_UUIDS.write,
|
|
33
|
+
notifyUuid: TREZOR_BLE_UUIDS.notify,
|
|
34
|
+
write: {
|
|
35
|
+
mode: "padded",
|
|
36
|
+
chunkSize: TREZOR_BLE_PACKET_SIZE,
|
|
37
|
+
chunkDelayMs: TREZOR_BLE_WRITE_CHUNK_DELAY_MS
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/TrezorElectronBleTransport.ts
|
|
27
42
|
var disconnectError = (message) => Object.assign(new Error(message), { code: HardwareErrorCode.DeviceDisconnected });
|
|
28
43
|
var notConnectedError = (id) => disconnectError(`Trezor Electron BLE device is not connected: ${id}`);
|
|
29
44
|
var resolveBridge = (options) => {
|
|
@@ -51,6 +66,8 @@ var TrezorElectronBleTransport = class {
|
|
|
51
66
|
async scan(durationMs) {
|
|
52
67
|
try {
|
|
53
68
|
return await this._bridge.scan({
|
|
69
|
+
vendor: TREZOR_BLE_VENDOR,
|
|
70
|
+
match: TREZOR_BLE_MATCH,
|
|
54
71
|
durationMs
|
|
55
72
|
});
|
|
56
73
|
} catch (error) {
|
|
@@ -69,7 +86,7 @@ var TrezorElectronBleTransport = class {
|
|
|
69
86
|
}
|
|
70
87
|
async connect(connectId) {
|
|
71
88
|
if (this._connected.has(connectId)) return;
|
|
72
|
-
await this._bridge.connect(connectId);
|
|
89
|
+
await this._bridge.connect(connectId, TREZOR_BLE_CONNECT_PROFILE);
|
|
73
90
|
try {
|
|
74
91
|
await this._bridge.subscribe(connectId);
|
|
75
92
|
} catch (error) {
|
|
@@ -181,7 +198,7 @@ var TrezorElectronBleConnector = class extends TrezorConnectorBase {
|
|
|
181
198
|
constructor(options) {
|
|
182
199
|
super({
|
|
183
200
|
connectionType: "ble",
|
|
184
|
-
chunkSize:
|
|
201
|
+
chunkSize: TREZOR_BLE_PACKET_SIZE2,
|
|
185
202
|
thp: options?.thp,
|
|
186
203
|
deviceSessionFactory: options?.deviceSessionFactory
|
|
187
204
|
});
|
|
@@ -329,9 +346,9 @@ function toBleFilterLogSample(device) {
|
|
|
329
346
|
};
|
|
330
347
|
}
|
|
331
348
|
export {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
349
|
+
TREZOR_BLE_CONNECT_PROFILE,
|
|
350
|
+
TREZOR_BLE_MATCH,
|
|
351
|
+
TREZOR_BLE_VENDOR,
|
|
335
352
|
TREZOR_BLE_WRITE_CHUNK_DELAY_MS,
|
|
336
353
|
TrezorElectronBleConnector,
|
|
337
354
|
TrezorElectronBleTransport,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/TrezorElectronBleConnector.ts","../src/TrezorElectronBleTransport.ts"],"sourcesContent":["import { Buffer } from 'buffer';\nimport {\n TREZOR_BLE_PACKET_SIZE,\n TREZOR_SAFE_7_MODEL,\n isTrezorBleDescriptor,\n} from '@onekeyfe/hwk-trezor-adapter';\nimport { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport {\n TrezorConnectorBase,\n type TrezorConnectorBaseOptions,\n type TrezorConnectorByteTransport,\n type TrezorDebugLogLevel,\n type TrezorDebugLogger,\n filterTrezorDebugLogEntry,\n} from '@onekeyfe/hwk-trezor-connector';\n\nimport {\n TrezorElectronBleTransport,\n type TrezorElectronBleTransportOptions,\n} from './TrezorElectronBleTransport';\n\nimport type { ConnectorDevice } from '@onekeyfe/hwk-adapter-core';\nimport type { TrezorBleDeviceInfo } from './types/desktop-api';\n\nconst isStandardHwkError = (error: unknown): error is { code: number } =>\n typeof (error as { code?: unknown })?.code === 'number';\n\nexport interface TrezorElectronBleConnectorOptions {\n transport?: TrezorElectronBleTransport;\n transportOptions?: TrezorElectronBleTransportOptions;\n thp?: TrezorConnectorBaseOptions['thp'];\n deviceSessionFactory?: TrezorConnectorBaseOptions['deviceSessionFactory'];\n}\n\nexport class TrezorElectronBleConnector extends TrezorConnectorBase {\n private _transport: TrezorElectronBleTransport | undefined;\n\n private readonly _transportOptions?: TrezorElectronBleTransportOptions;\n\n private readonly _logger?: TrezorDebugLogger;\n\n constructor(options?: TrezorElectronBleConnectorOptions) {\n super({\n connectionType: 'ble',\n chunkSize: TREZOR_BLE_PACKET_SIZE,\n thp: options?.thp,\n deviceSessionFactory: options?.deviceSessionFactory,\n });\n this._transport = options?.transport;\n this._transportOptions = options?.transportOptions;\n this._logger = options?.transportOptions?.logger;\n }\n\n protected async enumerateDevices(): Promise<ConnectorDevice[]> {\n const transport = this._ensureTransport();\n const devices = await transport.scan();\n const filtered = devices.filter(isTrezorBleDescriptor);\n if (filtered.length !== devices.length) {\n this._log('info', 'ble.connector.enumerate.filtered', {\n transport: 'electron-ble',\n descriptorCount: devices.length,\n filteredCount: filtered.length,\n dropped: devices.filter(device => !isTrezorBleDescriptor(device)).map(toBleFilterLogSample),\n kept: filtered.map(toBleFilterLogSample),\n });\n }\n return filtered.map(d => ({\n connectId: d.id,\n deviceId: '',\n name: d.name ?? d.localName ?? 'Trezor Safe 7',\n model: TREZOR_SAFE_7_MODEL,\n connectionType: 'ble' as const,\n // Promote the typed BLE fields the device surface already has slots for.\n rssi: d.rssi ?? null,\n isConnectable: d.isConnectable ?? null,\n capabilities: { persistentDeviceIdentity: false },\n // Stash the FULL scan-time advertisement so the app/debug layer sees\n // everything the OS BLE stack exposed (mirrors the WebUSB connector's\n // `raw.descriptor`). This is where a cross-transport identity, if any,\n // would surface (manufacturerData / serviceData / localName).\n raw: {\n transport: 'electron-ble',\n descriptor: d,\n },\n }));\n }\n\n protected async createByteTransport(\n device: ConnectorDevice\n ): Promise<TrezorConnectorByteTransport> {\n const transport = this._ensureTransport();\n try {\n await transport.connect(device.connectId);\n } catch (error) {\n // Rethrowing the caught error (typed `unknown`) as-is is intentional.\n // eslint-disable-next-line @typescript-eslint/no-throw-literal\n if (isStandardHwkError(error)) throw error;\n const reason = error instanceof Error ? error.message : String(error);\n // The device wasn't found at all → DeviceNotFound. Otherwise the connect\n // itself failed: noble drops the real CoreBluetooth reason (hardcodes\n // \"connection failed\" / a timeout), so we CANNOT tell a stale bond from an\n // out-of-range / unresponsive device. Surface one honest, generic\n // BleConnectFailed instead of guessing a specific cause.\n if (/device not found/i.test(reason)) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Trezor BLE device not found: ${device.connectId}`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n // cancelPairing abandoned the connect. Reporting that as a connect failure\n // would tell the user the device is unreachable when they are the one who\n // stopped it.\n if (/connect cancelled/i.test(reason)) {\n throw createHwkError({\n code: HardwareErrorCode.BlePairingCancelled,\n message: `Trezor BLE pairing cancelled: ${device.connectId}`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n throw createHwkError({\n code: HardwareErrorCode.BleConnectFailed,\n message: `Trezor BLE connect failed: ${device.connectId} (${reason})`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n\n return {\n write: async (chunk: Buffer) => {\n await transport.write(device.connectId, Uint8Array.from(chunk));\n },\n read: async () => {\n const data = await transport.read(device.connectId);\n return Buffer.from(data);\n },\n close: () => transport.disconnect(device.connectId),\n onDisconnect: (handler: () => void) => transport.onDisconnect(device.connectId, handler),\n };\n }\n\n protected resolveUnlistedDevice(deviceId: string): ConnectorDevice | undefined {\n const connectId = deviceId.trim();\n if (!connectId) return undefined;\n return {\n connectId,\n deviceId: '',\n name: 'Trezor Safe 7',\n model: TREZOR_SAFE_7_MODEL,\n capabilities: { persistentDeviceIdentity: false },\n };\n }\n\n override async cancel(sessionId: string): Promise<void> {\n await super.cancel(sessionId);\n // Base cancel only settles UI waiters; a connect stuck in the main process\n // must be abandoned there.\n try {\n await this._transport?.cancelPairing();\n } catch {\n // Cancel must never throw.\n }\n }\n\n reset(): void {\n super.reset();\n this._transport?.reset();\n this._transport = undefined;\n }\n\n private _ensureTransport(): TrezorElectronBleTransport {\n if (!this._transport) {\n this._transport = new TrezorElectronBleTransport(this._transportOptions);\n }\n return this._transport;\n }\n\n private _log(level: TrezorDebugLogLevel, event: string, data?: Record<string, unknown>): void {\n const entry = filterTrezorDebugLogEntry({ level, scope: 'trezor-electron-ble', event, data });\n if (!entry) return;\n\n try {\n this._logger?.(entry);\n } catch {\n // Debug logging must not affect BLE connector behavior.\n }\n }\n}\n\nexport function createTrezorElectronBleConnector(\n options?: TrezorElectronBleConnectorOptions\n): TrezorElectronBleConnector {\n return new TrezorElectronBleConnector(options);\n}\n\nfunction readStringArrayField(source: TrezorBleDeviceInfo, key: string): string[] | undefined {\n const value = (source as unknown as Record<string, unknown>)[key];\n if (!Array.isArray(value)) return undefined;\n return value.filter((item): item is string => typeof item === 'string');\n}\n\nfunction toBleFilterLogSample(device: TrezorBleDeviceInfo): Record<string, unknown> {\n return {\n id: device.id,\n name: device.name,\n localName: device.localName,\n rssi: device.rssi,\n isConnectable: device.isConnectable,\n keys: Object.keys(device).sort(),\n matchesTrezorService: isTrezorBleDescriptor(device),\n serviceUUIDs: readStringArrayField(device, 'serviceUUIDs'),\n serviceUuids: readStringArrayField(device, 'serviceUuids'),\n advertisedServiceUuids: readStringArrayField(device, 'advertisedServiceUuids'),\n serviceSolicitationUuids: device.serviceSolicitationUuids,\n txPowerLevel: device.txPowerLevel,\n manufacturerDataHex: device.manufacturerDataHex,\n serviceData: device.serviceData,\n address: device.address,\n addressType: device.addressType,\n state: device.state,\n };\n}\n","import { Buffer } from 'buffer';\nimport { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport {\n type TrezorDebugLogLevel,\n type TrezorDebugLogger,\n filterTrezorDebugLogEntry,\n} from '@onekeyfe/hwk-trezor-connector';\n\nimport type { TrezorBleApi, TrezorBleDeviceInfo } from './types/desktop-api';\n\nexport interface TrezorElectronBleTransportOptions {\n /** The IPC bridge exposed by the main process (typically `window.desktopApi.trezorBle`). */\n bridge?: TrezorBleApi;\n logger?: TrezorDebugLogger;\n}\n\nconst disconnectError = (message: string): Error =>\n Object.assign(new Error(message), { code: HardwareErrorCode.DeviceDisconnected });\n\nconst notConnectedError = (id: string): Error =>\n disconnectError(`Trezor Electron BLE device is not connected: ${id}`);\n\nconst resolveBridge = (options?: TrezorElectronBleTransportOptions): TrezorBleApi => {\n if (options?.bridge) return options.bridge;\n const win =\n typeof window !== 'undefined'\n ? (window as unknown as { desktopApi?: { trezorBle?: TrezorBleApi } })\n : undefined;\n const bridge = win?.desktopApi?.trezorBle;\n if (!bridge) {\n throw createHwkError({\n code: HardwareErrorCode.BridgeNotFound,\n message:\n 'TrezorElectronBleTransport: no bridge found — pass `bridge` or expose `window.desktopApi.trezorBle` from your Electron preload script',\n });\n }\n return bridge;\n};\n\ninterface PendingRead {\n resolve(data: Uint8Array): void;\n reject(error: Error): void;\n}\n\n/**\n * Renderer-side wrapper around the main process's BLE handler. Buffers\n * notifications into a per-device read queue so callers can `read()`\n * sequentially without missing chunks that arrive between reads.\n */\nexport class TrezorElectronBleTransport {\n private readonly _bridge: TrezorBleApi;\n\n private readonly _connected = new Set<string>();\n\n private readonly _readQueues = new Map<string, Uint8Array[]>();\n\n private readonly _pendingReads = new Map<string, PendingRead[]>();\n\n private readonly _disconnectHandlers = new Map<string, Set<() => void>>();\n\n private _disposeNotificationListener?: () => void;\n\n private _disposeDisconnectListener?: () => void;\n\n private readonly _logger?: TrezorElectronBleTransportOptions['logger'];\n\n constructor(options: TrezorElectronBleTransportOptions = {}) {\n this._bridge = resolveBridge(options);\n this._logger = options.logger;\n this._wireGlobalListeners();\n }\n\n async scan(durationMs?: number): Promise<TrezorBleDeviceInfo[]> {\n // No serviceUuids filter: a native service-UUID scan filter drops a\n // Safe 7's ADV packets on Windows (its UUID travels in the scan response,\n // not the ADV packet), so the handler scans unfiltered and does the Trezor\n // matching itself in JS. Passing a filter here would at best be ignored by\n // a current handler and at worst re-break discovery on an older one.\n try {\n return await this._bridge.scan({\n durationMs,\n });\n } catch (error) {\n this._log('warn', 'ble.renderer.scan.error', {\n error: String(error),\n });\n throw error;\n }\n }\n\n async stopScan(): Promise<void> {\n await this._bridge.stopScan();\n }\n\n /** Abandon the in-flight connect/pairing in the main process. */\n async cancelPairing(): Promise<void> {\n await this._bridge.cancelPairing();\n }\n\n async connect(connectId: string): Promise<void> {\n if (this._connected.has(connectId)) return;\n await this._bridge.connect(connectId);\n try {\n await this._bridge.subscribe(connectId);\n } catch (error) {\n // Main process is already connected — tear it down so we don't leak a\n // main-side connection the renderer can no longer address.\n await this._bridge.disconnect(connectId).catch(() => undefined);\n throw error;\n }\n this._connected.add(connectId);\n this._readQueues.set(connectId, []);\n this._pendingReads.set(connectId, []);\n }\n\n async disconnect(connectId: string): Promise<void> {\n this._connected.delete(connectId);\n this._failPendingReads(connectId, notConnectedError(connectId));\n this._readQueues.delete(connectId);\n try {\n await this._bridge.unsubscribe(connectId);\n } catch (error) {\n this._log('warn', 'unsubscribe.error', { connectId, error: String(error) });\n }\n await this._bridge.disconnect(connectId);\n }\n\n async write(connectId: string, data: Uint8Array): Promise<void> {\n if (!this._connected.has(connectId)) throw notConnectedError(connectId);\n const hex = Buffer.from(data).toString('hex');\n await this._bridge.write(connectId, hex);\n }\n\n async read(connectId: string): Promise<Uint8Array> {\n if (!this._connected.has(connectId)) throw notConnectedError(connectId);\n const queue = this._readQueues.get(connectId);\n if (queue && queue.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return queue.shift()!;\n }\n return new Promise<Uint8Array>((resolve, reject) => {\n const pending = this._pendingReads.get(connectId);\n if (!pending) {\n reject(notConnectedError(connectId));\n return;\n }\n pending.push({ resolve, reject });\n });\n }\n\n onDisconnect(connectId: string, handler: () => void): () => void {\n const handlers = this._disconnectHandlers.get(connectId) ?? new Set<() => void>();\n handlers.add(handler);\n this._disconnectHandlers.set(connectId, handlers);\n return () => {\n handlers.delete(handler);\n if (handlers.size === 0) {\n this._disconnectHandlers.delete(connectId);\n }\n };\n }\n\n /** Tear down global listeners — called by the connector's `reset()`. */\n reset(): void {\n this._disposeNotificationListener?.();\n this._disposeDisconnectListener?.();\n this._disposeNotificationListener = undefined;\n this._disposeDisconnectListener = undefined;\n for (const handlers of this._disconnectHandlers.values()) handlers.clear();\n this._disconnectHandlers.clear();\n for (const id of this._connected) this._failPendingReads(id, notConnectedError(id));\n this._connected.clear();\n this._readQueues.clear();\n this._pendingReads.clear();\n }\n\n private _wireGlobalListeners(): void {\n this._disposeNotificationListener = this._bridge.onNotification((id, hex) => {\n const data = new Uint8Array(Buffer.from(hex, 'hex'));\n const pending = this._pendingReads.get(id);\n if (pending && pending.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n pending.shift()!.resolve(data);\n return;\n }\n const queue = this._readQueues.get(id);\n if (queue) queue.push(data);\n });\n this._disposeDisconnectListener = this._bridge.onDeviceDisconnected(id => {\n this._connected.delete(id);\n this._failPendingReads(id, disconnectError(`Trezor BLE device disconnected: ${id}`));\n this._readQueues.delete(id);\n this._disconnectHandlers.get(id)?.forEach(handler => {\n try {\n handler();\n } catch (error) {\n this._log('error', 'disconnect.handler.threw', { id, error: String(error) });\n }\n });\n });\n }\n\n private _failPendingReads(connectId: string, error: Error): void {\n const pending = this._pendingReads.get(connectId);\n if (!pending) return;\n for (const item of pending) item.reject(error);\n this._pendingReads.set(connectId, []);\n }\n\n private _log(level: TrezorDebugLogLevel, event: string, data?: Record<string, unknown>): void {\n const entry = filterTrezorDebugLogEntry({ level, scope: 'trezor-electron-ble', event, data });\n if (!entry) return;\n\n this._logger?.(entry);\n }\n}\n\nexport function createTrezorElectronBleTransport(\n options?: TrezorElectronBleTransportOptions\n): TrezorElectronBleTransport {\n return new TrezorElectronBleTransport(options);\n}\n"],"mappings":"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","names":["Buffer","HardwareErrorCode","createHwkError","filterTrezorDebugLogEntry","createHwkError","HardwareErrorCode","Buffer","filterTrezorDebugLogEntry"]}
|
|
1
|
+
{"version":3,"sources":["../src/TrezorElectronBleConnector.ts","../src/TrezorElectronBleTransport.ts","../src/bleProfile.ts"],"sourcesContent":["import { Buffer } from 'buffer';\nimport {\n TREZOR_BLE_PACKET_SIZE,\n TREZOR_SAFE_7_MODEL,\n isTrezorBleDescriptor,\n} from '@onekeyfe/hwk-trezor-adapter';\nimport { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport {\n TrezorConnectorBase,\n type TrezorConnectorBaseOptions,\n type TrezorConnectorByteTransport,\n type TrezorDebugLogLevel,\n type TrezorDebugLogger,\n filterTrezorDebugLogEntry,\n} from '@onekeyfe/hwk-trezor-connector';\n\nimport {\n TrezorElectronBleTransport,\n type TrezorElectronBleTransportOptions,\n} from './TrezorElectronBleTransport';\n\nimport type { ConnectorDevice } from '@onekeyfe/hwk-adapter-core';\nimport type { ThirdPartyBleDeviceInfo } from '@onekeyfe/hwk-desktop-noble-ble';\n\nconst isStandardHwkError = (error: unknown): error is { code: number } =>\n typeof (error as { code?: unknown })?.code === 'number';\n\nexport interface TrezorElectronBleConnectorOptions {\n transport?: TrezorElectronBleTransport;\n transportOptions?: TrezorElectronBleTransportOptions;\n thp?: TrezorConnectorBaseOptions['thp'];\n deviceSessionFactory?: TrezorConnectorBaseOptions['deviceSessionFactory'];\n}\n\nexport class TrezorElectronBleConnector extends TrezorConnectorBase {\n private _transport: TrezorElectronBleTransport | undefined;\n\n private readonly _transportOptions?: TrezorElectronBleTransportOptions;\n\n private readonly _logger?: TrezorDebugLogger;\n\n constructor(options?: TrezorElectronBleConnectorOptions) {\n super({\n connectionType: 'ble',\n chunkSize: TREZOR_BLE_PACKET_SIZE,\n thp: options?.thp,\n deviceSessionFactory: options?.deviceSessionFactory,\n });\n this._transport = options?.transport;\n this._transportOptions = options?.transportOptions;\n this._logger = options?.transportOptions?.logger;\n }\n\n protected async enumerateDevices(): Promise<ConnectorDevice[]> {\n const transport = this._ensureTransport();\n const devices = await transport.scan();\n const filtered = devices.filter(isTrezorBleDescriptor);\n if (filtered.length !== devices.length) {\n this._log('info', 'ble.connector.enumerate.filtered', {\n transport: 'electron-ble',\n descriptorCount: devices.length,\n filteredCount: filtered.length,\n dropped: devices.filter(device => !isTrezorBleDescriptor(device)).map(toBleFilterLogSample),\n kept: filtered.map(toBleFilterLogSample),\n });\n }\n return filtered.map(d => ({\n connectId: d.id,\n deviceId: '',\n name: d.name ?? d.localName ?? 'Trezor Safe 7',\n model: TREZOR_SAFE_7_MODEL,\n connectionType: 'ble' as const,\n // Promote the typed BLE fields the device surface already has slots for.\n rssi: d.rssi ?? null,\n isConnectable: d.isConnectable ?? null,\n capabilities: { persistentDeviceIdentity: false },\n // Stash the FULL scan-time advertisement so the app/debug layer sees\n // everything the OS BLE stack exposed (mirrors the WebUSB connector's\n // `raw.descriptor`). This is where a cross-transport identity, if any,\n // would surface (manufacturerData / serviceData / localName).\n raw: {\n transport: 'electron-ble',\n descriptor: d,\n },\n }));\n }\n\n protected async createByteTransport(\n device: ConnectorDevice\n ): Promise<TrezorConnectorByteTransport> {\n const transport = this._ensureTransport();\n try {\n await transport.connect(device.connectId);\n } catch (error) {\n // Rethrowing the caught error (typed `unknown`) as-is is intentional.\n // eslint-disable-next-line @typescript-eslint/no-throw-literal\n if (isStandardHwkError(error)) throw error;\n const reason = error instanceof Error ? error.message : String(error);\n // The device wasn't found at all → DeviceNotFound. Otherwise the connect\n // itself failed: noble drops the real CoreBluetooth reason (hardcodes\n // \"connection failed\" / a timeout), so we CANNOT tell a stale bond from an\n // out-of-range / unresponsive device. Surface one honest, generic\n // BleConnectFailed instead of guessing a specific cause.\n if (/device not found/i.test(reason)) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Trezor BLE device not found: ${device.connectId}`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n // cancelPairing abandoned the connect. Reporting that as a connect failure\n // would tell the user the device is unreachable when they are the one who\n // stopped it.\n if (/connect cancelled/i.test(reason)) {\n throw createHwkError({\n code: HardwareErrorCode.BlePairingCancelled,\n message: `Trezor BLE pairing cancelled: ${device.connectId}`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n throw createHwkError({\n code: HardwareErrorCode.BleConnectFailed,\n message: `Trezor BLE connect failed: ${device.connectId} (${reason})`,\n params: { connectId: device.connectId, originalError: { message: reason } },\n });\n }\n\n return {\n write: async (chunk: Buffer) => {\n await transport.write(device.connectId, Uint8Array.from(chunk));\n },\n read: async () => {\n const data = await transport.read(device.connectId);\n return Buffer.from(data);\n },\n close: () => transport.disconnect(device.connectId),\n onDisconnect: (handler: () => void) => transport.onDisconnect(device.connectId, handler),\n };\n }\n\n protected resolveUnlistedDevice(deviceId: string): ConnectorDevice | undefined {\n const connectId = deviceId.trim();\n if (!connectId) return undefined;\n return {\n connectId,\n deviceId: '',\n name: 'Trezor Safe 7',\n model: TREZOR_SAFE_7_MODEL,\n capabilities: { persistentDeviceIdentity: false },\n };\n }\n\n override async cancel(sessionId: string): Promise<void> {\n await super.cancel(sessionId);\n // Base cancel only settles UI waiters; a connect stuck in the main process\n // must be abandoned there.\n try {\n await this._transport?.cancelPairing();\n } catch {\n // Cancel must never throw.\n }\n }\n\n reset(): void {\n super.reset();\n this._transport?.reset();\n this._transport = undefined;\n }\n\n private _ensureTransport(): TrezorElectronBleTransport {\n if (!this._transport) {\n this._transport = new TrezorElectronBleTransport(this._transportOptions);\n }\n return this._transport;\n }\n\n private _log(level: TrezorDebugLogLevel, event: string, data?: Record<string, unknown>): void {\n const entry = filterTrezorDebugLogEntry({ level, scope: 'trezor-electron-ble', event, data });\n if (!entry) return;\n\n try {\n this._logger?.(entry);\n } catch {\n // Debug logging must not affect BLE connector behavior.\n }\n }\n}\n\nexport function createTrezorElectronBleConnector(\n options?: TrezorElectronBleConnectorOptions\n): TrezorElectronBleConnector {\n return new TrezorElectronBleConnector(options);\n}\n\nfunction readStringArrayField(source: ThirdPartyBleDeviceInfo, key: string): string[] | undefined {\n const value = (source as unknown as Record<string, unknown>)[key];\n if (!Array.isArray(value)) return undefined;\n return value.filter((item): item is string => typeof item === 'string');\n}\n\nfunction toBleFilterLogSample(device: ThirdPartyBleDeviceInfo): Record<string, unknown> {\n return {\n id: device.id,\n name: device.name,\n localName: device.localName,\n rssi: device.rssi,\n isConnectable: device.isConnectable,\n keys: Object.keys(device).sort(),\n matchesTrezorService: isTrezorBleDescriptor(device),\n serviceUUIDs: readStringArrayField(device, 'serviceUUIDs'),\n serviceUuids: readStringArrayField(device, 'serviceUuids'),\n advertisedServiceUuids: readStringArrayField(device, 'advertisedServiceUuids'),\n serviceSolicitationUuids: device.serviceSolicitationUuids,\n txPowerLevel: device.txPowerLevel,\n manufacturerDataHex: device.manufacturerDataHex,\n serviceData: device.serviceData,\n address: device.address,\n addressType: device.addressType,\n state: device.state,\n };\n}\n","import { Buffer } from 'buffer';\nimport { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport {\n type TrezorDebugLogLevel,\n type TrezorDebugLogger,\n filterTrezorDebugLogEntry,\n} from '@onekeyfe/hwk-trezor-connector';\n\nimport { TREZOR_BLE_CONNECT_PROFILE, TREZOR_BLE_MATCH, TREZOR_BLE_VENDOR } from './bleProfile';\n\nimport type { ThirdPartyBleApi, ThirdPartyBleDeviceInfo } from '@onekeyfe/hwk-desktop-noble-ble';\n\nexport interface TrezorElectronBleTransportOptions {\n /** The IPC bridge exposed by the main process (typically `window.desktopApi.trezorBle`). */\n bridge?: ThirdPartyBleApi;\n logger?: TrezorDebugLogger;\n}\n\nconst disconnectError = (message: string): Error =>\n Object.assign(new Error(message), { code: HardwareErrorCode.DeviceDisconnected });\n\nconst notConnectedError = (id: string): Error =>\n disconnectError(`Trezor Electron BLE device is not connected: ${id}`);\n\nconst resolveBridge = (options?: TrezorElectronBleTransportOptions): ThirdPartyBleApi => {\n if (options?.bridge) return options.bridge;\n const win =\n typeof window !== 'undefined'\n ? (window as unknown as { desktopApi?: { trezorBle?: ThirdPartyBleApi } })\n : undefined;\n const bridge = win?.desktopApi?.trezorBle;\n if (!bridge) {\n throw createHwkError({\n code: HardwareErrorCode.BridgeNotFound,\n message:\n 'TrezorElectronBleTransport: no bridge found — pass `bridge` or expose `window.desktopApi.trezorBle` from your Electron preload script',\n });\n }\n return bridge;\n};\n\ninterface PendingRead {\n resolve(data: Uint8Array): void;\n reject(error: Error): void;\n}\n\n/**\n * Renderer-side wrapper around the main process's BLE handler. Buffers\n * notifications into a per-device read queue so callers can `read()`\n * sequentially without missing chunks that arrive between reads.\n */\nexport class TrezorElectronBleTransport {\n private readonly _bridge: ThirdPartyBleApi;\n\n private readonly _connected = new Set<string>();\n\n private readonly _readQueues = new Map<string, Uint8Array[]>();\n\n private readonly _pendingReads = new Map<string, PendingRead[]>();\n\n private readonly _disconnectHandlers = new Map<string, Set<() => void>>();\n\n private _disposeNotificationListener?: () => void;\n\n private _disposeDisconnectListener?: () => void;\n\n private readonly _logger?: TrezorElectronBleTransportOptions['logger'];\n\n constructor(options: TrezorElectronBleTransportOptions = {}) {\n this._bridge = resolveBridge(options);\n this._logger = options.logger;\n this._wireGlobalListeners();\n }\n\n async scan(durationMs?: number): Promise<ThirdPartyBleDeviceInfo[]> {\n // `match` is applied in JS, after an unfiltered radio scan — it is not a\n // native scan filter. That distinction matters: a native service-UUID\n // filter drops a Safe 7's ADV packets on Windows, because its UUID travels\n // in the scan response rather than the ADV packet. Hence the name patterns,\n // which match what the ADV packet does carry.\n try {\n return await this._bridge.scan({\n vendor: TREZOR_BLE_VENDOR,\n match: TREZOR_BLE_MATCH,\n durationMs,\n });\n } catch (error) {\n this._log('warn', 'ble.renderer.scan.error', {\n error: String(error),\n });\n throw error;\n }\n }\n\n async stopScan(): Promise<void> {\n await this._bridge.stopScan();\n }\n\n /** Abandon the in-flight connect/pairing in the main process. */\n async cancelPairing(): Promise<void> {\n await this._bridge.cancelPairing();\n }\n\n async connect(connectId: string): Promise<void> {\n if (this._connected.has(connectId)) return;\n // The shared handler holds no vendor defaults: every GATT uuid and the\n // padded-write framing travel with the call.\n await this._bridge.connect(connectId, TREZOR_BLE_CONNECT_PROFILE);\n try {\n await this._bridge.subscribe(connectId);\n } catch (error) {\n // Main process is already connected — tear it down so we don't leak a\n // main-side connection the renderer can no longer address.\n await this._bridge.disconnect(connectId).catch(() => undefined);\n throw error;\n }\n this._connected.add(connectId);\n this._readQueues.set(connectId, []);\n this._pendingReads.set(connectId, []);\n }\n\n async disconnect(connectId: string): Promise<void> {\n this._connected.delete(connectId);\n this._failPendingReads(connectId, notConnectedError(connectId));\n this._readQueues.delete(connectId);\n try {\n await this._bridge.unsubscribe(connectId);\n } catch (error) {\n this._log('warn', 'unsubscribe.error', { connectId, error: String(error) });\n }\n await this._bridge.disconnect(connectId);\n }\n\n async write(connectId: string, data: Uint8Array): Promise<void> {\n if (!this._connected.has(connectId)) throw notConnectedError(connectId);\n const hex = Buffer.from(data).toString('hex');\n await this._bridge.write(connectId, hex);\n }\n\n async read(connectId: string): Promise<Uint8Array> {\n if (!this._connected.has(connectId)) throw notConnectedError(connectId);\n const queue = this._readQueues.get(connectId);\n if (queue && queue.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return queue.shift()!;\n }\n return new Promise<Uint8Array>((resolve, reject) => {\n const pending = this._pendingReads.get(connectId);\n if (!pending) {\n reject(notConnectedError(connectId));\n return;\n }\n pending.push({ resolve, reject });\n });\n }\n\n onDisconnect(connectId: string, handler: () => void): () => void {\n const handlers = this._disconnectHandlers.get(connectId) ?? new Set<() => void>();\n handlers.add(handler);\n this._disconnectHandlers.set(connectId, handlers);\n return () => {\n handlers.delete(handler);\n if (handlers.size === 0) {\n this._disconnectHandlers.delete(connectId);\n }\n };\n }\n\n /** Tear down global listeners — called by the connector's `reset()`. */\n reset(): void {\n this._disposeNotificationListener?.();\n this._disposeDisconnectListener?.();\n this._disposeNotificationListener = undefined;\n this._disposeDisconnectListener = undefined;\n for (const handlers of this._disconnectHandlers.values()) handlers.clear();\n this._disconnectHandlers.clear();\n for (const id of this._connected) this._failPendingReads(id, notConnectedError(id));\n this._connected.clear();\n this._readQueues.clear();\n this._pendingReads.clear();\n }\n\n private _wireGlobalListeners(): void {\n this._disposeNotificationListener = this._bridge.onNotification((id, hex) => {\n const data = new Uint8Array(Buffer.from(hex, 'hex'));\n const pending = this._pendingReads.get(id);\n if (pending && pending.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n pending.shift()!.resolve(data);\n return;\n }\n const queue = this._readQueues.get(id);\n if (queue) queue.push(data);\n });\n this._disposeDisconnectListener = this._bridge.onDeviceDisconnected(id => {\n this._connected.delete(id);\n this._failPendingReads(id, disconnectError(`Trezor BLE device disconnected: ${id}`));\n this._readQueues.delete(id);\n this._disconnectHandlers.get(id)?.forEach(handler => {\n try {\n handler();\n } catch (error) {\n this._log('error', 'disconnect.handler.threw', { id, error: String(error) });\n }\n });\n });\n }\n\n private _failPendingReads(connectId: string, error: Error): void {\n const pending = this._pendingReads.get(connectId);\n if (!pending) return;\n for (const item of pending) item.reject(error);\n this._pendingReads.set(connectId, []);\n }\n\n private _log(level: TrezorDebugLogLevel, event: string, data?: Record<string, unknown>): void {\n const entry = filterTrezorDebugLogEntry({ level, scope: 'trezor-electron-ble', event, data });\n if (!entry) return;\n\n this._logger?.(entry);\n }\n}\n\nexport function createTrezorElectronBleTransport(\n options?: TrezorElectronBleTransportOptions\n): TrezorElectronBleTransport {\n return new TrezorElectronBleTransport(options);\n}\n","import { TREZOR_BLE_PACKET_SIZE, TREZOR_BLE_UUIDS } from '@onekeyfe/hwk-trezor-adapter';\n\nimport type { ElectronBleConnectOptions, ElectronBleMatch } from '@onekeyfe/hwk-adapter-core';\n\n/** Inter-chunk delay during write, matches OneKey's `UNIFIED_WRITE_DELAY`. */\nexport const TREZOR_BLE_WRITE_CHUNK_DELAY_MS = 5;\n\nexport const TREZOR_BLE_VENDOR = 'trezor';\n\n/**\n * How the shared desktop handler recognizes a Trezor. The main process holds\n * no vendor knowledge, so the name test that used to live there travels as\n * data: a local name must satisfy every pattern, which reproduces\n * `isTrezorSafe7BleName` — \"Trezor\" plus either \"Safe 7\" or \"T3W1\".\n */\nexport const TREZOR_BLE_MATCH: ElectronBleMatch = {\n serviceUuids: [TREZOR_BLE_UUIDS.service],\n namePatterns: ['\\\\bTrezor\\\\b', '\\\\bSafe\\\\s*7\\\\b|\\\\bT3W1\\\\b'],\n};\n\n/**\n * Trezor firmware expects fixed-size packets: a short final packet is silently\n * dropped, so every write is padded to the full MTU.\n */\nexport const TREZOR_BLE_CONNECT_PROFILE: ElectronBleConnectOptions = {\n vendor: TREZOR_BLE_VENDOR,\n serviceUuid: TREZOR_BLE_UUIDS.service,\n writeUuid: TREZOR_BLE_UUIDS.write,\n notifyUuid: TREZOR_BLE_UUIDS.notify,\n write: {\n mode: 'padded',\n chunkSize: TREZOR_BLE_PACKET_SIZE,\n chunkDelayMs: TREZOR_BLE_WRITE_CHUNK_DELAY_MS,\n },\n};\n"],"mappings":"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","names":["Buffer","TREZOR_BLE_PACKET_SIZE","HardwareErrorCode","createHwkError","filterTrezorDebugLogEntry","TREZOR_BLE_PACKET_SIZE","createHwkError","HardwareErrorCode","Buffer","filterTrezorDebugLogEntry"]}
|