@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.d.mts
CHANGED
|
@@ -114,9 +114,9 @@ declare class LedgerAdapter implements IHardwareWallet {
|
|
|
114
114
|
dispose(): Promise<void>;
|
|
115
115
|
uiResponse(response: UiResponseEvent): void;
|
|
116
116
|
searchDevices(options?: SearchDevicesOptions): Promise<DeviceInfo[]>;
|
|
117
|
-
/** Compact snapshot helpers for diagnostic logs. */
|
|
118
117
|
private _snapshotSessions;
|
|
119
118
|
private _snapshotDiscovered;
|
|
119
|
+
private _evictAllSessions;
|
|
120
120
|
private static readonly MAX_BUSINESS_RETRY_BUDGET;
|
|
121
121
|
private static readonly STUCK_APP_RETRY_DELAY_MS;
|
|
122
122
|
private static readonly MAX_DOCONNECT_CONFIRMS;
|
package/dist/index.d.ts
CHANGED
|
@@ -114,9 +114,9 @@ declare class LedgerAdapter implements IHardwareWallet {
|
|
|
114
114
|
dispose(): Promise<void>;
|
|
115
115
|
uiResponse(response: UiResponseEvent): void;
|
|
116
116
|
searchDevices(options?: SearchDevicesOptions): Promise<DeviceInfo[]>;
|
|
117
|
-
/** Compact snapshot helpers for diagnostic logs. */
|
|
118
117
|
private _snapshotSessions;
|
|
119
118
|
private _snapshotDiscovered;
|
|
119
|
+
private _evictAllSessions;
|
|
120
120
|
private static readonly MAX_BUSINESS_RETRY_BUDGET;
|
|
121
121
|
private static readonly STUCK_APP_RETRY_DELAY_MS;
|
|
122
122
|
private static readonly MAX_DOCONNECT_CONFIRMS;
|
package/dist/index.js
CHANGED
|
@@ -347,6 +347,15 @@ function isAppNotInstalledError(err) {
|
|
|
347
347
|
if (hasStatusCode(err, APP_NOT_INSTALLED_CODES)) return true;
|
|
348
348
|
return false;
|
|
349
349
|
}
|
|
350
|
+
function isOutOfMemoryError(err) {
|
|
351
|
+
if (!err || typeof err !== "object") return false;
|
|
352
|
+
const e = err;
|
|
353
|
+
if (e._tag === "OutOfMemoryDAError") return true;
|
|
354
|
+
if (typeof e.message === "string" && /out of memory|not enough.*space|insufficient.*memory/i.test(e.message)) {
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
350
359
|
function isDeviceDisconnectedError(err) {
|
|
351
360
|
if (!err || typeof err !== "object") return false;
|
|
352
361
|
const e = err;
|
|
@@ -409,6 +418,8 @@ function mapLedgerError(err, opts) {
|
|
|
409
418
|
code = import_hwk_adapter_core.HardwareErrorCode.WrongApp;
|
|
410
419
|
} else if (isAppNotInstalledError(err)) {
|
|
411
420
|
code = import_hwk_adapter_core.HardwareErrorCode.AppNotInstalled;
|
|
421
|
+
} else if (isOutOfMemoryError(err)) {
|
|
422
|
+
code = import_hwk_adapter_core.HardwareErrorCode.DeviceOutOfMemory;
|
|
412
423
|
} else if (isDeviceDisconnectedError(err)) {
|
|
413
424
|
code = import_hwk_adapter_core.HardwareErrorCode.DeviceDisconnected;
|
|
414
425
|
} else if (isTimeoutError(err)) {
|
|
@@ -666,7 +677,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
666
677
|
);
|
|
667
678
|
return Array.from(this._discoveredDevices.values());
|
|
668
679
|
}
|
|
669
|
-
/** Compact snapshot helpers for diagnostic logs. */
|
|
670
680
|
_snapshotSessions() {
|
|
671
681
|
return [...this._sessions.entries()].map(([connectId, sessionId]) => ({
|
|
672
682
|
connectId,
|
|
@@ -681,6 +691,30 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
681
691
|
serial: info.serialNumber
|
|
682
692
|
}));
|
|
683
693
|
}
|
|
694
|
+
// Enforce USB single-session invariant — see connectDevice.
|
|
695
|
+
async _evictAllSessions(reason) {
|
|
696
|
+
if (this._sessions.size === 0) return;
|
|
697
|
+
const stale = [...this._sessions.entries()];
|
|
698
|
+
debugLog(
|
|
699
|
+
"[SESS-DBG] evictAllSessions reason=",
|
|
700
|
+
reason,
|
|
701
|
+
"evicting=",
|
|
702
|
+
stale.map(([cid, sid]) => ({ connectId: cid, sessionId: sid }))
|
|
703
|
+
);
|
|
704
|
+
this._sessions.clear();
|
|
705
|
+
for (const [, sid] of stale) {
|
|
706
|
+
try {
|
|
707
|
+
await this.connector.disconnect(sid);
|
|
708
|
+
} catch (err) {
|
|
709
|
+
debugLog(
|
|
710
|
+
"[SESS-DBG] evictAllSessions disconnect failed sessionId=",
|
|
711
|
+
sid,
|
|
712
|
+
"err=",
|
|
713
|
+
err?.message
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
684
718
|
static _createDeviceBusyError(method) {
|
|
685
719
|
return Object.assign(new Error(`Ledger device is busy while calling ${method}`), {
|
|
686
720
|
code: import_hwk_adapter_core2.HardwareErrorCode.DeviceBusy
|
|
@@ -701,6 +735,9 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
701
735
|
code: import_hwk_adapter_core2.HardwareErrorCode.DeviceNotFound
|
|
702
736
|
});
|
|
703
737
|
}
|
|
738
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
739
|
+
await this._evictAllSessions("connectDevice");
|
|
740
|
+
}
|
|
704
741
|
await this._ensureDevicePermission(connectId);
|
|
705
742
|
const session = await this.connector.connect(connectId);
|
|
706
743
|
const prev = this._sessions.get(connectId);
|
|
@@ -1122,13 +1159,24 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1122
1159
|
return connectId;
|
|
1123
1160
|
}
|
|
1124
1161
|
if (!connectId && this._sessions.size > 0) {
|
|
1162
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType) && this._sessions.size > 1) {
|
|
1163
|
+
debugLog(
|
|
1164
|
+
"[SESS-DBG] ensureConnected ABORT multiple USB sessions present sessions=",
|
|
1165
|
+
this._snapshotSessions()
|
|
1166
|
+
);
|
|
1167
|
+
throw Object.assign(
|
|
1168
|
+
new Error(
|
|
1169
|
+
"Ledger USB session invariant violated: more than one session is active. Please reconnect the device."
|
|
1170
|
+
),
|
|
1171
|
+
{ code: import_hwk_adapter_core2.HardwareErrorCode.DeviceOneDeviceOnly }
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1125
1174
|
const ambient = this._sessions.keys().next().value;
|
|
1126
1175
|
debugLog(
|
|
1127
1176
|
"[SESS-DBG] ensureConnected RESOLVED path=ambient-fallback chosenConnectId=",
|
|
1128
1177
|
ambient,
|
|
1129
1178
|
"sessionId=",
|
|
1130
|
-
this._sessions.get(ambient)
|
|
1131
|
-
"WARNING: caller passed empty connectId, routing to first session entry"
|
|
1179
|
+
this._sessions.get(ambient)
|
|
1132
1180
|
);
|
|
1133
1181
|
return ambient;
|
|
1134
1182
|
}
|
|
@@ -1692,7 +1740,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1692
1740
|
const tag = err && typeof err === "object" ? err._tag : void 0;
|
|
1693
1741
|
if (err && typeof err === "object" && "code" in err && typeof err.code === "number") {
|
|
1694
1742
|
const e = err;
|
|
1695
|
-
const params = e.code === import_hwk_adapter_core2.HardwareErrorCode.DevicePermissionDenied && e.reason ? { permissionDeniedReason: e.reason } :
|
|
1743
|
+
const params = e.code === import_hwk_adapter_core2.HardwareErrorCode.DevicePermissionDenied && e.reason ? { permissionDeniedReason: e.reason } : e.params;
|
|
1696
1744
|
return ledgerFailure(e.code, e.message ?? "Unknown error", e.appName, tag, params);
|
|
1697
1745
|
}
|
|
1698
1746
|
const mapped = mapLedgerError(err);
|
|
@@ -1742,7 +1790,7 @@ _LedgerAdapter.MAX_DOCONNECT_CONFIRMS = 3;
|
|
|
1742
1790
|
var LedgerAdapter = _LedgerAdapter;
|
|
1743
1791
|
|
|
1744
1792
|
// src/connector/LedgerConnectorBase.ts
|
|
1745
|
-
var
|
|
1793
|
+
var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
|
|
1746
1794
|
|
|
1747
1795
|
// src/device/LedgerDeviceManager.ts
|
|
1748
1796
|
var LedgerDeviceManager = class {
|
|
@@ -3158,6 +3206,7 @@ async function _createTrx(ctx, sessionId) {
|
|
|
3158
3206
|
|
|
3159
3207
|
// src/device-apps/DeviceApps.ts
|
|
3160
3208
|
var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
|
|
3209
|
+
var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
|
|
3161
3210
|
var import_rxjs = require("rxjs");
|
|
3162
3211
|
var INSTALL_TIMEOUT_MS = 5 * 6e4;
|
|
3163
3212
|
var DeviceApps = class {
|
|
@@ -3223,6 +3272,72 @@ var DeviceApps = class {
|
|
|
3223
3272
|
hwVersion: v.hwVersion
|
|
3224
3273
|
};
|
|
3225
3274
|
}
|
|
3275
|
+
/**
|
|
3276
|
+
* Pre-flight space check. Mirrors DMK's PredictOutOfMemoryTask using the
|
|
3277
|
+
* data we already expose (listInstalled / listAvailable / getOsVersion).
|
|
3278
|
+
* Fails fast with HardwareErrorCode.DeviceOutOfMemory before issuing the
|
|
3279
|
+
* actual install — saves the user the time-to-fail of DMK's state machine.
|
|
3280
|
+
*/
|
|
3281
|
+
async _assertEnoughSpace(appName) {
|
|
3282
|
+
let osVersion;
|
|
3283
|
+
let installed;
|
|
3284
|
+
let available;
|
|
3285
|
+
try {
|
|
3286
|
+
[osVersion, installed, available] = await Promise.all([
|
|
3287
|
+
this._fetchOsVersion(),
|
|
3288
|
+
this.listInstalled(),
|
|
3289
|
+
this.listAvailable()
|
|
3290
|
+
]);
|
|
3291
|
+
} catch (err) {
|
|
3292
|
+
debugLog("[DeviceApps] precheck skipped:", err?.message);
|
|
3293
|
+
return;
|
|
3294
|
+
}
|
|
3295
|
+
if (installed.some((a) => a.versionName === appName)) return;
|
|
3296
|
+
const target = available.find((a) => a.versionName === appName);
|
|
3297
|
+
if (!target) return;
|
|
3298
|
+
const capacity = getDeviceCapacity(osVersion.targetId);
|
|
3299
|
+
if (!capacity) return;
|
|
3300
|
+
const blockSize = capacity.getBlockSize(osVersion.seVersion);
|
|
3301
|
+
const totalBlocks = Math.floor(capacity.memorySize / blockSize);
|
|
3302
|
+
const blocks = (b) => Math.ceil((b ?? 0) / blockSize);
|
|
3303
|
+
const usedBlocks = installed.reduce((sum, a) => sum + blocks(a.bytes), 0);
|
|
3304
|
+
const neededBlocks = blocks(target.bytes);
|
|
3305
|
+
debugLog(
|
|
3306
|
+
"[DeviceApps] space check",
|
|
3307
|
+
"targetId=",
|
|
3308
|
+
osVersion.targetId.toString(16),
|
|
3309
|
+
"memorySize=",
|
|
3310
|
+
capacity.memorySize,
|
|
3311
|
+
"blockSize=",
|
|
3312
|
+
blockSize,
|
|
3313
|
+
"usedBlocks=",
|
|
3314
|
+
usedBlocks,
|
|
3315
|
+
"neededBlocks=",
|
|
3316
|
+
neededBlocks,
|
|
3317
|
+
"totalBlocks=",
|
|
3318
|
+
totalBlocks
|
|
3319
|
+
);
|
|
3320
|
+
if (usedBlocks + neededBlocks > totalBlocks) {
|
|
3321
|
+
const usedBytes = usedBlocks * blockSize;
|
|
3322
|
+
const neededBytes = neededBlocks * blockSize;
|
|
3323
|
+
const freeBytes = Math.max(0, capacity.memorySize - usedBytes);
|
|
3324
|
+
throw Object.assign(
|
|
3325
|
+
new Error(
|
|
3326
|
+
`Not enough space to install "${appName}": needs ${neededBytes} bytes, ${freeBytes} bytes free of ${capacity.memorySize}.`
|
|
3327
|
+
),
|
|
3328
|
+
{
|
|
3329
|
+
code: import_hwk_adapter_core12.HardwareErrorCode.DeviceOutOfMemory,
|
|
3330
|
+
_tag: "OutOfMemoryDAError",
|
|
3331
|
+
appName,
|
|
3332
|
+
params: {
|
|
3333
|
+
requiredBytes: neededBytes,
|
|
3334
|
+
availableBytes: freeBytes,
|
|
3335
|
+
totalBytes: capacity.memorySize
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
);
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3226
3341
|
// Sole sendCommand wrapper — surfaces unlock-device interaction through
|
|
3227
3342
|
// the same onInteraction pipeline as the device-action methods.
|
|
3228
3343
|
async _fetchOsVersion() {
|
|
@@ -3244,6 +3359,7 @@ var DeviceApps = class {
|
|
|
3244
3359
|
async install(appName, onProgress, options) {
|
|
3245
3360
|
if (!appName) throw new Error("DeviceApps.install: appName is required");
|
|
3246
3361
|
debugLog("[DeviceApps] install:", appName);
|
|
3362
|
+
await this._assertEnoughSpace(appName);
|
|
3247
3363
|
const action = this._dmk.executeDeviceAction({
|
|
3248
3364
|
sessionId: this._sessionId,
|
|
3249
3365
|
deviceAction: new this._ledgerKit.InstallAppDeviceAction({
|
|
@@ -3284,6 +3400,34 @@ function applicationToMetadata(app) {
|
|
|
3284
3400
|
isDevTools: app.isDevTools
|
|
3285
3401
|
};
|
|
3286
3402
|
}
|
|
3403
|
+
var DEVICE_CAPACITIES = [
|
|
3404
|
+
// Nano S — block size 4K on fw<2.0, 2K on >=2.0. Default 4K (conservative).
|
|
3405
|
+
{
|
|
3406
|
+
mask: 823132160,
|
|
3407
|
+
capacity: {
|
|
3408
|
+
memorySize: 320 * 1024,
|
|
3409
|
+
getBlockSize: (fw) => parseMajor(fw) >= 2 ? 2 * 1024 : 4 * 1024
|
|
3410
|
+
}
|
|
3411
|
+
},
|
|
3412
|
+
// Nano S Plus
|
|
3413
|
+
{ mask: 856686592, capacity: { memorySize: 1533 * 1024, getBlockSize: () => 32 } },
|
|
3414
|
+
// Nano X
|
|
3415
|
+
{ mask: 855638016, capacity: { memorySize: 2 * 1024 * 1024, getBlockSize: () => 4 * 1024 } },
|
|
3416
|
+
// Stax
|
|
3417
|
+
{ mask: 857735168, capacity: { memorySize: 1533 * 1024, getBlockSize: () => 32 } },
|
|
3418
|
+
// Flex
|
|
3419
|
+
{ mask: 858783744, capacity: { memorySize: 1533 * 1024, getBlockSize: () => 32 } },
|
|
3420
|
+
// Apex / Nano Gen5
|
|
3421
|
+
{ mask: 859832320, capacity: { memorySize: 1533 * 1024, getBlockSize: () => 32 } }
|
|
3422
|
+
];
|
|
3423
|
+
function getDeviceCapacity(targetId) {
|
|
3424
|
+
const masked = targetId & 4294901760;
|
|
3425
|
+
return DEVICE_CAPACITIES.find((d) => d.mask === masked)?.capacity;
|
|
3426
|
+
}
|
|
3427
|
+
function parseMajor(version) {
|
|
3428
|
+
const m = /^(\d+)/.exec(version);
|
|
3429
|
+
return m ? Number(m[1]) : 0;
|
|
3430
|
+
}
|
|
3287
3431
|
var GetOsVersionDeviceAction = class {
|
|
3288
3432
|
constructor(_deps) {
|
|
3289
3433
|
this._deps = _deps;
|
|
@@ -3398,7 +3542,7 @@ var METHOD_PREFIX_TO_APP_NAME = {
|
|
|
3398
3542
|
tron: "Tron"
|
|
3399
3543
|
};
|
|
3400
3544
|
var HARDWARE_ERROR_CODE_VALUES = new Set(
|
|
3401
|
-
Object.values(
|
|
3545
|
+
Object.values(import_hwk_adapter_core13.HardwareErrorCode).filter((value) => typeof value === "number")
|
|
3402
3546
|
);
|
|
3403
3547
|
var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
|
|
3404
3548
|
async function defaultLedgerKitImporter(pkg) {
|
|
@@ -3577,7 +3721,7 @@ var LedgerConnectorBase = class {
|
|
|
3577
3721
|
`Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
|
|
3578
3722
|
);
|
|
3579
3723
|
err._tag = ERROR_TAG.BlePairingTimeout;
|
|
3580
|
-
err.code =
|
|
3724
|
+
err.code = import_hwk_adapter_core13.HardwareErrorCode.BlePairingTimeout;
|
|
3581
3725
|
reject(err);
|
|
3582
3726
|
}, HANG_CEILING_MS);
|
|
3583
3727
|
});
|
|
@@ -3610,7 +3754,7 @@ var LedgerConnectorBase = class {
|
|
|
3610
3754
|
"Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
|
|
3611
3755
|
);
|
|
3612
3756
|
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
3613
|
-
err.code =
|
|
3757
|
+
err.code = import_hwk_adapter_core13.HardwareErrorCode.DeviceNotFound;
|
|
3614
3758
|
throw err;
|
|
3615
3759
|
};
|
|
3616
3760
|
const doConnect = async (path) => {
|
|
@@ -3689,7 +3833,7 @@ var LedgerConnectorBase = class {
|
|
|
3689
3833
|
"Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
|
|
3690
3834
|
);
|
|
3691
3835
|
wrapped._tag = ERROR_TAG.BleGattBondingFailed;
|
|
3692
|
-
wrapped.code =
|
|
3836
|
+
wrapped.code = import_hwk_adapter_core13.HardwareErrorCode.BlePairingTimeout;
|
|
3693
3837
|
wrapped.originalError = err;
|
|
3694
3838
|
throw wrapped;
|
|
3695
3839
|
}
|
|
@@ -3810,7 +3954,7 @@ var LedgerConnectorBase = class {
|
|
|
3810
3954
|
this._unwatchSessionState(sessionId);
|
|
3811
3955
|
this._signerManager?.invalidate(sessionId);
|
|
3812
3956
|
this._cancellers.get(sessionId)?.({
|
|
3813
|
-
code:
|
|
3957
|
+
code: import_hwk_adapter_core13.HardwareErrorCode.DeviceDisconnected,
|
|
3814
3958
|
tag: "DeviceDisconnected",
|
|
3815
3959
|
message: "Device disconnected"
|
|
3816
3960
|
});
|
|
@@ -3827,14 +3971,14 @@ var LedgerConnectorBase = class {
|
|
|
3827
3971
|
} catch (err) {
|
|
3828
3972
|
if (isAppStuckByApdu(err)) {
|
|
3829
3973
|
throw Object.assign(new Error("Ledger app is unresponsive"), {
|
|
3830
|
-
code:
|
|
3974
|
+
code: import_hwk_adapter_core13.HardwareErrorCode.DeviceAppStuck,
|
|
3831
3975
|
_tag: ERROR_TAG.DeviceAppStuck,
|
|
3832
3976
|
originalError: err
|
|
3833
3977
|
});
|
|
3834
3978
|
}
|
|
3835
3979
|
if (isTransportStuck(err)) {
|
|
3836
3980
|
throw Object.assign(new Error("Device communication interrupted, please retry"), {
|
|
3837
|
-
code:
|
|
3981
|
+
code: import_hwk_adapter_core13.HardwareErrorCode.TransportError,
|
|
3838
3982
|
_tag: ERROR_TAG.DeviceTransportStuck,
|
|
3839
3983
|
originalError: err
|
|
3840
3984
|
});
|