@onekeyfe/hwk-ledger-adapter 1.1.26-patch.2 → 1.1.27-alpha.1
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 +14 -4
- package/dist/index.d.ts +14 -4
- package/dist/index.js +78 -87
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +78 -87
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -16,12 +16,6 @@ import {
|
|
|
16
16
|
|
|
17
17
|
// src/errors.ts
|
|
18
18
|
import { HardwareErrorCode, enrichErrorMessage } from "@onekeyfe/hwk-adapter-core";
|
|
19
|
-
var MULTIPLE_USB_LEDGER_DEVICES_ERROR_MESSAGE = "Multiple Ledger USB devices are connected. Please connect only one Ledger device and try again.";
|
|
20
|
-
function createMultipleUsbLedgerDevicesError() {
|
|
21
|
-
return Object.assign(new Error(MULTIPLE_USB_LEDGER_DEVICES_ERROR_MESSAGE), {
|
|
22
|
-
code: HardwareErrorCode.DeviceOneDeviceOnly
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
19
|
function ledgerFailure(code, error, appName, tag, params) {
|
|
26
20
|
const payload = { error, code };
|
|
27
21
|
if (appName !== void 0) payload.appName = appName;
|
|
@@ -453,7 +447,7 @@ function btcAccountIndexFromPath(path) {
|
|
|
453
447
|
return Number.isFinite(accountIndex) ? accountIndex : null;
|
|
454
448
|
}
|
|
455
449
|
var _LedgerAdapter = class _LedgerAdapter {
|
|
456
|
-
constructor(connector) {
|
|
450
|
+
constructor(connector, options) {
|
|
457
451
|
this.vendor = "ledger";
|
|
458
452
|
this.emitter = new TypedEventEmitter();
|
|
459
453
|
this._discoveredDevices = /* @__PURE__ */ new Map();
|
|
@@ -475,7 +469,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
475
469
|
*
|
|
476
470
|
* - If a session already exists for the given connectId, reuse it.
|
|
477
471
|
* - If ANY session exists (Ledger IDs are ephemeral), reuse it.
|
|
478
|
-
* - Otherwise: search →
|
|
472
|
+
* - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.
|
|
479
473
|
*/
|
|
480
474
|
// Mutex for ensureConnected — prevents concurrent calls from establishing duplicate connections
|
|
481
475
|
this._connectingPromise = null;
|
|
@@ -506,6 +500,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
506
500
|
this.emitter.emit("ui-event", event);
|
|
507
501
|
};
|
|
508
502
|
this.connector = connector;
|
|
503
|
+
this._handleSelectDevice = options?.handleSelectDevice ?? false;
|
|
509
504
|
this._jobQueue = new DeviceJobQueue();
|
|
510
505
|
this.registerEventListeners();
|
|
511
506
|
}
|
|
@@ -579,18 +574,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
579
574
|
);
|
|
580
575
|
return Array.from(this._discoveredDevices.values());
|
|
581
576
|
}
|
|
582
|
-
// USB single-session invariant: evict all sessions, best-effort (see connectDevice).
|
|
583
|
-
async _evictAllSessions() {
|
|
584
|
-
if (this._sessions.size === 0) return;
|
|
585
|
-
const stale = [...this._sessions.values()];
|
|
586
|
-
this._sessions.clear();
|
|
587
|
-
for (const sid of stale) {
|
|
588
|
-
try {
|
|
589
|
-
await this.connector.disconnect(sid);
|
|
590
|
-
} catch {
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
577
|
static _createDeviceBusyError(method) {
|
|
595
578
|
return Object.assign(new Error(`Ledger device is busy while calling ${method}`), {
|
|
596
579
|
code: HardwareErrorCode2.DeviceBusy
|
|
@@ -603,9 +586,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
603
586
|
code: HardwareErrorCode2.DeviceNotFound
|
|
604
587
|
});
|
|
605
588
|
}
|
|
606
|
-
if (!isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
607
|
-
await this._evictAllSessions();
|
|
608
|
-
}
|
|
609
589
|
await this._ensureDevicePermission(connectId);
|
|
610
590
|
const session = await this.connector.connect(connectId);
|
|
611
591
|
this._sessions.set(connectId, session.sessionId);
|
|
@@ -933,15 +913,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
933
913
|
});
|
|
934
914
|
}
|
|
935
915
|
if (connectId && this._sessions.has(connectId)) return connectId;
|
|
936
|
-
if (
|
|
937
|
-
if (!isLedgerBleConnectionType(this.connector.connectionType) && this._sessions.size > 1) {
|
|
938
|
-
throw Object.assign(
|
|
939
|
-
new Error(
|
|
940
|
-
"Ledger USB session invariant violated: more than one session is active. Please reconnect the device."
|
|
941
|
-
),
|
|
942
|
-
{ code: HardwareErrorCode2.DeviceOneDeviceOnly }
|
|
943
|
-
);
|
|
944
|
-
}
|
|
916
|
+
if (this._sessions.size > 0) {
|
|
945
917
|
return this._sessions.keys().next().value;
|
|
946
918
|
}
|
|
947
919
|
if (!this._connectingPromise) {
|
|
@@ -1029,37 +1001,24 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1029
1001
|
const target = devices.find(
|
|
1030
1002
|
(d) => d.connectId === targetConnectId || d.deviceId === targetConnectId
|
|
1031
1003
|
);
|
|
1032
|
-
if (target) {
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
}
|
|
1041
|
-
const err = Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
|
|
1042
|
-
code: HardwareErrorCode2.DeviceNotFound
|
|
1043
|
-
});
|
|
1044
|
-
if (isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
1045
|
-
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
1004
|
+
if (!target) {
|
|
1005
|
+
const err = Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
|
|
1006
|
+
code: HardwareErrorCode2.DeviceNotFound
|
|
1007
|
+
});
|
|
1008
|
+
if (isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
1009
|
+
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
1010
|
+
}
|
|
1011
|
+
throw err;
|
|
1046
1012
|
}
|
|
1047
|
-
|
|
1013
|
+
return this._connectDeviceOrThrow(target.connectId);
|
|
1048
1014
|
}
|
|
1049
1015
|
if (isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
1050
1016
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
1051
1017
|
code: HardwareErrorCode2.DeviceNotFound
|
|
1052
1018
|
});
|
|
1053
1019
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
}
|
|
1057
|
-
if (devices.length !== 1) {
|
|
1058
|
-
throw Object.assign(new Error("Ledger device not found."), {
|
|
1059
|
-
code: HardwareErrorCode2.DeviceNotFound
|
|
1060
|
-
});
|
|
1061
|
-
}
|
|
1062
|
-
return this._connectDeviceOrThrow(devices[0].connectId);
|
|
1020
|
+
const chosenConnectId = devices.length === 1 ? devices[0].connectId : await this._chooseDeviceFromList(devices);
|
|
1021
|
+
return this._connectDeviceOrThrow(chosenConnectId);
|
|
1063
1022
|
}
|
|
1064
1023
|
async _connectDeviceOrThrow(chosenConnectId) {
|
|
1065
1024
|
const result = await this.connectDevice(chosenConnectId);
|
|
@@ -1075,6 +1034,46 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1075
1034
|
}
|
|
1076
1035
|
return chosenConnectId;
|
|
1077
1036
|
}
|
|
1037
|
+
async _chooseDeviceFromList(devices) {
|
|
1038
|
+
if (!this._handleSelectDevice) {
|
|
1039
|
+
debugLog(
|
|
1040
|
+
`[DMK] Multiple Ledger devices found (${devices.length}); handleSelectDevice=false, picking first (${devices[0].connectId}).`
|
|
1041
|
+
);
|
|
1042
|
+
return devices[0].connectId;
|
|
1043
|
+
}
|
|
1044
|
+
let response;
|
|
1045
|
+
try {
|
|
1046
|
+
const waitPromise = this._uiRegistry.wait(
|
|
1047
|
+
UI_REQUEST.REQUEST_SELECT_DEVICE
|
|
1048
|
+
);
|
|
1049
|
+
this.emitter.emit(UI_REQUEST.REQUEST_SELECT_DEVICE, {
|
|
1050
|
+
type: UI_REQUEST.REQUEST_SELECT_DEVICE,
|
|
1051
|
+
payload: { devices }
|
|
1052
|
+
});
|
|
1053
|
+
response = await waitPromise;
|
|
1054
|
+
} catch (err) {
|
|
1055
|
+
if (err?._tag === UI_REQUEST_PREEMPTED_TAG) {
|
|
1056
|
+
this.emitter.emit(UI_REQUEST.CLOSE_UI_WINDOW, {
|
|
1057
|
+
type: UI_REQUEST.CLOSE_UI_WINDOW,
|
|
1058
|
+
payload: {}
|
|
1059
|
+
});
|
|
1060
|
+
throw Object.assign(new Error("Device selection superseded"), {
|
|
1061
|
+
_tag: ERROR_TAG.UserAborted,
|
|
1062
|
+
code: HardwareErrorCode2.UserAborted,
|
|
1063
|
+
cause: err
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
throw err;
|
|
1067
|
+
}
|
|
1068
|
+
const chosen = devices.find((d) => d.connectId === response?.sdkConnectId);
|
|
1069
|
+
if (!chosen) {
|
|
1070
|
+
throw Object.assign(
|
|
1071
|
+
new Error(`Selected sdkConnectId '${response?.sdkConnectId}' not in discovered list`),
|
|
1072
|
+
{ _tag: ERROR_TAG.DeviceNotRecognized }
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
return chosen.connectId;
|
|
1076
|
+
}
|
|
1078
1077
|
/**
|
|
1079
1078
|
* Call the connector with automatic session resolution and disconnect retry.
|
|
1080
1079
|
*
|
|
@@ -1239,7 +1238,8 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1239
1238
|
} catch {
|
|
1240
1239
|
}
|
|
1241
1240
|
}
|
|
1242
|
-
const
|
|
1241
|
+
const retryConnectId = isLedgerBleConnectionType(this.connector.connectionType) ? resolvedConnectId : void 0;
|
|
1242
|
+
const reConnectId = await this.ensureConnected(retryConnectId, signal);
|
|
1243
1243
|
const reSessionId = this._sessions.get(reConnectId);
|
|
1244
1244
|
if (!reSessionId) throw lastErr;
|
|
1245
1245
|
if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
|
|
@@ -1307,7 +1307,8 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1307
1307
|
*/
|
|
1308
1308
|
async _retryAfterStuckApp(resolvedConnectId, method, params, signal, originalErr, fingerprint) {
|
|
1309
1309
|
await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
|
|
1310
|
-
const
|
|
1310
|
+
const retryTargetConnectId = isLedgerBleConnectionType(this.connector.connectionType) ? resolvedConnectId : void 0;
|
|
1311
|
+
const retryConnectId = await this.ensureConnected(retryTargetConnectId, signal);
|
|
1311
1312
|
const retrySessionId = this._sessions.get(retryConnectId);
|
|
1312
1313
|
if (!retrySessionId) throw originalErr;
|
|
1313
1314
|
if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
|
|
@@ -3051,12 +3052,6 @@ var LedgerConnectorBase = class {
|
|
|
3051
3052
|
}
|
|
3052
3053
|
// ---------------------------------------------------------------------------
|
|
3053
3054
|
// IConnector -- Device discovery
|
|
3054
|
-
//
|
|
3055
|
-
// Discovery never throws on multiple USB devices — it returns the full list.
|
|
3056
|
-
// The "connect exactly one device" rule is enforced upstream: an explicit
|
|
3057
|
-
// connectId connects that device (or fails as not-found), and only the
|
|
3058
|
-
// no-connectId USB path rejects when more than one device is present
|
|
3059
|
-
// (see LedgerAdapter._connectFirstOrSelect).
|
|
3060
3055
|
// ---------------------------------------------------------------------------
|
|
3061
3056
|
async searchDevices() {
|
|
3062
3057
|
const dm = await this._getDeviceManager();
|
|
@@ -3162,16 +3157,7 @@ var LedgerConnectorBase = class {
|
|
|
3162
3157
|
}
|
|
3163
3158
|
throw err;
|
|
3164
3159
|
}
|
|
3165
|
-
|
|
3166
|
-
this._watchSessionState(sessionId, externalConnectId);
|
|
3167
|
-
} catch (subErr) {
|
|
3168
|
-
debugLog("[DMK] state subscription failed during connect; disconnecting session:", subErr);
|
|
3169
|
-
try {
|
|
3170
|
-
await dm.disconnect(sessionId);
|
|
3171
|
-
} catch {
|
|
3172
|
-
}
|
|
3173
|
-
throw subErr;
|
|
3174
|
-
}
|
|
3160
|
+
this._watchSessionState(sessionId, externalConnectId);
|
|
3175
3161
|
const info = dm.getDiscoveredDeviceInfo(path);
|
|
3176
3162
|
const session = {
|
|
3177
3163
|
sessionId,
|
|
@@ -3237,7 +3223,8 @@ var LedgerConnectorBase = class {
|
|
|
3237
3223
|
* `LedgerAdapter._sessions` map would hold a dead session entry until
|
|
3238
3224
|
* the next call hit `DeviceSessionNotFound`.
|
|
3239
3225
|
*
|
|
3240
|
-
*
|
|
3226
|
+
* Best-effort: any error subscribing is swallowed so a flaky DMK
|
|
3227
|
+
* doesn't break the connect path.
|
|
3241
3228
|
*/
|
|
3242
3229
|
_watchSessionState(sessionId, externalConnectId) {
|
|
3243
3230
|
const dmk = this._dmk;
|
|
@@ -3249,20 +3236,24 @@ var LedgerConnectorBase = class {
|
|
|
3249
3236
|
} catch {
|
|
3250
3237
|
}
|
|
3251
3238
|
}
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3239
|
+
try {
|
|
3240
|
+
const sub = dmk.getDeviceSessionState({ sessionId }).subscribe({
|
|
3241
|
+
next: (state) => {
|
|
3242
|
+
if (state?.deviceStatus === "NOT CONNECTED") {
|
|
3243
|
+
this._handleAutonomousDisconnect(sessionId, externalConnectId);
|
|
3244
|
+
}
|
|
3245
|
+
},
|
|
3246
|
+
error: () => {
|
|
3247
|
+
this._handleAutonomousDisconnect(sessionId, externalConnectId);
|
|
3248
|
+
},
|
|
3249
|
+
complete: () => {
|
|
3255
3250
|
this._handleAutonomousDisconnect(sessionId, externalConnectId);
|
|
3256
3251
|
}
|
|
3257
|
-
}
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
this._handleAutonomousDisconnect(sessionId, externalConnectId);
|
|
3263
|
-
}
|
|
3264
|
-
});
|
|
3265
|
-
this._sessionStateSubs.set(sessionId, sub);
|
|
3252
|
+
});
|
|
3253
|
+
this._sessionStateSubs.set(sessionId, sub);
|
|
3254
|
+
} catch (err) {
|
|
3255
|
+
debugLog("[DMK] _watchSessionState subscribe failed:", err);
|
|
3256
|
+
}
|
|
3266
3257
|
}
|
|
3267
3258
|
_unwatchSessionState(sessionId) {
|
|
3268
3259
|
const sub = this._sessionStateSubs.get(sessionId);
|