@onekeyfe/hwk-ledger-adapter 1.1.26-alpha.20 → 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 +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +156 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +156 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -306,6 +306,15 @@ function isAppNotInstalledError(err) {
|
|
|
306
306
|
if (hasStatusCode(err, APP_NOT_INSTALLED_CODES)) return true;
|
|
307
307
|
return false;
|
|
308
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
|
+
}
|
|
309
318
|
function isDeviceDisconnectedError(err) {
|
|
310
319
|
if (!err || typeof err !== "object") return false;
|
|
311
320
|
const e = err;
|
|
@@ -368,6 +377,8 @@ function mapLedgerError(err, opts) {
|
|
|
368
377
|
code = HardwareErrorCode.WrongApp;
|
|
369
378
|
} else if (isAppNotInstalledError(err)) {
|
|
370
379
|
code = HardwareErrorCode.AppNotInstalled;
|
|
380
|
+
} else if (isOutOfMemoryError(err)) {
|
|
381
|
+
code = HardwareErrorCode.DeviceOutOfMemory;
|
|
371
382
|
} else if (isDeviceDisconnectedError(err)) {
|
|
372
383
|
code = HardwareErrorCode.DeviceDisconnected;
|
|
373
384
|
} else if (isTimeoutError(err)) {
|
|
@@ -625,7 +636,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
625
636
|
);
|
|
626
637
|
return Array.from(this._discoveredDevices.values());
|
|
627
638
|
}
|
|
628
|
-
/** Compact snapshot helpers for diagnostic logs. */
|
|
629
639
|
_snapshotSessions() {
|
|
630
640
|
return [...this._sessions.entries()].map(([connectId, sessionId]) => ({
|
|
631
641
|
connectId,
|
|
@@ -640,6 +650,30 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
640
650
|
serial: info.serialNumber
|
|
641
651
|
}));
|
|
642
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
|
+
}
|
|
643
677
|
static _createDeviceBusyError(method) {
|
|
644
678
|
return Object.assign(new Error(`Ledger device is busy while calling ${method}`), {
|
|
645
679
|
code: HardwareErrorCode2.DeviceBusy
|
|
@@ -660,6 +694,9 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
660
694
|
code: HardwareErrorCode2.DeviceNotFound
|
|
661
695
|
});
|
|
662
696
|
}
|
|
697
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
698
|
+
await this._evictAllSessions("connectDevice");
|
|
699
|
+
}
|
|
663
700
|
await this._ensureDevicePermission(connectId);
|
|
664
701
|
const session = await this.connector.connect(connectId);
|
|
665
702
|
const prev = this._sessions.get(connectId);
|
|
@@ -1081,13 +1118,24 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1081
1118
|
return connectId;
|
|
1082
1119
|
}
|
|
1083
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
|
+
}
|
|
1084
1133
|
const ambient = this._sessions.keys().next().value;
|
|
1085
1134
|
debugLog(
|
|
1086
1135
|
"[SESS-DBG] ensureConnected RESOLVED path=ambient-fallback chosenConnectId=",
|
|
1087
1136
|
ambient,
|
|
1088
1137
|
"sessionId=",
|
|
1089
|
-
this._sessions.get(ambient)
|
|
1090
|
-
"WARNING: caller passed empty connectId, routing to first session entry"
|
|
1138
|
+
this._sessions.get(ambient)
|
|
1091
1139
|
);
|
|
1092
1140
|
return ambient;
|
|
1093
1141
|
}
|
|
@@ -1651,7 +1699,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1651
1699
|
const tag = err && typeof err === "object" ? err._tag : void 0;
|
|
1652
1700
|
if (err && typeof err === "object" && "code" in err && typeof err.code === "number") {
|
|
1653
1701
|
const e = err;
|
|
1654
|
-
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;
|
|
1655
1703
|
return ledgerFailure(e.code, e.message ?? "Unknown error", e.appName, tag, params);
|
|
1656
1704
|
}
|
|
1657
1705
|
const mapped = mapLedgerError(err);
|
|
@@ -1701,7 +1749,7 @@ _LedgerAdapter.MAX_DOCONNECT_CONFIRMS = 3;
|
|
|
1701
1749
|
var LedgerAdapter = _LedgerAdapter;
|
|
1702
1750
|
|
|
1703
1751
|
// src/connector/LedgerConnectorBase.ts
|
|
1704
|
-
import { HardwareErrorCode as
|
|
1752
|
+
import { HardwareErrorCode as HardwareErrorCode8 } from "@onekeyfe/hwk-adapter-core";
|
|
1705
1753
|
|
|
1706
1754
|
// src/device/LedgerDeviceManager.ts
|
|
1707
1755
|
var LedgerDeviceManager = class {
|
|
@@ -3122,6 +3170,7 @@ async function _createTrx(ctx, sessionId) {
|
|
|
3122
3170
|
|
|
3123
3171
|
// src/device-apps/DeviceApps.ts
|
|
3124
3172
|
import { DeviceActionStatus as DeviceActionStatus2 } from "@ledgerhq/device-management-kit";
|
|
3173
|
+
import { HardwareErrorCode as HardwareErrorCode7 } from "@onekeyfe/hwk-adapter-core";
|
|
3125
3174
|
import { Subject } from "rxjs";
|
|
3126
3175
|
var INSTALL_TIMEOUT_MS = 5 * 6e4;
|
|
3127
3176
|
var DeviceApps = class {
|
|
@@ -3187,6 +3236,72 @@ var DeviceApps = class {
|
|
|
3187
3236
|
hwVersion: v.hwVersion
|
|
3188
3237
|
};
|
|
3189
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
|
+
}
|
|
3190
3305
|
// Sole sendCommand wrapper — surfaces unlock-device interaction through
|
|
3191
3306
|
// the same onInteraction pipeline as the device-action methods.
|
|
3192
3307
|
async _fetchOsVersion() {
|
|
@@ -3208,6 +3323,7 @@ var DeviceApps = class {
|
|
|
3208
3323
|
async install(appName, onProgress, options) {
|
|
3209
3324
|
if (!appName) throw new Error("DeviceApps.install: appName is required");
|
|
3210
3325
|
debugLog("[DeviceApps] install:", appName);
|
|
3326
|
+
await this._assertEnoughSpace(appName);
|
|
3211
3327
|
const action = this._dmk.executeDeviceAction({
|
|
3212
3328
|
sessionId: this._sessionId,
|
|
3213
3329
|
deviceAction: new this._ledgerKit.InstallAppDeviceAction({
|
|
@@ -3248,6 +3364,34 @@ function applicationToMetadata(app) {
|
|
|
3248
3364
|
isDevTools: app.isDevTools
|
|
3249
3365
|
};
|
|
3250
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
|
+
}
|
|
3251
3395
|
var GetOsVersionDeviceAction = class {
|
|
3252
3396
|
constructor(_deps) {
|
|
3253
3397
|
this._deps = _deps;
|
|
@@ -3362,7 +3506,7 @@ var METHOD_PREFIX_TO_APP_NAME = {
|
|
|
3362
3506
|
tron: "Tron"
|
|
3363
3507
|
};
|
|
3364
3508
|
var HARDWARE_ERROR_CODE_VALUES = new Set(
|
|
3365
|
-
Object.values(
|
|
3509
|
+
Object.values(HardwareErrorCode8).filter((value) => typeof value === "number")
|
|
3366
3510
|
);
|
|
3367
3511
|
var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
|
|
3368
3512
|
async function defaultLedgerKitImporter(pkg) {
|
|
@@ -3541,7 +3685,7 @@ var LedgerConnectorBase = class {
|
|
|
3541
3685
|
`Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
|
|
3542
3686
|
);
|
|
3543
3687
|
err._tag = ERROR_TAG.BlePairingTimeout;
|
|
3544
|
-
err.code =
|
|
3688
|
+
err.code = HardwareErrorCode8.BlePairingTimeout;
|
|
3545
3689
|
reject(err);
|
|
3546
3690
|
}, HANG_CEILING_MS);
|
|
3547
3691
|
});
|
|
@@ -3574,7 +3718,7 @@ var LedgerConnectorBase = class {
|
|
|
3574
3718
|
"Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
|
|
3575
3719
|
);
|
|
3576
3720
|
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
3577
|
-
err.code =
|
|
3721
|
+
err.code = HardwareErrorCode8.DeviceNotFound;
|
|
3578
3722
|
throw err;
|
|
3579
3723
|
};
|
|
3580
3724
|
const doConnect = async (path) => {
|
|
@@ -3653,7 +3797,7 @@ var LedgerConnectorBase = class {
|
|
|
3653
3797
|
"Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
|
|
3654
3798
|
);
|
|
3655
3799
|
wrapped._tag = ERROR_TAG.BleGattBondingFailed;
|
|
3656
|
-
wrapped.code =
|
|
3800
|
+
wrapped.code = HardwareErrorCode8.BlePairingTimeout;
|
|
3657
3801
|
wrapped.originalError = err;
|
|
3658
3802
|
throw wrapped;
|
|
3659
3803
|
}
|
|
@@ -3774,7 +3918,7 @@ var LedgerConnectorBase = class {
|
|
|
3774
3918
|
this._unwatchSessionState(sessionId);
|
|
3775
3919
|
this._signerManager?.invalidate(sessionId);
|
|
3776
3920
|
this._cancellers.get(sessionId)?.({
|
|
3777
|
-
code:
|
|
3921
|
+
code: HardwareErrorCode8.DeviceDisconnected,
|
|
3778
3922
|
tag: "DeviceDisconnected",
|
|
3779
3923
|
message: "Device disconnected"
|
|
3780
3924
|
});
|
|
@@ -3791,14 +3935,14 @@ var LedgerConnectorBase = class {
|
|
|
3791
3935
|
} catch (err) {
|
|
3792
3936
|
if (isAppStuckByApdu(err)) {
|
|
3793
3937
|
throw Object.assign(new Error("Ledger app is unresponsive"), {
|
|
3794
|
-
code:
|
|
3938
|
+
code: HardwareErrorCode8.DeviceAppStuck,
|
|
3795
3939
|
_tag: ERROR_TAG.DeviceAppStuck,
|
|
3796
3940
|
originalError: err
|
|
3797
3941
|
});
|
|
3798
3942
|
}
|
|
3799
3943
|
if (isTransportStuck(err)) {
|
|
3800
3944
|
throw Object.assign(new Error("Device communication interrupted, please retry"), {
|
|
3801
|
-
code:
|
|
3945
|
+
code: HardwareErrorCode8.TransportError,
|
|
3802
3946
|
_tag: ERROR_TAG.DeviceTransportStuck,
|
|
3803
3947
|
originalError: err
|
|
3804
3948
|
});
|