@onekeyfe/hwk-ledger-adapter 1.1.26-alpha.15 → 1.1.26-alpha.21
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 +96 -63
- package/dist/index.d.ts +96 -63
- package/dist/index.js +798 -100
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +798 -100
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -16,6 +16,12 @@ 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
|
+
}
|
|
19
25
|
function ledgerFailure(code, error, appName, tag, params) {
|
|
20
26
|
const payload = { error, code };
|
|
21
27
|
if (appName !== void 0) payload.appName = appName;
|
|
@@ -300,6 +306,15 @@ function isAppNotInstalledError(err) {
|
|
|
300
306
|
if (hasStatusCode(err, APP_NOT_INSTALLED_CODES)) return true;
|
|
301
307
|
return false;
|
|
302
308
|
}
|
|
309
|
+
function isOutOfMemoryError(err) {
|
|
310
|
+
if (!err || typeof err !== "object") return false;
|
|
311
|
+
const e = err;
|
|
312
|
+
if (e._tag === "OutOfMemoryDAError") return true;
|
|
313
|
+
if (typeof e.message === "string" && /out of memory|not enough.*space|insufficient.*memory/i.test(e.message)) {
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
303
318
|
function isDeviceDisconnectedError(err) {
|
|
304
319
|
if (!err || typeof err !== "object") return false;
|
|
305
320
|
const e = err;
|
|
@@ -362,6 +377,8 @@ function mapLedgerError(err, opts) {
|
|
|
362
377
|
code = HardwareErrorCode.WrongApp;
|
|
363
378
|
} else if (isAppNotInstalledError(err)) {
|
|
364
379
|
code = HardwareErrorCode.AppNotInstalled;
|
|
380
|
+
} else if (isOutOfMemoryError(err)) {
|
|
381
|
+
code = HardwareErrorCode.DeviceOutOfMemory;
|
|
365
382
|
} else if (isDeviceDisconnectedError(err)) {
|
|
366
383
|
code = HardwareErrorCode.DeviceDisconnected;
|
|
367
384
|
} else if (isTimeoutError(err)) {
|
|
@@ -447,7 +464,7 @@ function btcAccountIndexFromPath(path) {
|
|
|
447
464
|
return Number.isFinite(accountIndex) ? accountIndex : null;
|
|
448
465
|
}
|
|
449
466
|
var _LedgerAdapter = class _LedgerAdapter {
|
|
450
|
-
constructor(connector
|
|
467
|
+
constructor(connector) {
|
|
451
468
|
this.vendor = "ledger";
|
|
452
469
|
this.emitter = new TypedEventEmitter();
|
|
453
470
|
this._discoveredDevices = /* @__PURE__ */ new Map();
|
|
@@ -469,7 +486,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
469
486
|
*
|
|
470
487
|
* - If a session already exists for the given connectId, reuse it.
|
|
471
488
|
* - If ANY session exists (Ledger IDs are ephemeral), reuse it.
|
|
472
|
-
* - Otherwise: search → 1 device: auto-connect, multiple:
|
|
489
|
+
* - Otherwise: search → 1 USB device: auto-connect, multiple USB devices: throw, 0: throw.
|
|
473
490
|
*/
|
|
474
491
|
// Mutex for ensureConnected — prevents concurrent calls from establishing duplicate connections
|
|
475
492
|
this._connectingPromise = null;
|
|
@@ -478,16 +495,45 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
478
495
|
// ---------------------------------------------------------------------------
|
|
479
496
|
this.deviceConnectHandler = (data) => {
|
|
480
497
|
const deviceInfo = this.connectorDeviceToDeviceInfo(data.device);
|
|
498
|
+
const hadSession = this._sessions.get(deviceInfo.connectId);
|
|
481
499
|
this._discoveredDevices.set(deviceInfo.connectId, deviceInfo);
|
|
482
500
|
this._sessions.delete(deviceInfo.connectId);
|
|
501
|
+
debugLog(
|
|
502
|
+
"[SESS-DBG] deviceConnectHandler EVENT connectId=",
|
|
503
|
+
deviceInfo.connectId,
|
|
504
|
+
"deviceId=",
|
|
505
|
+
deviceInfo.deviceId,
|
|
506
|
+
"label=",
|
|
507
|
+
deviceInfo.label,
|
|
508
|
+
"serial=",
|
|
509
|
+
deviceInfo.serialNumber,
|
|
510
|
+
"staleSessionDeleted=",
|
|
511
|
+
hadSession ?? "(none)",
|
|
512
|
+
"sessionsAfter=",
|
|
513
|
+
this._snapshotSessions()
|
|
514
|
+
);
|
|
483
515
|
this.emitter.emit(DEVICE.CONNECT, {
|
|
484
516
|
type: DEVICE.CONNECT,
|
|
485
517
|
payload: deviceInfo
|
|
486
518
|
});
|
|
487
519
|
};
|
|
488
520
|
this.deviceDisconnectHandler = (data) => {
|
|
521
|
+
const lostSession = this._sessions.get(data.connectId);
|
|
522
|
+
const lostDeviceInfo = this._discoveredDevices.get(data.connectId);
|
|
489
523
|
this._discoveredDevices.delete(data.connectId);
|
|
490
524
|
this._sessions.delete(data.connectId);
|
|
525
|
+
debugLog(
|
|
526
|
+
"[SESS-DBG] deviceDisconnectHandler EVENT connectId=",
|
|
527
|
+
data.connectId,
|
|
528
|
+
"removedSessionId=",
|
|
529
|
+
lostSession ?? "(none)",
|
|
530
|
+
"removedDeviceId=",
|
|
531
|
+
lostDeviceInfo?.deviceId,
|
|
532
|
+
"removedSerial=",
|
|
533
|
+
lostDeviceInfo?.serialNumber,
|
|
534
|
+
"sessionsAfter=",
|
|
535
|
+
this._snapshotSessions()
|
|
536
|
+
);
|
|
491
537
|
this.emitter.emit(DEVICE.DISCONNECT, {
|
|
492
538
|
type: DEVICE.DISCONNECT,
|
|
493
539
|
payload: { connectId: data.connectId }
|
|
@@ -500,7 +546,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
500
546
|
this.emitter.emit("ui-event", event);
|
|
501
547
|
};
|
|
502
548
|
this.connector = connector;
|
|
503
|
-
this._handleSelectDevice = options?.handleSelectDevice ?? false;
|
|
504
549
|
this._jobQueue = new DeviceJobQueue();
|
|
505
550
|
this.registerEventListeners();
|
|
506
551
|
}
|
|
@@ -549,12 +594,21 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
549
594
|
// Device management
|
|
550
595
|
// ---------------------------------------------------------------------------
|
|
551
596
|
async searchDevices(options) {
|
|
597
|
+
debugLog(
|
|
598
|
+
"[SESS-DBG] searchDevices ENTER resetSession=",
|
|
599
|
+
options?.resetSession ?? false,
|
|
600
|
+
"sessionsBefore=",
|
|
601
|
+
this._snapshotSessions(),
|
|
602
|
+
"discoveredBefore=",
|
|
603
|
+
this._snapshotDiscovered()
|
|
604
|
+
);
|
|
552
605
|
if (options?.resetSession) {
|
|
553
606
|
this._doConnectAbortController?.abort();
|
|
554
607
|
this._sessions.clear();
|
|
555
608
|
this._connectingPromise = null;
|
|
556
609
|
this._doConnectAbortController = null;
|
|
557
610
|
this._btcHighIndexConfirmedThisSession = false;
|
|
611
|
+
debugLog("[SESS-DBG] searchDevices cleared _sessions (resetSession=true)");
|
|
558
612
|
}
|
|
559
613
|
await this._ensureDevicePermission();
|
|
560
614
|
const devices = await this.connector.searchDevices();
|
|
@@ -568,32 +622,110 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
568
622
|
await this._ensureDevicePermission();
|
|
569
623
|
}
|
|
570
624
|
debugLog(
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
625
|
+
"[SESS-DBG] searchDevices RETURN count=",
|
|
626
|
+
this._discoveredDevices.size,
|
|
627
|
+
"devices=",
|
|
628
|
+
devices.map((d) => ({
|
|
629
|
+
connectId: d.connectId,
|
|
630
|
+
deviceId: d.deviceId,
|
|
631
|
+
name: d.name,
|
|
632
|
+
serial: d.serialNumber
|
|
633
|
+
})),
|
|
634
|
+
"sessionsAfter=",
|
|
635
|
+
this._snapshotSessions()
|
|
574
636
|
);
|
|
575
637
|
return Array.from(this._discoveredDevices.values());
|
|
576
638
|
}
|
|
639
|
+
_snapshotSessions() {
|
|
640
|
+
return [...this._sessions.entries()].map(([connectId, sessionId]) => ({
|
|
641
|
+
connectId,
|
|
642
|
+
sessionId
|
|
643
|
+
}));
|
|
644
|
+
}
|
|
645
|
+
_snapshotDiscovered() {
|
|
646
|
+
return [...this._discoveredDevices.entries()].map(([connectId, info]) => ({
|
|
647
|
+
connectId,
|
|
648
|
+
deviceId: info.deviceId,
|
|
649
|
+
label: info.label,
|
|
650
|
+
serial: info.serialNumber
|
|
651
|
+
}));
|
|
652
|
+
}
|
|
653
|
+
// Enforce USB single-session invariant — see connectDevice.
|
|
654
|
+
async _evictAllSessions(reason) {
|
|
655
|
+
if (this._sessions.size === 0) return;
|
|
656
|
+
const stale = [...this._sessions.entries()];
|
|
657
|
+
debugLog(
|
|
658
|
+
"[SESS-DBG] evictAllSessions reason=",
|
|
659
|
+
reason,
|
|
660
|
+
"evicting=",
|
|
661
|
+
stale.map(([cid, sid]) => ({ connectId: cid, sessionId: sid }))
|
|
662
|
+
);
|
|
663
|
+
this._sessions.clear();
|
|
664
|
+
for (const [, sid] of stale) {
|
|
665
|
+
try {
|
|
666
|
+
await this.connector.disconnect(sid);
|
|
667
|
+
} catch (err) {
|
|
668
|
+
debugLog(
|
|
669
|
+
"[SESS-DBG] evictAllSessions disconnect failed sessionId=",
|
|
670
|
+
sid,
|
|
671
|
+
"err=",
|
|
672
|
+
err?.message
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
577
677
|
static _createDeviceBusyError(method) {
|
|
578
678
|
return Object.assign(new Error(`Ledger device is busy while calling ${method}`), {
|
|
579
679
|
code: HardwareErrorCode2.DeviceBusy
|
|
580
680
|
});
|
|
581
681
|
}
|
|
582
682
|
async connectDevice(connectId) {
|
|
683
|
+
debugLog(
|
|
684
|
+
"[SESS-DBG] connectDevice ENTER connectId=",
|
|
685
|
+
connectId || "(empty)",
|
|
686
|
+
"sessionsBefore=",
|
|
687
|
+
this._snapshotSessions(),
|
|
688
|
+
"discoveredBefore=",
|
|
689
|
+
this._snapshotDiscovered()
|
|
690
|
+
);
|
|
583
691
|
try {
|
|
584
692
|
if (isLedgerBleConnectionType(this.connector.connectionType) && !connectId) {
|
|
585
693
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
586
694
|
code: HardwareErrorCode2.DeviceNotFound
|
|
587
695
|
});
|
|
588
696
|
}
|
|
697
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
698
|
+
await this._evictAllSessions("connectDevice");
|
|
699
|
+
}
|
|
589
700
|
await this._ensureDevicePermission(connectId);
|
|
590
701
|
const session = await this.connector.connect(connectId);
|
|
702
|
+
const prev = this._sessions.get(connectId);
|
|
591
703
|
this._sessions.set(connectId, session.sessionId);
|
|
704
|
+
debugLog(
|
|
705
|
+
"[SESS-DBG] connectDevice SET _sessions connectId=",
|
|
706
|
+
connectId,
|
|
707
|
+
"newSessionId=",
|
|
708
|
+
session.sessionId,
|
|
709
|
+
"replacedPrevSessionId=",
|
|
710
|
+
prev ?? "(none)",
|
|
711
|
+
"sessionInfoDeviceId=",
|
|
712
|
+
session.deviceInfo?.deviceId,
|
|
713
|
+
"sessionInfoSerial=",
|
|
714
|
+
session.deviceInfo?.serialNumber,
|
|
715
|
+
"sessionsAfter=",
|
|
716
|
+
this._snapshotSessions()
|
|
717
|
+
);
|
|
592
718
|
if (session.deviceInfo) {
|
|
593
719
|
this._discoveredDevices.set(connectId, session.deviceInfo);
|
|
594
720
|
}
|
|
595
721
|
return success(connectId);
|
|
596
722
|
} catch (err) {
|
|
723
|
+
debugLog(
|
|
724
|
+
"[SESS-DBG] connectDevice ERROR connectId=",
|
|
725
|
+
connectId,
|
|
726
|
+
"err=",
|
|
727
|
+
err?.message
|
|
728
|
+
);
|
|
597
729
|
return this.errorToFailure(err);
|
|
598
730
|
}
|
|
599
731
|
}
|
|
@@ -699,6 +831,62 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
699
831
|
tronSignMessage(connectId, deviceId, params) {
|
|
700
832
|
return this.callChain(connectId, deviceId, "tron", "tronSignMessage", params);
|
|
701
833
|
}
|
|
834
|
+
// ---------------------------------------------------------------------------
|
|
835
|
+
// App management — OS-level Ledger app install / list. Bypass fingerprint
|
|
836
|
+
// (no chain identity to verify) and chain handler dispatch. Progress for
|
|
837
|
+
// installApp is forwarded to the adapter emitter as 'app-install-progress'
|
|
838
|
+
// events so consumers can render progress bars without subscribing to a
|
|
839
|
+
// separate channel.
|
|
840
|
+
// ---------------------------------------------------------------------------
|
|
841
|
+
async installApp(connectId, appName) {
|
|
842
|
+
try {
|
|
843
|
+
const params = {
|
|
844
|
+
appName,
|
|
845
|
+
onProgress: (progress) => {
|
|
846
|
+
this.emitter.emit("app-install-progress", {
|
|
847
|
+
type: "app-install-progress",
|
|
848
|
+
payload: { connectId, appName, ...progress }
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
await this.connectorCall(connectId, "installApp", params);
|
|
853
|
+
return success(void 0);
|
|
854
|
+
} catch (err) {
|
|
855
|
+
return this.errorToFailure(err);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
async listInstalledApps(connectId) {
|
|
859
|
+
try {
|
|
860
|
+
const result = await this.connectorCall(connectId, "listInstalledApps", {});
|
|
861
|
+
return success(result);
|
|
862
|
+
} catch (err) {
|
|
863
|
+
return this.errorToFailure(err);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
async listAvailableApps(connectId) {
|
|
867
|
+
try {
|
|
868
|
+
const result = await this.connectorCall(connectId, "listAvailableApps", {});
|
|
869
|
+
return success(result);
|
|
870
|
+
} catch (err) {
|
|
871
|
+
return this.errorToFailure(err);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
async getLedgerFirmwareVersion(connectId) {
|
|
875
|
+
try {
|
|
876
|
+
const result = await this.connectorCall(connectId, "getFirmwareVersion", {});
|
|
877
|
+
return success(result);
|
|
878
|
+
} catch (err) {
|
|
879
|
+
return this.errorToFailure(err);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
async getLedgerDeviceInfo(connectId) {
|
|
883
|
+
try {
|
|
884
|
+
const result = await this.connectorCall(connectId, "getDeviceInfo", {});
|
|
885
|
+
return success(result);
|
|
886
|
+
} catch (err) {
|
|
887
|
+
return this.errorToFailure(err);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
702
890
|
on(event, listener) {
|
|
703
891
|
this.emitter.on(event, listener);
|
|
704
892
|
}
|
|
@@ -912,10 +1100,50 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
912
1100
|
code: HardwareErrorCode2.DeviceNotFound
|
|
913
1101
|
});
|
|
914
1102
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1103
|
+
debugLog(
|
|
1104
|
+
"[SESS-DBG] ensureConnected ENTER inputConnectId=",
|
|
1105
|
+
connectId || "(empty)",
|
|
1106
|
+
"sessions=",
|
|
1107
|
+
this._snapshotSessions(),
|
|
1108
|
+
"discovered=",
|
|
1109
|
+
this._snapshotDiscovered()
|
|
1110
|
+
);
|
|
1111
|
+
if (connectId && this._sessions.has(connectId)) {
|
|
1112
|
+
debugLog(
|
|
1113
|
+
"[SESS-DBG] ensureConnected RESOLVED path=fast-cache connectId=",
|
|
1114
|
+
connectId,
|
|
1115
|
+
"sessionId=",
|
|
1116
|
+
this._sessions.get(connectId)
|
|
1117
|
+
);
|
|
1118
|
+
return connectId;
|
|
1119
|
+
}
|
|
1120
|
+
if (!connectId && this._sessions.size > 0) {
|
|
1121
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType) && this._sessions.size > 1) {
|
|
1122
|
+
debugLog(
|
|
1123
|
+
"[SESS-DBG] ensureConnected ABORT multiple USB sessions present sessions=",
|
|
1124
|
+
this._snapshotSessions()
|
|
1125
|
+
);
|
|
1126
|
+
throw Object.assign(
|
|
1127
|
+
new Error(
|
|
1128
|
+
"Ledger USB session invariant violated: more than one session is active. Please reconnect the device."
|
|
1129
|
+
),
|
|
1130
|
+
{ code: HardwareErrorCode2.DeviceOneDeviceOnly }
|
|
1131
|
+
);
|
|
1132
|
+
}
|
|
1133
|
+
const ambient = this._sessions.keys().next().value;
|
|
1134
|
+
debugLog(
|
|
1135
|
+
"[SESS-DBG] ensureConnected RESOLVED path=ambient-fallback chosenConnectId=",
|
|
1136
|
+
ambient,
|
|
1137
|
+
"sessionId=",
|
|
1138
|
+
this._sessions.get(ambient)
|
|
1139
|
+
);
|
|
1140
|
+
return ambient;
|
|
918
1141
|
}
|
|
1142
|
+
debugLog(
|
|
1143
|
+
"[SESS-DBG] ensureConnected path=doConnect (no fast match)",
|
|
1144
|
+
"connectId=",
|
|
1145
|
+
connectId || "(empty)"
|
|
1146
|
+
);
|
|
919
1147
|
if (!this._connectingPromise) {
|
|
920
1148
|
this._doConnectAbortController = new AbortController();
|
|
921
1149
|
const innerSignal = this._doConnectAbortController.signal;
|
|
@@ -997,28 +1225,44 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
997
1225
|
throw new Error("_doConnect aborted");
|
|
998
1226
|
}
|
|
999
1227
|
async _connectFirstOrSelect(devices, targetConnectId) {
|
|
1228
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType) && devices.length > 1) {
|
|
1229
|
+
debugLog(
|
|
1230
|
+
`[DMK] Multiple Ledger USB devices found (${devices.length}); refusing to auto-select by ephemeral connectId.`
|
|
1231
|
+
);
|
|
1232
|
+
throw createMultipleUsbLedgerDevicesError();
|
|
1233
|
+
}
|
|
1000
1234
|
if (targetConnectId) {
|
|
1001
1235
|
const target = devices.find(
|
|
1002
1236
|
(d) => d.connectId === targetConnectId || d.deviceId === targetConnectId
|
|
1003
1237
|
);
|
|
1004
|
-
if (
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1238
|
+
if (target) {
|
|
1239
|
+
return this._connectDeviceOrThrow(target.connectId);
|
|
1240
|
+
}
|
|
1241
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType) && devices.length === 1) {
|
|
1242
|
+
debugLog(
|
|
1243
|
+
`[LedgerAdapter] target ${targetConnectId} not in fresh enumeration; accepting sole USB device ${devices[0].connectId} (assumed ephemeral path change)`
|
|
1244
|
+
);
|
|
1245
|
+
return this._connectDeviceOrThrow(devices[0].connectId);
|
|
1012
1246
|
}
|
|
1013
|
-
|
|
1247
|
+
const err = Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
|
|
1248
|
+
code: HardwareErrorCode2.DeviceNotFound
|
|
1249
|
+
});
|
|
1250
|
+
if (isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
1251
|
+
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
1252
|
+
}
|
|
1253
|
+
throw err;
|
|
1014
1254
|
}
|
|
1015
1255
|
if (isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
1016
1256
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
1017
1257
|
code: HardwareErrorCode2.DeviceNotFound
|
|
1018
1258
|
});
|
|
1019
1259
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1260
|
+
if (devices.length !== 1) {
|
|
1261
|
+
throw Object.assign(new Error("Ledger device not found."), {
|
|
1262
|
+
code: HardwareErrorCode2.DeviceNotFound
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
return this._connectDeviceOrThrow(devices[0].connectId);
|
|
1022
1266
|
}
|
|
1023
1267
|
async _connectDeviceOrThrow(chosenConnectId) {
|
|
1024
1268
|
const result = await this.connectDevice(chosenConnectId);
|
|
@@ -1034,46 +1278,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1034
1278
|
}
|
|
1035
1279
|
return chosenConnectId;
|
|
1036
1280
|
}
|
|
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
|
-
}
|
|
1077
1281
|
/**
|
|
1078
1282
|
* Call the connector with automatic session resolution and disconnect retry.
|
|
1079
1283
|
*
|
|
@@ -1083,7 +1287,18 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1083
1287
|
* 4. On disconnect error: clears stale session, re-connects, retries once
|
|
1084
1288
|
*/
|
|
1085
1289
|
async connectorCall(connectId, method, params, fingerprint, permissionDeviceId) {
|
|
1086
|
-
debugLog(
|
|
1290
|
+
debugLog(
|
|
1291
|
+
"[SESS-DBG] connectorCall ENTER method=",
|
|
1292
|
+
method,
|
|
1293
|
+
"callerConnectId=",
|
|
1294
|
+
connectId || "(empty)",
|
|
1295
|
+
"callerDeviceId=",
|
|
1296
|
+
fingerprint?.deviceId ?? permissionDeviceId ?? "(none)",
|
|
1297
|
+
"sessions=",
|
|
1298
|
+
this._snapshotSessions(),
|
|
1299
|
+
"discovered=",
|
|
1300
|
+
this._snapshotDiscovered()
|
|
1301
|
+
);
|
|
1087
1302
|
const queueKey = connectId || "__ledger_default__";
|
|
1088
1303
|
return this._jobQueue.enqueue(
|
|
1089
1304
|
queueKey,
|
|
@@ -1238,8 +1453,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1238
1453
|
} catch {
|
|
1239
1454
|
}
|
|
1240
1455
|
}
|
|
1241
|
-
const
|
|
1242
|
-
const reConnectId = await this.ensureConnected(retryConnectId, signal);
|
|
1456
|
+
const reConnectId = await this.ensureConnected(resolvedConnectId, signal);
|
|
1243
1457
|
const reSessionId = this._sessions.get(reConnectId);
|
|
1244
1458
|
if (!reSessionId) throw lastErr;
|
|
1245
1459
|
if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
|
|
@@ -1307,8 +1521,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1307
1521
|
*/
|
|
1308
1522
|
async _retryAfterStuckApp(resolvedConnectId, method, params, signal, originalErr, fingerprint) {
|
|
1309
1523
|
await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
|
|
1310
|
-
const
|
|
1311
|
-
const retryConnectId = await this.ensureConnected(retryTargetConnectId, signal);
|
|
1524
|
+
const retryConnectId = await this.ensureConnected(resolvedConnectId, signal);
|
|
1312
1525
|
const retrySessionId = this._sessions.get(retryConnectId);
|
|
1313
1526
|
if (!retrySessionId) throw originalErr;
|
|
1314
1527
|
if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
|
|
@@ -1486,7 +1699,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1486
1699
|
const tag = err && typeof err === "object" ? err._tag : void 0;
|
|
1487
1700
|
if (err && typeof err === "object" && "code" in err && typeof err.code === "number") {
|
|
1488
1701
|
const e = err;
|
|
1489
|
-
const params = e.code === HardwareErrorCode2.DevicePermissionDenied && e.reason ? { permissionDeniedReason: e.reason } :
|
|
1702
|
+
const params = e.code === HardwareErrorCode2.DevicePermissionDenied && e.reason ? { permissionDeniedReason: e.reason } : e.params;
|
|
1490
1703
|
return ledgerFailure(e.code, e.message ?? "Unknown error", e.appName, tag, params);
|
|
1491
1704
|
}
|
|
1492
1705
|
const mapped = mapLedgerError(err);
|
|
@@ -1536,7 +1749,7 @@ _LedgerAdapter.MAX_DOCONNECT_CONFIRMS = 3;
|
|
|
1536
1749
|
var LedgerAdapter = _LedgerAdapter;
|
|
1537
1750
|
|
|
1538
1751
|
// src/connector/LedgerConnectorBase.ts
|
|
1539
|
-
import { HardwareErrorCode as
|
|
1752
|
+
import { HardwareErrorCode as HardwareErrorCode8 } from "@onekeyfe/hwk-adapter-core";
|
|
1540
1753
|
|
|
1541
1754
|
// src/device/LedgerDeviceManager.ts
|
|
1542
1755
|
var LedgerDeviceManager = class {
|
|
@@ -1814,7 +2027,7 @@ import { hexToBytes } from "@onekeyfe/hwk-adapter-core";
|
|
|
1814
2027
|
// src/signer/deviceActionToPromise.ts
|
|
1815
2028
|
import { DeviceActionStatus } from "@ledgerhq/device-management-kit";
|
|
1816
2029
|
var IDLE_WATCHDOG_MS = 65e3;
|
|
1817
|
-
function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_MS, onRegisterCanceller) {
|
|
2030
|
+
function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_MS, onRegisterCanceller, onIntermediate) {
|
|
1818
2031
|
return new Promise((resolve, reject) => {
|
|
1819
2032
|
let settled = false;
|
|
1820
2033
|
let lastStep;
|
|
@@ -1896,14 +2109,22 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
|
|
|
1896
2109
|
onInteraction?.("interaction-complete");
|
|
1897
2110
|
sub?.unsubscribe();
|
|
1898
2111
|
rejectWithStepContext(state.error, lastStep, observedSteps, reject);
|
|
1899
|
-
} else if (state.status === DeviceActionStatus.Pending
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
2112
|
+
} else if (state.status === DeviceActionStatus.Pending) {
|
|
2113
|
+
if (onIntermediate) {
|
|
2114
|
+
try {
|
|
2115
|
+
onIntermediate(state.intermediateValue);
|
|
2116
|
+
} catch {
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
if (onInteraction) {
|
|
2120
|
+
const interaction = state.intermediateValue?.requiredUserInteraction;
|
|
2121
|
+
if (interaction && interaction !== "none") {
|
|
2122
|
+
if (interaction === "unlock-device" && timer) {
|
|
2123
|
+
clearTimeout(timer);
|
|
2124
|
+
timer = null;
|
|
2125
|
+
}
|
|
2126
|
+
onInteraction(String(interaction));
|
|
1905
2127
|
}
|
|
1906
|
-
onInteraction(String(interaction));
|
|
1907
2128
|
}
|
|
1908
2129
|
}
|
|
1909
2130
|
},
|
|
@@ -2947,6 +3168,336 @@ async function _createTrx(ctx, sessionId) {
|
|
|
2947
3168
|
return new Trx(new DmkTransport(dmk, sessionId));
|
|
2948
3169
|
}
|
|
2949
3170
|
|
|
3171
|
+
// src/device-apps/DeviceApps.ts
|
|
3172
|
+
import { DeviceActionStatus as DeviceActionStatus2 } from "@ledgerhq/device-management-kit";
|
|
3173
|
+
import { HardwareErrorCode as HardwareErrorCode7 } from "@onekeyfe/hwk-adapter-core";
|
|
3174
|
+
import { Subject } from "rxjs";
|
|
3175
|
+
var INSTALL_TIMEOUT_MS = 5 * 6e4;
|
|
3176
|
+
var DeviceApps = class {
|
|
3177
|
+
constructor(_dmk, _sessionId, _ledgerKit) {
|
|
3178
|
+
this._dmk = _dmk;
|
|
3179
|
+
this._sessionId = _sessionId;
|
|
3180
|
+
this._ledgerKit = _ledgerKit;
|
|
3181
|
+
}
|
|
3182
|
+
async listInstalled(options) {
|
|
3183
|
+
const action = this._dmk.executeDeviceAction({
|
|
3184
|
+
sessionId: this._sessionId,
|
|
3185
|
+
deviceAction: new this._ledgerKit.ListAppsWithMetadataDeviceAction({
|
|
3186
|
+
input: { unlockTimeout: options?.unlockTimeout }
|
|
3187
|
+
})
|
|
3188
|
+
});
|
|
3189
|
+
const result = await deviceActionToPromise(
|
|
3190
|
+
action,
|
|
3191
|
+
this.onInteraction,
|
|
3192
|
+
void 0,
|
|
3193
|
+
this.onRegisterCanceller
|
|
3194
|
+
);
|
|
3195
|
+
return result.filter((a) => a !== null).map(applicationToMetadata);
|
|
3196
|
+
}
|
|
3197
|
+
// Catalog lookup via custom device action — DMK has no typed wrapper for this.
|
|
3198
|
+
async listAvailable() {
|
|
3199
|
+
const customAction = new ListAvailableAppsDeviceAction({
|
|
3200
|
+
GetOsVersionCommand: this._ledgerKit.GetOsVersionCommand,
|
|
3201
|
+
isSuccessCommandResult: this._ledgerKit.isSuccessCommandResult
|
|
3202
|
+
});
|
|
3203
|
+
const action = this._dmk.executeDeviceAction({
|
|
3204
|
+
sessionId: this._sessionId,
|
|
3205
|
+
deviceAction: customAction
|
|
3206
|
+
});
|
|
3207
|
+
const result = await deviceActionToPromise(
|
|
3208
|
+
action,
|
|
3209
|
+
this.onInteraction,
|
|
3210
|
+
void 0,
|
|
3211
|
+
this.onRegisterCanceller
|
|
3212
|
+
);
|
|
3213
|
+
return result.map(applicationToMetadata);
|
|
3214
|
+
}
|
|
3215
|
+
async getFirmwareVersion() {
|
|
3216
|
+
const v = await this._fetchOsVersion();
|
|
3217
|
+
return {
|
|
3218
|
+
seVersion: v.seVersion,
|
|
3219
|
+
mcuSephVersion: v.mcuSephVersion,
|
|
3220
|
+
mcuBootloaderVersion: v.mcuBootloaderVersion,
|
|
3221
|
+
hwVersion: v.hwVersion
|
|
3222
|
+
};
|
|
3223
|
+
}
|
|
3224
|
+
async getDeviceInfo() {
|
|
3225
|
+
const v = await this._fetchOsVersion();
|
|
3226
|
+
return {
|
|
3227
|
+
isBootloader: v.isBootloader,
|
|
3228
|
+
isOsu: v.isOsu,
|
|
3229
|
+
targetId: v.targetId,
|
|
3230
|
+
seTargetId: v.seTargetId,
|
|
3231
|
+
mcuTargetId: v.mcuTargetId,
|
|
3232
|
+
seVersion: v.seVersion,
|
|
3233
|
+
seFlagsHex: bytesToHex2(v.seFlags),
|
|
3234
|
+
mcuSephVersion: v.mcuSephVersion,
|
|
3235
|
+
mcuBootloaderVersion: v.mcuBootloaderVersion,
|
|
3236
|
+
hwVersion: v.hwVersion
|
|
3237
|
+
};
|
|
3238
|
+
}
|
|
3239
|
+
/**
|
|
3240
|
+
* Pre-flight space check. Mirrors DMK's PredictOutOfMemoryTask using the
|
|
3241
|
+
* data we already expose (listInstalled / listAvailable / getOsVersion).
|
|
3242
|
+
* Fails fast with HardwareErrorCode.DeviceOutOfMemory before issuing the
|
|
3243
|
+
* actual install — saves the user the time-to-fail of DMK's state machine.
|
|
3244
|
+
*/
|
|
3245
|
+
async _assertEnoughSpace(appName) {
|
|
3246
|
+
let osVersion;
|
|
3247
|
+
let installed;
|
|
3248
|
+
let available;
|
|
3249
|
+
try {
|
|
3250
|
+
[osVersion, installed, available] = await Promise.all([
|
|
3251
|
+
this._fetchOsVersion(),
|
|
3252
|
+
this.listInstalled(),
|
|
3253
|
+
this.listAvailable()
|
|
3254
|
+
]);
|
|
3255
|
+
} catch (err) {
|
|
3256
|
+
debugLog("[DeviceApps] precheck skipped:", err?.message);
|
|
3257
|
+
return;
|
|
3258
|
+
}
|
|
3259
|
+
if (installed.some((a) => a.versionName === appName)) return;
|
|
3260
|
+
const target = available.find((a) => a.versionName === appName);
|
|
3261
|
+
if (!target) return;
|
|
3262
|
+
const capacity = getDeviceCapacity(osVersion.targetId);
|
|
3263
|
+
if (!capacity) return;
|
|
3264
|
+
const blockSize = capacity.getBlockSize(osVersion.seVersion);
|
|
3265
|
+
const totalBlocks = Math.floor(capacity.memorySize / blockSize);
|
|
3266
|
+
const blocks = (b) => Math.ceil((b ?? 0) / blockSize);
|
|
3267
|
+
const usedBlocks = installed.reduce((sum, a) => sum + blocks(a.bytes), 0);
|
|
3268
|
+
const neededBlocks = blocks(target.bytes);
|
|
3269
|
+
debugLog(
|
|
3270
|
+
"[DeviceApps] space check",
|
|
3271
|
+
"targetId=",
|
|
3272
|
+
osVersion.targetId.toString(16),
|
|
3273
|
+
"memorySize=",
|
|
3274
|
+
capacity.memorySize,
|
|
3275
|
+
"blockSize=",
|
|
3276
|
+
blockSize,
|
|
3277
|
+
"usedBlocks=",
|
|
3278
|
+
usedBlocks,
|
|
3279
|
+
"neededBlocks=",
|
|
3280
|
+
neededBlocks,
|
|
3281
|
+
"totalBlocks=",
|
|
3282
|
+
totalBlocks
|
|
3283
|
+
);
|
|
3284
|
+
if (usedBlocks + neededBlocks > totalBlocks) {
|
|
3285
|
+
const usedBytes = usedBlocks * blockSize;
|
|
3286
|
+
const neededBytes = neededBlocks * blockSize;
|
|
3287
|
+
const freeBytes = Math.max(0, capacity.memorySize - usedBytes);
|
|
3288
|
+
throw Object.assign(
|
|
3289
|
+
new Error(
|
|
3290
|
+
`Not enough space to install "${appName}": needs ${neededBytes} bytes, ${freeBytes} bytes free of ${capacity.memorySize}.`
|
|
3291
|
+
),
|
|
3292
|
+
{
|
|
3293
|
+
code: HardwareErrorCode7.DeviceOutOfMemory,
|
|
3294
|
+
_tag: "OutOfMemoryDAError",
|
|
3295
|
+
appName,
|
|
3296
|
+
params: {
|
|
3297
|
+
requiredBytes: neededBytes,
|
|
3298
|
+
availableBytes: freeBytes,
|
|
3299
|
+
totalBytes: capacity.memorySize
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
);
|
|
3303
|
+
}
|
|
3304
|
+
}
|
|
3305
|
+
// Sole sendCommand wrapper — surfaces unlock-device interaction through
|
|
3306
|
+
// the same onInteraction pipeline as the device-action methods.
|
|
3307
|
+
async _fetchOsVersion() {
|
|
3308
|
+
const customAction = new GetOsVersionDeviceAction({
|
|
3309
|
+
GetOsVersionCommand: this._ledgerKit.GetOsVersionCommand,
|
|
3310
|
+
isSuccessCommandResult: this._ledgerKit.isSuccessCommandResult
|
|
3311
|
+
});
|
|
3312
|
+
const action = this._dmk.executeDeviceAction({
|
|
3313
|
+
sessionId: this._sessionId,
|
|
3314
|
+
deviceAction: customAction
|
|
3315
|
+
});
|
|
3316
|
+
return deviceActionToPromise(
|
|
3317
|
+
action,
|
|
3318
|
+
this.onInteraction,
|
|
3319
|
+
void 0,
|
|
3320
|
+
this.onRegisterCanceller
|
|
3321
|
+
);
|
|
3322
|
+
}
|
|
3323
|
+
async install(appName, onProgress, options) {
|
|
3324
|
+
if (!appName) throw new Error("DeviceApps.install: appName is required");
|
|
3325
|
+
debugLog("[DeviceApps] install:", appName);
|
|
3326
|
+
await this._assertEnoughSpace(appName);
|
|
3327
|
+
const action = this._dmk.executeDeviceAction({
|
|
3328
|
+
sessionId: this._sessionId,
|
|
3329
|
+
deviceAction: new this._ledgerKit.InstallAppDeviceAction({
|
|
3330
|
+
input: { appName, unlockTimeout: options?.unlockTimeout }
|
|
3331
|
+
})
|
|
3332
|
+
});
|
|
3333
|
+
await deviceActionToPromise(
|
|
3334
|
+
action,
|
|
3335
|
+
this.onInteraction,
|
|
3336
|
+
INSTALL_TIMEOUT_MS,
|
|
3337
|
+
this.onRegisterCanceller,
|
|
3338
|
+
onProgress ? (intermediateValue) => {
|
|
3339
|
+
const iv = intermediateValue;
|
|
3340
|
+
if (typeof iv?.progress === "number") {
|
|
3341
|
+
onProgress({
|
|
3342
|
+
progress: iv.progress,
|
|
3343
|
+
requiredUserInteraction: iv.requiredUserInteraction
|
|
3344
|
+
});
|
|
3345
|
+
}
|
|
3346
|
+
} : void 0
|
|
3347
|
+
);
|
|
3348
|
+
}
|
|
3349
|
+
};
|
|
3350
|
+
function bytesToHex2(bytes) {
|
|
3351
|
+
if (!bytes) return "";
|
|
3352
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
3353
|
+
}
|
|
3354
|
+
function applicationToMetadata(app) {
|
|
3355
|
+
return {
|
|
3356
|
+
versionName: app.versionName,
|
|
3357
|
+
versionId: app.versionId,
|
|
3358
|
+
version: app.version,
|
|
3359
|
+
versionDisplayName: app.versionDisplayName,
|
|
3360
|
+
description: app.description,
|
|
3361
|
+
icon: app.icon,
|
|
3362
|
+
bytes: app.bytes,
|
|
3363
|
+
currencyId: app.currencyId,
|
|
3364
|
+
isDevTools: app.isDevTools
|
|
3365
|
+
};
|
|
3366
|
+
}
|
|
3367
|
+
var DEVICE_CAPACITIES = [
|
|
3368
|
+
// Nano S — block size 4K on fw<2.0, 2K on >=2.0. Default 4K (conservative).
|
|
3369
|
+
{
|
|
3370
|
+
mask: 823132160,
|
|
3371
|
+
capacity: {
|
|
3372
|
+
memorySize: 320 * 1024,
|
|
3373
|
+
getBlockSize: (fw) => parseMajor(fw) >= 2 ? 2 * 1024 : 4 * 1024
|
|
3374
|
+
}
|
|
3375
|
+
},
|
|
3376
|
+
// Nano S Plus
|
|
3377
|
+
{ mask: 856686592, capacity: { memorySize: 1533 * 1024, getBlockSize: () => 32 } },
|
|
3378
|
+
// Nano X
|
|
3379
|
+
{ mask: 855638016, capacity: { memorySize: 2 * 1024 * 1024, getBlockSize: () => 4 * 1024 } },
|
|
3380
|
+
// Stax
|
|
3381
|
+
{ mask: 857735168, capacity: { memorySize: 1533 * 1024, getBlockSize: () => 32 } },
|
|
3382
|
+
// Flex
|
|
3383
|
+
{ mask: 858783744, capacity: { memorySize: 1533 * 1024, getBlockSize: () => 32 } },
|
|
3384
|
+
// Apex / Nano Gen5
|
|
3385
|
+
{ mask: 859832320, capacity: { memorySize: 1533 * 1024, getBlockSize: () => 32 } }
|
|
3386
|
+
];
|
|
3387
|
+
function getDeviceCapacity(targetId) {
|
|
3388
|
+
const masked = targetId & 4294901760;
|
|
3389
|
+
return DEVICE_CAPACITIES.find((d) => d.mask === masked)?.capacity;
|
|
3390
|
+
}
|
|
3391
|
+
function parseMajor(version) {
|
|
3392
|
+
const m = /^(\d+)/.exec(version);
|
|
3393
|
+
return m ? Number(m[1]) : 0;
|
|
3394
|
+
}
|
|
3395
|
+
var GetOsVersionDeviceAction = class {
|
|
3396
|
+
constructor(_deps) {
|
|
3397
|
+
this._deps = _deps;
|
|
3398
|
+
this.input = void 0;
|
|
3399
|
+
}
|
|
3400
|
+
_execute(internalApi) {
|
|
3401
|
+
const subject = new Subject();
|
|
3402
|
+
let cancelled = false;
|
|
3403
|
+
(async () => {
|
|
3404
|
+
try {
|
|
3405
|
+
subject.next({
|
|
3406
|
+
status: DeviceActionStatus2.Pending,
|
|
3407
|
+
intermediateValue: { requiredUserInteraction: "none" }
|
|
3408
|
+
});
|
|
3409
|
+
const result = await internalApi.sendCommand(new this._deps.GetOsVersionCommand());
|
|
3410
|
+
if (cancelled) return;
|
|
3411
|
+
if (!this._deps.isSuccessCommandResult(result)) {
|
|
3412
|
+
const errObj = result?.error;
|
|
3413
|
+
throw new Error(errObj?.message ?? "GetOsVersionCommand failed");
|
|
3414
|
+
}
|
|
3415
|
+
subject.next({ status: DeviceActionStatus2.Completed, output: result.data });
|
|
3416
|
+
subject.complete();
|
|
3417
|
+
} catch (err) {
|
|
3418
|
+
if (cancelled) return;
|
|
3419
|
+
subject.next({ status: DeviceActionStatus2.Error, error: err });
|
|
3420
|
+
subject.complete();
|
|
3421
|
+
}
|
|
3422
|
+
})();
|
|
3423
|
+
return {
|
|
3424
|
+
observable: subject.asObservable(),
|
|
3425
|
+
cancel: () => {
|
|
3426
|
+
cancelled = true;
|
|
3427
|
+
subject.next({ status: DeviceActionStatus2.Stopped });
|
|
3428
|
+
subject.complete();
|
|
3429
|
+
}
|
|
3430
|
+
};
|
|
3431
|
+
}
|
|
3432
|
+
};
|
|
3433
|
+
var ListAvailableAppsDeviceAction = class {
|
|
3434
|
+
constructor(deps) {
|
|
3435
|
+
this.input = void 0;
|
|
3436
|
+
this._GetOsVersionCommand = deps.GetOsVersionCommand;
|
|
3437
|
+
this._isSuccessCommandResult = deps.isSuccessCommandResult;
|
|
3438
|
+
}
|
|
3439
|
+
_execute(internalApi) {
|
|
3440
|
+
const subject = new Subject();
|
|
3441
|
+
let cancelled = false;
|
|
3442
|
+
(async () => {
|
|
3443
|
+
try {
|
|
3444
|
+
subject.next({
|
|
3445
|
+
status: DeviceActionStatus2.Pending,
|
|
3446
|
+
intermediateValue: { requiredUserInteraction: "none" }
|
|
3447
|
+
});
|
|
3448
|
+
const osVersionResult = await internalApi.sendCommand(new this._GetOsVersionCommand());
|
|
3449
|
+
if (cancelled) return;
|
|
3450
|
+
if (!this._isSuccessCommandResult(osVersionResult)) {
|
|
3451
|
+
const errObj = osVersionResult?.error;
|
|
3452
|
+
throw new Error(errObj?.message ?? "GetOsVersionCommand failed");
|
|
3453
|
+
}
|
|
3454
|
+
const managerApi = internalApi.getManagerApiService();
|
|
3455
|
+
const either = await managerApi.getAppList(osVersionResult.data).run();
|
|
3456
|
+
if (cancelled) return;
|
|
3457
|
+
if (either.isLeft()) {
|
|
3458
|
+
const httpErr = either.extract();
|
|
3459
|
+
throw new Error(httpErr?.message ?? "Manager API getAppList failed");
|
|
3460
|
+
}
|
|
3461
|
+
const apps = either.extract();
|
|
3462
|
+
subject.next({ status: DeviceActionStatus2.Completed, output: apps });
|
|
3463
|
+
subject.complete();
|
|
3464
|
+
} catch (err) {
|
|
3465
|
+
if (cancelled) return;
|
|
3466
|
+
subject.next({ status: DeviceActionStatus2.Error, error: err });
|
|
3467
|
+
subject.complete();
|
|
3468
|
+
}
|
|
3469
|
+
})();
|
|
3470
|
+
return {
|
|
3471
|
+
observable: subject.asObservable(),
|
|
3472
|
+
cancel: () => {
|
|
3473
|
+
cancelled = true;
|
|
3474
|
+
subject.next({ status: DeviceActionStatus2.Stopped });
|
|
3475
|
+
subject.complete();
|
|
3476
|
+
}
|
|
3477
|
+
};
|
|
3478
|
+
}
|
|
3479
|
+
};
|
|
3480
|
+
|
|
3481
|
+
// src/device-apps/DeviceAppsManager.ts
|
|
3482
|
+
var DeviceAppsManager = class {
|
|
3483
|
+
constructor(dmk, importLedgerKit) {
|
|
3484
|
+
this._dmk = dmk;
|
|
3485
|
+
this._importLedgerKit = importLedgerKit;
|
|
3486
|
+
}
|
|
3487
|
+
async getOrCreate(sessionId) {
|
|
3488
|
+
const ledgerKit = await this._importLedgerKit(
|
|
3489
|
+
"@ledgerhq/device-management-kit"
|
|
3490
|
+
);
|
|
3491
|
+
return new DeviceApps(this._dmk, sessionId, ledgerKit);
|
|
3492
|
+
}
|
|
3493
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this
|
|
3494
|
+
invalidate(_sessionId) {
|
|
3495
|
+
}
|
|
3496
|
+
// eslint-disable-next-line class-methods-use-this
|
|
3497
|
+
clearAll() {
|
|
3498
|
+
}
|
|
3499
|
+
};
|
|
3500
|
+
|
|
2950
3501
|
// src/connector/LedgerConnectorBase.ts
|
|
2951
3502
|
var METHOD_PREFIX_TO_APP_NAME = {
|
|
2952
3503
|
evm: "Ethereum",
|
|
@@ -2955,7 +3506,7 @@ var METHOD_PREFIX_TO_APP_NAME = {
|
|
|
2955
3506
|
tron: "Tron"
|
|
2956
3507
|
};
|
|
2957
3508
|
var HARDWARE_ERROR_CODE_VALUES = new Set(
|
|
2958
|
-
Object.values(
|
|
3509
|
+
Object.values(HardwareErrorCode8).filter((value) => typeof value === "number")
|
|
2959
3510
|
);
|
|
2960
3511
|
var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
|
|
2961
3512
|
async function defaultLedgerKitImporter(pkg) {
|
|
@@ -2974,10 +3525,25 @@ async function defaultLedgerKitImporter(pkg) {
|
|
|
2974
3525
|
throw new Error(`Unknown Ledger kit package: ${pkg}`);
|
|
2975
3526
|
}
|
|
2976
3527
|
}
|
|
3528
|
+
async function _getDeviceApps(ctx, sessionId) {
|
|
3529
|
+
const manager = await ctx.getDeviceAppsManager();
|
|
3530
|
+
const apps = await manager.getOrCreate(sessionId);
|
|
3531
|
+
apps.onInteraction = (interaction) => {
|
|
3532
|
+
ctx.emit("ui-event", {
|
|
3533
|
+
type: collapseSignerInteraction(interaction),
|
|
3534
|
+
payload: { sessionId }
|
|
3535
|
+
});
|
|
3536
|
+
};
|
|
3537
|
+
apps.onRegisterCanceller = (cancel) => {
|
|
3538
|
+
ctx.registerCanceller(sessionId, cancel);
|
|
3539
|
+
};
|
|
3540
|
+
return apps;
|
|
3541
|
+
}
|
|
2977
3542
|
var LedgerConnectorBase = class {
|
|
2978
3543
|
constructor(createTransport, options) {
|
|
2979
3544
|
this._deviceManager = null;
|
|
2980
3545
|
this._signerManager = null;
|
|
3546
|
+
this._deviceAppsManager = null;
|
|
2981
3547
|
this._dmk = null;
|
|
2982
3548
|
this._eventHandlers = /* @__PURE__ */ new Map();
|
|
2983
3549
|
// ---------------------------------------------------------------------------
|
|
@@ -3016,6 +3582,7 @@ var LedgerConnectorBase = class {
|
|
|
3016
3582
|
getOrCreateDmk: () => this._getOrCreateDmk(),
|
|
3017
3583
|
getDeviceManager: () => this._getDeviceManager(),
|
|
3018
3584
|
getSignerManager: () => this._getSignerManager(),
|
|
3585
|
+
getDeviceAppsManager: () => this._getDeviceAppsManager(),
|
|
3019
3586
|
clearAllSigners: () => this._signerManager?.clearAll(),
|
|
3020
3587
|
replaceSession: (oldSid, newSid) => this._replaceSession(oldSid, newSid),
|
|
3021
3588
|
registerCanceller: (sid, cancel) => this._cancellers.set(sid, cancel),
|
|
@@ -3050,12 +3617,22 @@ var LedgerConnectorBase = class {
|
|
|
3050
3617
|
}
|
|
3051
3618
|
return descriptors;
|
|
3052
3619
|
}
|
|
3620
|
+
_assertSingleUsbDescriptor(descriptors) {
|
|
3621
|
+
if (isLedgerBleConnectionType(this.connectionType) || descriptors.length <= 1) {
|
|
3622
|
+
return;
|
|
3623
|
+
}
|
|
3624
|
+
debugLog(
|
|
3625
|
+
`[DMK] Multiple Ledger USB devices found (${descriptors.length}); refusing to choose by ephemeral path. paths=[${descriptors.map((d) => d.path).join(",")}]`
|
|
3626
|
+
);
|
|
3627
|
+
throw createMultipleUsbLedgerDevicesError();
|
|
3628
|
+
}
|
|
3053
3629
|
// ---------------------------------------------------------------------------
|
|
3054
3630
|
// IConnector -- Device discovery
|
|
3055
3631
|
// ---------------------------------------------------------------------------
|
|
3056
3632
|
async searchDevices() {
|
|
3057
3633
|
const dm = await this._getDeviceManager();
|
|
3058
3634
|
const descriptors = await this._discoverDescriptors(dm);
|
|
3635
|
+
this._assertSingleUsbDescriptor(descriptors);
|
|
3059
3636
|
const resolvedDescriptors = descriptors.map((d) => ({
|
|
3060
3637
|
descriptor: d,
|
|
3061
3638
|
connectId: this._resolveConnectId(d)
|
|
@@ -3081,6 +3658,10 @@ var LedgerConnectorBase = class {
|
|
|
3081
3658
|
async connect(deviceId) {
|
|
3082
3659
|
const callerSuppliedConnectId = Boolean(deviceId);
|
|
3083
3660
|
let targetPath = deviceId;
|
|
3661
|
+
if (callerSuppliedConnectId && !isLedgerBleConnectionType(this.connectionType)) {
|
|
3662
|
+
const dm = await this._getDeviceManager();
|
|
3663
|
+
this._assertSingleUsbDescriptor(await this._discoverDescriptors(dm));
|
|
3664
|
+
}
|
|
3084
3665
|
if (!targetPath) {
|
|
3085
3666
|
const discovered = await this.searchDevices();
|
|
3086
3667
|
if (discovered.length === 0) {
|
|
@@ -3104,7 +3685,7 @@ var LedgerConnectorBase = class {
|
|
|
3104
3685
|
`Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
|
|
3105
3686
|
);
|
|
3106
3687
|
err._tag = ERROR_TAG.BlePairingTimeout;
|
|
3107
|
-
err.code =
|
|
3688
|
+
err.code = HardwareErrorCode8.BlePairingTimeout;
|
|
3108
3689
|
reject(err);
|
|
3109
3690
|
}, HANG_CEILING_MS);
|
|
3110
3691
|
});
|
|
@@ -3137,7 +3718,7 @@ var LedgerConnectorBase = class {
|
|
|
3137
3718
|
"Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
|
|
3138
3719
|
);
|
|
3139
3720
|
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
3140
|
-
err.code =
|
|
3721
|
+
err.code = HardwareErrorCode8.DeviceNotFound;
|
|
3141
3722
|
throw err;
|
|
3142
3723
|
};
|
|
3143
3724
|
const doConnect = async (path) => {
|
|
@@ -3157,7 +3738,19 @@ var LedgerConnectorBase = class {
|
|
|
3157
3738
|
}
|
|
3158
3739
|
throw err;
|
|
3159
3740
|
}
|
|
3160
|
-
|
|
3741
|
+
try {
|
|
3742
|
+
this._watchSessionState(sessionId, externalConnectId);
|
|
3743
|
+
} catch (subErr) {
|
|
3744
|
+
debugLog(
|
|
3745
|
+
"[DMK] state subscription failed during connect; disconnecting session:",
|
|
3746
|
+
subErr
|
|
3747
|
+
);
|
|
3748
|
+
try {
|
|
3749
|
+
await dm.disconnect(sessionId);
|
|
3750
|
+
} catch {
|
|
3751
|
+
}
|
|
3752
|
+
throw subErr;
|
|
3753
|
+
}
|
|
3161
3754
|
const info = dm.getDiscoveredDeviceInfo(path);
|
|
3162
3755
|
const session = {
|
|
3163
3756
|
sessionId,
|
|
@@ -3174,6 +3767,18 @@ var LedgerConnectorBase = class {
|
|
|
3174
3767
|
}
|
|
3175
3768
|
};
|
|
3176
3769
|
const name = dm.getDeviceName(path) ?? "Ledger";
|
|
3770
|
+
debugLog(
|
|
3771
|
+
"[SESS-DBG] connector.connect SUCCESS dmPath=",
|
|
3772
|
+
path,
|
|
3773
|
+
"externalConnectId=",
|
|
3774
|
+
externalConnectId,
|
|
3775
|
+
"newSessionId=",
|
|
3776
|
+
sessionId,
|
|
3777
|
+
"name=",
|
|
3778
|
+
name,
|
|
3779
|
+
"model=",
|
|
3780
|
+
info?.model
|
|
3781
|
+
);
|
|
3177
3782
|
this._emit("device-connect", {
|
|
3178
3783
|
device: { connectId: externalConnectId, deviceId: path, name }
|
|
3179
3784
|
});
|
|
@@ -3192,7 +3797,7 @@ var LedgerConnectorBase = class {
|
|
|
3192
3797
|
"Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
|
|
3193
3798
|
);
|
|
3194
3799
|
wrapped._tag = ERROR_TAG.BleGattBondingFailed;
|
|
3195
|
-
wrapped.code =
|
|
3800
|
+
wrapped.code = HardwareErrorCode8.BlePairingTimeout;
|
|
3196
3801
|
wrapped.originalError = err;
|
|
3197
3802
|
throw wrapped;
|
|
3198
3803
|
}
|
|
@@ -3236,24 +3841,48 @@ var LedgerConnectorBase = class {
|
|
|
3236
3841
|
} catch {
|
|
3237
3842
|
}
|
|
3238
3843
|
}
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3844
|
+
debugLog(
|
|
3845
|
+
"[SESS-DBG] _watchSessionState SUBSCRIBE sessionId=",
|
|
3846
|
+
sessionId,
|
|
3847
|
+
"connectId=",
|
|
3848
|
+
externalConnectId
|
|
3849
|
+
);
|
|
3850
|
+
const sub = dmk.getDeviceSessionState({ sessionId }).subscribe({
|
|
3851
|
+
next: (state) => {
|
|
3852
|
+
debugLog(
|
|
3853
|
+
"[SESS-DBG] _watchSessionState NEXT sessionId=",
|
|
3854
|
+
sessionId,
|
|
3855
|
+
"connectId=",
|
|
3856
|
+
externalConnectId,
|
|
3857
|
+
"deviceStatus=",
|
|
3858
|
+
state?.deviceStatus
|
|
3859
|
+
);
|
|
3860
|
+
if (state?.deviceStatus === "NOT CONNECTED") {
|
|
3250
3861
|
this._handleAutonomousDisconnect(sessionId, externalConnectId);
|
|
3251
3862
|
}
|
|
3252
|
-
}
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3863
|
+
},
|
|
3864
|
+
error: (err) => {
|
|
3865
|
+
debugLog(
|
|
3866
|
+
"[SESS-DBG] _watchSessionState ERROR sessionId=",
|
|
3867
|
+
sessionId,
|
|
3868
|
+
"connectId=",
|
|
3869
|
+
externalConnectId,
|
|
3870
|
+
"err=",
|
|
3871
|
+
err?.message
|
|
3872
|
+
);
|
|
3873
|
+
this._handleAutonomousDisconnect(sessionId, externalConnectId);
|
|
3874
|
+
},
|
|
3875
|
+
complete: () => {
|
|
3876
|
+
debugLog(
|
|
3877
|
+
"[SESS-DBG] _watchSessionState COMPLETE sessionId=",
|
|
3878
|
+
sessionId,
|
|
3879
|
+
"connectId=",
|
|
3880
|
+
externalConnectId
|
|
3881
|
+
);
|
|
3882
|
+
this._handleAutonomousDisconnect(sessionId, externalConnectId);
|
|
3883
|
+
}
|
|
3884
|
+
});
|
|
3885
|
+
this._sessionStateSubs.set(sessionId, sub);
|
|
3257
3886
|
}
|
|
3258
3887
|
_unwatchSessionState(sessionId) {
|
|
3259
3888
|
const sub = this._sessionStateSubs.get(sessionId);
|
|
@@ -3265,7 +3894,21 @@ var LedgerConnectorBase = class {
|
|
|
3265
3894
|
this._sessionStateSubs.delete(sessionId);
|
|
3266
3895
|
}
|
|
3267
3896
|
_handleAutonomousDisconnect(sessionId, externalConnectId) {
|
|
3268
|
-
if (!this._sessionStateSubs.has(sessionId))
|
|
3897
|
+
if (!this._sessionStateSubs.has(sessionId)) {
|
|
3898
|
+
debugLog(
|
|
3899
|
+
"[SESS-DBG] _handleAutonomousDisconnect SKIP (already handled) sessionId=",
|
|
3900
|
+
sessionId,
|
|
3901
|
+
"connectId=",
|
|
3902
|
+
externalConnectId
|
|
3903
|
+
);
|
|
3904
|
+
return;
|
|
3905
|
+
}
|
|
3906
|
+
debugLog(
|
|
3907
|
+
"[SESS-DBG] _handleAutonomousDisconnect FIRE sessionId=",
|
|
3908
|
+
sessionId,
|
|
3909
|
+
"connectId=",
|
|
3910
|
+
externalConnectId
|
|
3911
|
+
);
|
|
3269
3912
|
debugLog(
|
|
3270
3913
|
"[DMK] autonomous disconnect detected \u2014 sessionId:",
|
|
3271
3914
|
sessionId,
|
|
@@ -3275,7 +3918,7 @@ var LedgerConnectorBase = class {
|
|
|
3275
3918
|
this._unwatchSessionState(sessionId);
|
|
3276
3919
|
this._signerManager?.invalidate(sessionId);
|
|
3277
3920
|
this._cancellers.get(sessionId)?.({
|
|
3278
|
-
code:
|
|
3921
|
+
code: HardwareErrorCode8.DeviceDisconnected,
|
|
3279
3922
|
tag: "DeviceDisconnected",
|
|
3280
3923
|
message: "Device disconnected"
|
|
3281
3924
|
});
|
|
@@ -3292,14 +3935,14 @@ var LedgerConnectorBase = class {
|
|
|
3292
3935
|
} catch (err) {
|
|
3293
3936
|
if (isAppStuckByApdu(err)) {
|
|
3294
3937
|
throw Object.assign(new Error("Ledger app is unresponsive"), {
|
|
3295
|
-
code:
|
|
3938
|
+
code: HardwareErrorCode8.DeviceAppStuck,
|
|
3296
3939
|
_tag: ERROR_TAG.DeviceAppStuck,
|
|
3297
3940
|
originalError: err
|
|
3298
3941
|
});
|
|
3299
3942
|
}
|
|
3300
3943
|
if (isTransportStuck(err)) {
|
|
3301
3944
|
throw Object.assign(new Error("Device communication interrupted, please retry"), {
|
|
3302
|
-
code:
|
|
3945
|
+
code: HardwareErrorCode8.TransportError,
|
|
3303
3946
|
_tag: ERROR_TAG.DeviceTransportStuck,
|
|
3304
3947
|
originalError: err
|
|
3305
3948
|
});
|
|
@@ -3356,6 +3999,49 @@ var LedgerConnectorBase = class {
|
|
|
3356
3999
|
};
|
|
3357
4000
|
return tronSignMessage(ctx, sessionId, internalParams);
|
|
3358
4001
|
}
|
|
4002
|
+
// OS-level device management — symmetric to chain handlers.
|
|
4003
|
+
// _getDeviceApps wires onInteraction/onRegisterCanceller like _getEthSigner.
|
|
4004
|
+
case "installApp": {
|
|
4005
|
+
const p = params;
|
|
4006
|
+
const apps = await _getDeviceApps(ctx, sessionId);
|
|
4007
|
+
try {
|
|
4008
|
+
return await apps.install(p.appName, p.onProgress);
|
|
4009
|
+
} finally {
|
|
4010
|
+
ctx.clearCanceller(sessionId);
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
case "listInstalledApps": {
|
|
4014
|
+
const apps = await _getDeviceApps(ctx, sessionId);
|
|
4015
|
+
try {
|
|
4016
|
+
return await apps.listInstalled(params);
|
|
4017
|
+
} finally {
|
|
4018
|
+
ctx.clearCanceller(sessionId);
|
|
4019
|
+
}
|
|
4020
|
+
}
|
|
4021
|
+
case "listAvailableApps": {
|
|
4022
|
+
const apps = await _getDeviceApps(ctx, sessionId);
|
|
4023
|
+
try {
|
|
4024
|
+
return await apps.listAvailable();
|
|
4025
|
+
} finally {
|
|
4026
|
+
ctx.clearCanceller(sessionId);
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
case "getFirmwareVersion": {
|
|
4030
|
+
const apps = await _getDeviceApps(ctx, sessionId);
|
|
4031
|
+
try {
|
|
4032
|
+
return await apps.getFirmwareVersion();
|
|
4033
|
+
} finally {
|
|
4034
|
+
ctx.clearCanceller(sessionId);
|
|
4035
|
+
}
|
|
4036
|
+
}
|
|
4037
|
+
case "getDeviceInfo": {
|
|
4038
|
+
const apps = await _getDeviceApps(ctx, sessionId);
|
|
4039
|
+
try {
|
|
4040
|
+
return await apps.getDeviceInfo();
|
|
4041
|
+
} finally {
|
|
4042
|
+
ctx.clearCanceller(sessionId);
|
|
4043
|
+
}
|
|
4044
|
+
}
|
|
3359
4045
|
default:
|
|
3360
4046
|
throw new Error(`LedgerConnector: unknown method "${method}"`);
|
|
3361
4047
|
}
|
|
@@ -3428,6 +4114,7 @@ var LedgerConnectorBase = class {
|
|
|
3428
4114
|
const mod = await importKit("@ledgerhq/device-signer-kit-ethereum");
|
|
3429
4115
|
return new mod.SignerEthBuilder(args);
|
|
3430
4116
|
});
|
|
4117
|
+
this._deviceAppsManager = new DeviceAppsManager(dmk, importKit);
|
|
3431
4118
|
}
|
|
3432
4119
|
async _getDeviceManager() {
|
|
3433
4120
|
if (this._deviceManager) return this._deviceManager;
|
|
@@ -3442,6 +4129,13 @@ var LedgerConnectorBase = class {
|
|
|
3442
4129
|
}
|
|
3443
4130
|
return this._signerManager;
|
|
3444
4131
|
}
|
|
4132
|
+
async _getDeviceAppsManager() {
|
|
4133
|
+
if (!this._deviceAppsManager) {
|
|
4134
|
+
const dmk = await this._getOrCreateDmk();
|
|
4135
|
+
this._initManagers(dmk);
|
|
4136
|
+
}
|
|
4137
|
+
return this._deviceAppsManager;
|
|
4138
|
+
}
|
|
3445
4139
|
_invalidateSession(sessionId) {
|
|
3446
4140
|
this._signerManager?.invalidate(sessionId);
|
|
3447
4141
|
}
|
|
@@ -3477,6 +4171,8 @@ var LedgerConnectorBase = class {
|
|
|
3477
4171
|
debugLog("[DMK] _resetSignersAndSessions called");
|
|
3478
4172
|
this._signerManager?.clearAll();
|
|
3479
4173
|
this._signerManager = null;
|
|
4174
|
+
this._deviceAppsManager?.clearAll();
|
|
4175
|
+
this._deviceAppsManager = null;
|
|
3480
4176
|
this._deviceManager?.disposeKeepingDmk();
|
|
3481
4177
|
this._deviceManager = null;
|
|
3482
4178
|
}
|
|
@@ -3497,9 +4193,11 @@ var LedgerConnectorBase = class {
|
|
|
3497
4193
|
}
|
|
3498
4194
|
this._sessionStateSubs.clear();
|
|
3499
4195
|
this._signerManager?.clearAll();
|
|
4196
|
+
this._deviceAppsManager?.clearAll();
|
|
3500
4197
|
this._deviceManager?.dispose();
|
|
3501
4198
|
this._deviceManager = null;
|
|
3502
4199
|
this._signerManager = null;
|
|
4200
|
+
this._deviceAppsManager = null;
|
|
3503
4201
|
this._dmk = null;
|
|
3504
4202
|
}
|
|
3505
4203
|
// ---------------------------------------------------------------------------
|