@metamask-previews/eth-ledger-bridge-keyring 12.2.0-e51c895 → 12.3.0-1fa477f

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/CHANGELOG.md CHANGED
@@ -7,9 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - Add `createDMKError` factory function and wire DMK `_tag` resolution into the Ledger DMK bridge ([#597](https://github.com/MetaMask/accounts/pull/597))
13
+ - `createDMKError` constructs `HardwareWalletError` instances from DMK `_tag` strings.
14
+ - `translateDmkError` now resolves DMK connection/session errors (e.g. `DeviceSessionNotFound`, `DeviceLockedError`) by their `_tag` before falling back to hex APDU status codes.
15
+ - `LedgerDmkBridge.#toError` also resolves DMK `_tag` errors so `sendCommand` failures are correctly classified.
16
+
17
+ ### Changed
18
+
19
+ - Bump `@metamask/hw-wallet-sdk` from `^0.10.0` to `^0.11.0` ([#597](https://github.com/MetaMask/accounts/pull/597))
20
+
21
+ ## [12.3.0]
22
+
10
23
  ### Changed
11
24
 
12
- - Bump `@metamask/hw-wallet-sdk` from `^0.8.0` to `^0.9.0` ([#576](https://github.com/MetaMask/accounts/pull/576))
25
+ - Throw `HardwareWalletError` with `DeviceStateOnlyV4Supported` when `signTypedData` is called with a non-V4 version ([#575](https://github.com/MetaMask/accounts/pull/575))
26
+ - Bump `@metamask/hw-wallet-sdk` from `^0.8.0` to `^0.10.0` ([#576](https://github.com/MetaMask/accounts/pull/576), [#587](https://github.com/MetaMask/accounts/pull/587))
27
+ - Bump `@metamask/keyring-api` from `^23.3.0` to `^23.5.0` ([#583](https://github.com/MetaMask/accounts/pull/583), [#587](https://github.com/MetaMask/accounts/pull/587))
13
28
 
14
29
  ## [12.2.0]
15
30
 
@@ -463,7 +478,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
463
478
 
464
479
  - Support new versions of ethereumjs/tx ([#68](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/68))
465
480
 
466
- [Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@12.2.0...HEAD
481
+ [Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@12.3.0...HEAD
482
+ [12.3.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@12.2.0...@metamask/eth-ledger-bridge-keyring@12.3.0
467
483
  [12.2.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@12.1.0...@metamask/eth-ledger-bridge-keyring@12.2.0
468
484
  [12.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@12.0.3...@metamask/eth-ledger-bridge-keyring@12.1.0
469
485
  [12.0.3]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@12.0.2...@metamask/eth-ledger-bridge-keyring@12.0.3
@@ -3,19 +3,41 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isDeviceExchangeError = exports.translateDmkError = void 0;
4
4
  const device_management_kit_1 = require("@ledgerhq/device-management-kit");
5
5
  const hw_transport_1 = require("@ledgerhq/hw-transport");
6
+ const hw_wallet_sdk_1 = require("@metamask/hw-wallet-sdk");
7
+ const errors_1 = require("../errors.cjs");
6
8
  const GENERIC_ERROR_STATUS_CODE = 0x6f00;
7
9
  /**
8
- * Translates a DMK error (DeviceExchangeError with hex error codes) into a
9
- * TransportStatusError that the Ledger keyring error handler can process.
10
+ * Translates a DMK error into an error the Ledger keyring error handler can
11
+ * process.
12
+ *
13
+ * Resolution order:
14
+ * 1. **DMK `_tag`** — connection/session-level DMK errors (e.g.
15
+ * `DeviceSessionNotFound`, `DeviceLockedError`) carry a `_tag` but no hex
16
+ * APDU status code. These are resolved to a {@link HardwareWalletError}
17
+ * via the shared SDK mappings.
18
+ * 2. **`DeviceExchangeError` hex code** — APDU-level errors that carry a
19
+ * 4-character hex `errorCode` (e.g. `'6985'`). These are converted to a
20
+ * {@link TransportStatusError} so the existing `LEDGER_ERROR_MAPPINGS`
21
+ * lookup in the keyring error handler applies.
22
+ * 3. **Generic fallback** — anything else is wrapped in a
23
+ * {@link TransportStatusError} with status `0x6f00`.
10
24
  *
11
25
  * @param error - The error from a DMK device action or command.
12
- * @returns A TransportStatusError with the corresponding APDU status code.
26
+ * @returns A `HardwareWalletError` (for resolved DMK tags) or a
27
+ * `TransportStatusError` (for hex codes and the generic fallback).
13
28
  */
14
29
  function translateDmkError(error) {
30
+ // 1. DMK connection/session errors identified by _tag
31
+ const tagResolution = (0, hw_wallet_sdk_1.getDMKErrorFromTag)(error);
32
+ if (tagResolution) {
33
+ return (0, errors_1.createDMKError)(tagResolution.tag);
34
+ }
35
+ // 2. DeviceExchangeError with hex APDU status code
15
36
  if (isDeviceExchangeError(error)) {
16
37
  const statusCode = parseHexErrorCode(error.errorCode);
17
38
  return new hw_transport_1.TransportStatusError(statusCode);
18
39
  }
40
+ // 3. Generic fallback
19
41
  return new hw_transport_1.TransportStatusError(GENERIC_ERROR_STATUS_CODE);
20
42
  }
21
43
  exports.translateDmkError = translateDmkError;
@@ -1 +1 @@
1
- {"version":3,"file":"dmk-error-translator.cjs","sourceRoot":"","sources":["../../src/dmk/dmk-error-translator.ts"],"names":[],"mappings":";;;AAAA,2EAAsE;AACtE,yDAA8D;AAE9D,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEzC;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAAC,KAAc;IAC9C,IAAI,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACtD,OAAO,IAAI,mCAAoB,CAAC,UAAU,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,IAAI,mCAAoB,CAAC,yBAAyB,CAAC,CAAC;AAC7D,CAAC;AAPD,8CAOC;AAED,SAAgB,qBAAqB,CACnC,KAAc;IAEd,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,WAAW,IAAI,KAAK,CACrB,CAAC;AACJ,CAAC;AATD,sDASC;AAED,SAAS,iBAAiB,CAAC,SAAkB;IAC3C,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACzE,OAAO,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,yBAAyB,CAAC;AACnC,CAAC","sourcesContent":["import { DeviceExchangeError } from '@ledgerhq/device-management-kit';\nimport { TransportStatusError } from '@ledgerhq/hw-transport';\n\nconst GENERIC_ERROR_STATUS_CODE = 0x6f00;\n\n/**\n * Translates a DMK error (DeviceExchangeError with hex error codes) into a\n * TransportStatusError that the Ledger keyring error handler can process.\n *\n * @param error - The error from a DMK device action or command.\n * @returns A TransportStatusError with the corresponding APDU status code.\n */\nexport function translateDmkError(error: unknown): TransportStatusError {\n if (isDeviceExchangeError(error)) {\n const statusCode = parseHexErrorCode(error.errorCode);\n return new TransportStatusError(statusCode);\n }\n\n return new TransportStatusError(GENERIC_ERROR_STATUS_CODE);\n}\n\nexport function isDeviceExchangeError(\n error: unknown,\n): error is DeviceExchangeError<string> {\n return (\n typeof error === 'object' &&\n error !== null &&\n '_tag' in error &&\n 'errorCode' in error\n );\n}\n\nfunction parseHexErrorCode(errorCode: unknown): number {\n if (typeof errorCode === 'string' && /^[0-9a-fA-F]{4}$/u.test(errorCode)) {\n return parseInt(errorCode, 16);\n }\n\n return GENERIC_ERROR_STATUS_CODE;\n}\n"]}
1
+ {"version":3,"file":"dmk-error-translator.cjs","sourceRoot":"","sources":["../../src/dmk/dmk-error-translator.ts"],"names":[],"mappings":";;;AAAA,2EAAsE;AACtE,yDAA8D;AAC9D,2DAGiC;AAEjC,0CAA2C;AAE3C,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAgB,iBAAiB,CAC/B,KAAc;IAEd,sDAAsD;IACtD,MAAM,aAAa,GAAG,IAAA,kCAAkB,EAAC,KAAK,CAAC,CAAC;IAChD,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,IAAA,uBAAc,EAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,mDAAmD;IACnD,IAAI,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACtD,OAAO,IAAI,mCAAoB,CAAC,UAAU,CAAC,CAAC;IAC9C,CAAC;IAED,sBAAsB;IACtB,OAAO,IAAI,mCAAoB,CAAC,yBAAyB,CAAC,CAAC;AAC7D,CAAC;AAjBD,8CAiBC;AAED,SAAgB,qBAAqB,CACnC,KAAc;IAEd,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,WAAW,IAAI,KAAK,CACrB,CAAC;AACJ,CAAC;AATD,sDASC;AAED,SAAS,iBAAiB,CAAC,SAAkB;IAC3C,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACzE,OAAO,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,yBAAyB,CAAC;AACnC,CAAC","sourcesContent":["import { DeviceExchangeError } from '@ledgerhq/device-management-kit';\nimport { TransportStatusError } from '@ledgerhq/hw-transport';\nimport {\n getDMKErrorFromTag,\n HardwareWalletError,\n} from '@metamask/hw-wallet-sdk';\n\nimport { createDMKError } from '../errors';\n\nconst GENERIC_ERROR_STATUS_CODE = 0x6f00;\n\n/**\n * Translates a DMK error into an error the Ledger keyring error handler can\n * process.\n *\n * Resolution order:\n * 1. **DMK `_tag`** — connection/session-level DMK errors (e.g.\n * `DeviceSessionNotFound`, `DeviceLockedError`) carry a `_tag` but no hex\n * APDU status code. These are resolved to a {@link HardwareWalletError}\n * via the shared SDK mappings.\n * 2. **`DeviceExchangeError` hex code** — APDU-level errors that carry a\n * 4-character hex `errorCode` (e.g. `'6985'`). These are converted to a\n * {@link TransportStatusError} so the existing `LEDGER_ERROR_MAPPINGS`\n * lookup in the keyring error handler applies.\n * 3. **Generic fallback** — anything else is wrapped in a\n * {@link TransportStatusError} with status `0x6f00`.\n *\n * @param error - The error from a DMK device action or command.\n * @returns A `HardwareWalletError` (for resolved DMK tags) or a\n * `TransportStatusError` (for hex codes and the generic fallback).\n */\nexport function translateDmkError(\n error: unknown,\n): TransportStatusError | HardwareWalletError {\n // 1. DMK connection/session errors identified by _tag\n const tagResolution = getDMKErrorFromTag(error);\n if (tagResolution) {\n return createDMKError(tagResolution.tag);\n }\n\n // 2. DeviceExchangeError with hex APDU status code\n if (isDeviceExchangeError(error)) {\n const statusCode = parseHexErrorCode(error.errorCode);\n return new TransportStatusError(statusCode);\n }\n\n // 3. Generic fallback\n return new TransportStatusError(GENERIC_ERROR_STATUS_CODE);\n}\n\nexport function isDeviceExchangeError(\n error: unknown,\n): error is DeviceExchangeError<string> {\n return (\n typeof error === 'object' &&\n error !== null &&\n '_tag' in error &&\n 'errorCode' in error\n );\n}\n\nfunction parseHexErrorCode(errorCode: unknown): number {\n if (typeof errorCode === 'string' && /^[0-9a-fA-F]{4}$/u.test(errorCode)) {\n return parseInt(errorCode, 16);\n }\n\n return GENERIC_ERROR_STATUS_CODE;\n}\n"]}
@@ -1,12 +1,26 @@
1
1
  import { DeviceExchangeError } from "@ledgerhq/device-management-kit";
2
2
  import { TransportStatusError } from "@ledgerhq/hw-transport";
3
+ import { HardwareWalletError } from "@metamask/hw-wallet-sdk";
3
4
  /**
4
- * Translates a DMK error (DeviceExchangeError with hex error codes) into a
5
- * TransportStatusError that the Ledger keyring error handler can process.
5
+ * Translates a DMK error into an error the Ledger keyring error handler can
6
+ * process.
7
+ *
8
+ * Resolution order:
9
+ * 1. **DMK `_tag`** — connection/session-level DMK errors (e.g.
10
+ * `DeviceSessionNotFound`, `DeviceLockedError`) carry a `_tag` but no hex
11
+ * APDU status code. These are resolved to a {@link HardwareWalletError}
12
+ * via the shared SDK mappings.
13
+ * 2. **`DeviceExchangeError` hex code** — APDU-level errors that carry a
14
+ * 4-character hex `errorCode` (e.g. `'6985'`). These are converted to a
15
+ * {@link TransportStatusError} so the existing `LEDGER_ERROR_MAPPINGS`
16
+ * lookup in the keyring error handler applies.
17
+ * 3. **Generic fallback** — anything else is wrapped in a
18
+ * {@link TransportStatusError} with status `0x6f00`.
6
19
  *
7
20
  * @param error - The error from a DMK device action or command.
8
- * @returns A TransportStatusError with the corresponding APDU status code.
21
+ * @returns A `HardwareWalletError` (for resolved DMK tags) or a
22
+ * `TransportStatusError` (for hex codes and the generic fallback).
9
23
  */
10
- export declare function translateDmkError(error: unknown): TransportStatusError;
24
+ export declare function translateDmkError(error: unknown): TransportStatusError | HardwareWalletError;
11
25
  export declare function isDeviceExchangeError(error: unknown): error is DeviceExchangeError<string>;
12
26
  //# sourceMappingURL=dmk-error-translator.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dmk-error-translator.d.cts","sourceRoot":"","sources":["../../src/dmk/dmk-error-translator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,wCAAwC;AACtE,OAAO,EAAE,oBAAoB,EAAE,+BAA+B;AAI9D;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,CAOtE;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAOtC"}
1
+ {"version":3,"file":"dmk-error-translator.d.cts","sourceRoot":"","sources":["../../src/dmk/dmk-error-translator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,wCAAwC;AACtE,OAAO,EAAE,oBAAoB,EAAE,+BAA+B;AAC9D,OAAO,EAEL,mBAAmB,EACpB,gCAAgC;AAMjC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,GACb,oBAAoB,GAAG,mBAAmB,CAe5C;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAOtC"}
@@ -1,12 +1,26 @@
1
1
  import { DeviceExchangeError } from "@ledgerhq/device-management-kit";
2
2
  import { TransportStatusError } from "@ledgerhq/hw-transport";
3
+ import { HardwareWalletError } from "@metamask/hw-wallet-sdk";
3
4
  /**
4
- * Translates a DMK error (DeviceExchangeError with hex error codes) into a
5
- * TransportStatusError that the Ledger keyring error handler can process.
5
+ * Translates a DMK error into an error the Ledger keyring error handler can
6
+ * process.
7
+ *
8
+ * Resolution order:
9
+ * 1. **DMK `_tag`** — connection/session-level DMK errors (e.g.
10
+ * `DeviceSessionNotFound`, `DeviceLockedError`) carry a `_tag` but no hex
11
+ * APDU status code. These are resolved to a {@link HardwareWalletError}
12
+ * via the shared SDK mappings.
13
+ * 2. **`DeviceExchangeError` hex code** — APDU-level errors that carry a
14
+ * 4-character hex `errorCode` (e.g. `'6985'`). These are converted to a
15
+ * {@link TransportStatusError} so the existing `LEDGER_ERROR_MAPPINGS`
16
+ * lookup in the keyring error handler applies.
17
+ * 3. **Generic fallback** — anything else is wrapped in a
18
+ * {@link TransportStatusError} with status `0x6f00`.
6
19
  *
7
20
  * @param error - The error from a DMK device action or command.
8
- * @returns A TransportStatusError with the corresponding APDU status code.
21
+ * @returns A `HardwareWalletError` (for resolved DMK tags) or a
22
+ * `TransportStatusError` (for hex codes and the generic fallback).
9
23
  */
10
- export declare function translateDmkError(error: unknown): TransportStatusError;
24
+ export declare function translateDmkError(error: unknown): TransportStatusError | HardwareWalletError;
11
25
  export declare function isDeviceExchangeError(error: unknown): error is DeviceExchangeError<string>;
12
26
  //# sourceMappingURL=dmk-error-translator.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dmk-error-translator.d.mts","sourceRoot":"","sources":["../../src/dmk/dmk-error-translator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,wCAAwC;AACtE,OAAO,EAAE,oBAAoB,EAAE,+BAA+B;AAI9D;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,CAOtE;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAOtC"}
1
+ {"version":3,"file":"dmk-error-translator.d.mts","sourceRoot":"","sources":["../../src/dmk/dmk-error-translator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,wCAAwC;AACtE,OAAO,EAAE,oBAAoB,EAAE,+BAA+B;AAC9D,OAAO,EAEL,mBAAmB,EACpB,gCAAgC;AAMjC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,GACb,oBAAoB,GAAG,mBAAmB,CAe5C;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAOtC"}
@@ -1,18 +1,40 @@
1
1
  import { DeviceExchangeError } from "@ledgerhq/device-management-kit";
2
2
  import { TransportStatusError } from "@ledgerhq/hw-transport";
3
+ import { getDMKErrorFromTag, HardwareWalletError } from "@metamask/hw-wallet-sdk";
4
+ import { createDMKError } from "../errors.mjs";
3
5
  const GENERIC_ERROR_STATUS_CODE = 0x6f00;
4
6
  /**
5
- * Translates a DMK error (DeviceExchangeError with hex error codes) into a
6
- * TransportStatusError that the Ledger keyring error handler can process.
7
+ * Translates a DMK error into an error the Ledger keyring error handler can
8
+ * process.
9
+ *
10
+ * Resolution order:
11
+ * 1. **DMK `_tag`** — connection/session-level DMK errors (e.g.
12
+ * `DeviceSessionNotFound`, `DeviceLockedError`) carry a `_tag` but no hex
13
+ * APDU status code. These are resolved to a {@link HardwareWalletError}
14
+ * via the shared SDK mappings.
15
+ * 2. **`DeviceExchangeError` hex code** — APDU-level errors that carry a
16
+ * 4-character hex `errorCode` (e.g. `'6985'`). These are converted to a
17
+ * {@link TransportStatusError} so the existing `LEDGER_ERROR_MAPPINGS`
18
+ * lookup in the keyring error handler applies.
19
+ * 3. **Generic fallback** — anything else is wrapped in a
20
+ * {@link TransportStatusError} with status `0x6f00`.
7
21
  *
8
22
  * @param error - The error from a DMK device action or command.
9
- * @returns A TransportStatusError with the corresponding APDU status code.
23
+ * @returns A `HardwareWalletError` (for resolved DMK tags) or a
24
+ * `TransportStatusError` (for hex codes and the generic fallback).
10
25
  */
11
26
  export function translateDmkError(error) {
27
+ // 1. DMK connection/session errors identified by _tag
28
+ const tagResolution = getDMKErrorFromTag(error);
29
+ if (tagResolution) {
30
+ return createDMKError(tagResolution.tag);
31
+ }
32
+ // 2. DeviceExchangeError with hex APDU status code
12
33
  if (isDeviceExchangeError(error)) {
13
34
  const statusCode = parseHexErrorCode(error.errorCode);
14
35
  return new TransportStatusError(statusCode);
15
36
  }
37
+ // 3. Generic fallback
16
38
  return new TransportStatusError(GENERIC_ERROR_STATUS_CODE);
17
39
  }
18
40
  export function isDeviceExchangeError(error) {
@@ -1 +1 @@
1
- {"version":3,"file":"dmk-error-translator.mjs","sourceRoot":"","sources":["../../src/dmk/dmk-error-translator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,wCAAwC;AACtE,OAAO,EAAE,oBAAoB,EAAE,+BAA+B;AAE9D,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,IAAI,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACtD,OAAO,IAAI,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,IAAI,oBAAoB,CAAC,yBAAyB,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,KAAc;IAEd,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,WAAW,IAAI,KAAK,CACrB,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,SAAkB;IAC3C,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACzE,OAAO,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,yBAAyB,CAAC;AACnC,CAAC","sourcesContent":["import { DeviceExchangeError } from '@ledgerhq/device-management-kit';\nimport { TransportStatusError } from '@ledgerhq/hw-transport';\n\nconst GENERIC_ERROR_STATUS_CODE = 0x6f00;\n\n/**\n * Translates a DMK error (DeviceExchangeError with hex error codes) into a\n * TransportStatusError that the Ledger keyring error handler can process.\n *\n * @param error - The error from a DMK device action or command.\n * @returns A TransportStatusError with the corresponding APDU status code.\n */\nexport function translateDmkError(error: unknown): TransportStatusError {\n if (isDeviceExchangeError(error)) {\n const statusCode = parseHexErrorCode(error.errorCode);\n return new TransportStatusError(statusCode);\n }\n\n return new TransportStatusError(GENERIC_ERROR_STATUS_CODE);\n}\n\nexport function isDeviceExchangeError(\n error: unknown,\n): error is DeviceExchangeError<string> {\n return (\n typeof error === 'object' &&\n error !== null &&\n '_tag' in error &&\n 'errorCode' in error\n );\n}\n\nfunction parseHexErrorCode(errorCode: unknown): number {\n if (typeof errorCode === 'string' && /^[0-9a-fA-F]{4}$/u.test(errorCode)) {\n return parseInt(errorCode, 16);\n }\n\n return GENERIC_ERROR_STATUS_CODE;\n}\n"]}
1
+ {"version":3,"file":"dmk-error-translator.mjs","sourceRoot":"","sources":["../../src/dmk/dmk-error-translator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,wCAAwC;AACtE,OAAO,EAAE,oBAAoB,EAAE,+BAA+B;AAC9D,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACpB,gCAAgC;AAEjC,OAAO,EAAE,cAAc,EAAE,sBAAkB;AAE3C,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAc;IAEd,sDAAsD;IACtD,MAAM,aAAa,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAChD,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,cAAc,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,mDAAmD;IACnD,IAAI,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACtD,OAAO,IAAI,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAC9C,CAAC;IAED,sBAAsB;IACtB,OAAO,IAAI,oBAAoB,CAAC,yBAAyB,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,KAAc;IAEd,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,WAAW,IAAI,KAAK,CACrB,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,SAAkB;IAC3C,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACzE,OAAO,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,yBAAyB,CAAC;AACnC,CAAC","sourcesContent":["import { DeviceExchangeError } from '@ledgerhq/device-management-kit';\nimport { TransportStatusError } from '@ledgerhq/hw-transport';\nimport {\n getDMKErrorFromTag,\n HardwareWalletError,\n} from '@metamask/hw-wallet-sdk';\n\nimport { createDMKError } from '../errors';\n\nconst GENERIC_ERROR_STATUS_CODE = 0x6f00;\n\n/**\n * Translates a DMK error into an error the Ledger keyring error handler can\n * process.\n *\n * Resolution order:\n * 1. **DMK `_tag`** — connection/session-level DMK errors (e.g.\n * `DeviceSessionNotFound`, `DeviceLockedError`) carry a `_tag` but no hex\n * APDU status code. These are resolved to a {@link HardwareWalletError}\n * via the shared SDK mappings.\n * 2. **`DeviceExchangeError` hex code** — APDU-level errors that carry a\n * 4-character hex `errorCode` (e.g. `'6985'`). These are converted to a\n * {@link TransportStatusError} so the existing `LEDGER_ERROR_MAPPINGS`\n * lookup in the keyring error handler applies.\n * 3. **Generic fallback** — anything else is wrapped in a\n * {@link TransportStatusError} with status `0x6f00`.\n *\n * @param error - The error from a DMK device action or command.\n * @returns A `HardwareWalletError` (for resolved DMK tags) or a\n * `TransportStatusError` (for hex codes and the generic fallback).\n */\nexport function translateDmkError(\n error: unknown,\n): TransportStatusError | HardwareWalletError {\n // 1. DMK connection/session errors identified by _tag\n const tagResolution = getDMKErrorFromTag(error);\n if (tagResolution) {\n return createDMKError(tagResolution.tag);\n }\n\n // 2. DeviceExchangeError with hex APDU status code\n if (isDeviceExchangeError(error)) {\n const statusCode = parseHexErrorCode(error.errorCode);\n return new TransportStatusError(statusCode);\n }\n\n // 3. Generic fallback\n return new TransportStatusError(GENERIC_ERROR_STATUS_CODE);\n}\n\nexport function isDeviceExchangeError(\n error: unknown,\n): error is DeviceExchangeError<string> {\n return (\n typeof error === 'object' &&\n error !== null &&\n '_tag' in error &&\n 'errorCode' in error\n );\n}\n\nfunction parseHexErrorCode(errorCode: unknown): number {\n if (typeof errorCode === 'string' && /^[0-9a-fA-F]{4}$/u.test(errorCode)) {\n return parseInt(errorCode, 16);\n }\n\n return GENERIC_ERROR_STATUS_CODE;\n}\n"]}
@@ -14,8 +14,10 @@ var _LedgerDmkBridge_instances, _LedgerDmkBridge_transportMiddleware, _LedgerDmk
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.LedgerDmkBridge = void 0;
16
16
  const device_management_kit_1 = require("@ledgerhq/device-management-kit");
17
+ const hw_wallet_sdk_1 = require("@metamask/hw-wallet-sdk");
17
18
  const rxjs_1 = require("rxjs");
18
19
  const operators_1 = require("rxjs/operators");
20
+ const errors_1 = require("../errors.cjs");
19
21
  const dmk_error_translator_1 = require("./dmk-error-translator.cjs");
20
22
  const eth_get_app_configuration_command_1 = require("./eth-get-app-configuration-command.cjs");
21
23
  const internal_utils_1 = require("./internal-utils.cjs");
@@ -348,6 +350,13 @@ _LedgerDmkBridge_transportMiddleware = new WeakMap(), _LedgerDmkBridge_sdk = new
348
350
  // through. Defensive guard retained for type safety.
349
351
  throw new Error('Ledger device action ended without completion.');
350
352
  }, _LedgerDmkBridge_toError = function _LedgerDmkBridge_toError(error) {
353
+ // DMK connection/session errors identified by _tag (e.g.
354
+ // DeviceSessionNotFound, DeviceLockedError) carry no hex APDU code.
355
+ // Resolve them to a HardwareWalletError before falling through.
356
+ const tagResolution = (0, hw_wallet_sdk_1.getDMKErrorFromTag)(error);
357
+ if (tagResolution) {
358
+ return (0, errors_1.createDMKError)(tagResolution.tag);
359
+ }
351
360
  if ((0, dmk_error_translator_1.isDeviceExchangeError)(error)) {
352
361
  return (0, dmk_error_translator_1.translateDmkError)(error);
353
362
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-dmk-bridge.cjs","sourceRoot":"","sources":["../../src/dmk/ledger-dmk-bridge.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2EAQyC;AAQzC,+BAQc;AACd,8CAOwB;AAiBxB,qEAGgC;AAChC,+FAAoF;AACpF,yDAK0B;AAC1B,2FAAiF;AAWjF;;;;;GAKG;AACH,MAAa,eAAe;IAW1B,IAAI,oBAAoB;QACtB,OAAO,uBAAA,IAAI,sCAAe,CAAC,YAAY,EAAE,CAAC;IAC5C,CAAC;IAID,IAAI,iBAAiB;QACnB,OAAO,uBAAA,IAAI,oCAAa,CAAC;IAC3B,CAAC;IAED,YAAY,IAA4B;;QApB/B,uDAAmD;QAEnD,uCAA0B;QAEnC,wCAA8B;QAE9B,uCAAe,KAAK,EAAC;QAErB,yCAAiB,IAAI,cAAO,EAA0B,EAAC;QAMvD,+CAA4C,IAAI,EAAC;QAO/C,uBAAA,IAAI,wBAAQ,IAAI,kDAA0B,EAAE;aACzC,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC;aACnC,KAAK,EAAE,MAAA,CAAC;QACX,uBAAA,IAAI,yBAAS,IAAI,MAAA,CAAC;QAClB,uBAAA,IAAI,wCAAwB,IAAI,8DAA4B,CAAC,uBAAA,IAAI,4BAAK,CAAC,MAAA,CAAC;IAC1E,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,IAAI;QACR,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,OAAO;QACX,uBAAA,IAAI,4CAAqB,EAAE,WAAW,EAAE,CAAC;QACzC,uBAAA,IAAI,wCAAwB,IAAI,MAAA,CAAC;QAEjC,IAAI,CAAC;YACH,MAAM,uBAAA,IAAI,4CAAqB,CAAC,OAAO,EAAE,CAAC;QAC5C,CAAC;gBAAS,CAAC;YACT,uBAAA,IAAI,gCAAgB,KAAK,MAAA,CAAC;YAC1B,uBAAA,IAAI,sCAAe,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YAC/C,uBAAA,IAAI,sCAAe,CAAC,QAAQ,EAAE,CAAC;YAC/B,uBAAA,IAAI,kCAAkB,IAAI,cAAO,EAA0B,MAAA,CAAC;QAC9D,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,UAAU;QACd,OAAO,uBAAA,IAAI,6BAAM,CAAC;IACpB,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,UAAU,CAAC,IAA4B;QAC3C,uBAAA,IAAI,yBAAS,IAAI,MAAA,CAAC;IACpB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,eAAe,CAAC,SAAiB;QACrC,MAAM,uBAAA,IAAI,4CAAqB,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QACxD,uBAAA,IAAI,gCAAgB,IAAI,MAAA,CAAC;QACzB,uBAAA,IAAI,2EAAwB,MAA5B,IAAI,EAAyB,SAAS,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,gBAAgB,CACd,GAAG,IAAkE;QAErE,OAAO,uBAAA,IAAI,4CAAqB,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7D,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CACX,GAAG,IAAyD;QAE5D,MAAM,SAAS,GAAG,MAAM,uBAAA,IAAI,4CAAqB,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QACnE,uBAAA,IAAI,gCAAgB,IAAI,MAAA,CAAC;QACzB,uBAAA,IAAI,2EAAwB,MAA5B,IAAI,EAAyB,SAAS,CAAC,CAAC;QAExC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,qBAAqB,CACzB,cAAkC;QAElC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,SAAS,GAAG,uBAAA,IAAI,4CAAqB,CAAC,YAAY,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,uBAAA,IAAI,4BAAK,CAAC,WAAW,CAAC;YACzC,SAAS;YACT,OAAO,EAAE,IAAI,sCAAc,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;SACrD,CAAC,CAAC;QAEH,IAAI,CAAC,IAAA,8CAAsB,EAAC,MAAM,CAAC,EAAE,CAAC;YACpC,MAAM,uBAAA,IAAI,4DAAS,MAAb,IAAI,EAAU,MAAM,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,SAAS;QACb,MAAM,SAAS,GAAG,uBAAA,IAAI,4CAAqB,CAAC,YAAY,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,uBAAA,IAAI,4BAAK,CAAC,WAAW,CAAC;YACzC,SAAS;YACT,OAAO,EAAE,IAAI,uCAAe,EAAE;SAC/B,CAAC,CAAC;QAEH,IAAI,CAAC,IAAA,8CAAsB,EAAC,MAAM,CAAC,EAAE,CAAC;YACpC,MAAM,uBAAA,IAAI,4DAAS,MAAb,IAAI,EAAU,MAAM,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,cAAc;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,YAAY,CAAC,EACjB,MAAM,GACa;QACnB,MAAM,EAAE,UAAU,EAAE,GAAG,uBAAA,IAAI,4CAAqB;aAC7C,YAAY,EAAE;aACd,UAAU,CAAC,IAAA,gCAAe,EAAC,MAAM,CAAC,EAAE;YACnC,aAAa,EAAE,KAAK;YACpB,eAAe,EAAE,IAAI;SACtB,CAAC,CAAC;QACL,MAAM,QAAQ,GACZ,MAAM,uBAAA,IAAI,wEAAqB,MAAzB,IAAI,EAAuC,UAAU,CAAC,CAAC;QAE/D,OAAO;YACL,SAAS,EAAE,QAAQ,CAAC,SAAS;YAC7B,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,SAAS,EAAE,QAAQ,CAAC,SAAS;SAC9B,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,qBAAqB,CAAC,EAC1B,EAAE,EACF,MAAM,GACsB;QAC5B,MAAM,EAAE,UAAU,EAAE,GAAG,uBAAA,IAAI,4CAAqB;aAC7C,YAAY,EAAE;aACd,eAAe,CAAC,IAAA,gCAAe,EAAC,MAAM,CAAC,EAAE,IAAA,2BAAU,EAAC,EAAE,CAAC,CAAC,CAAC;QAC5D,MAAM,SAAS,GAAG,MAAM,uBAAA,IAAI,wEAAqB,MAAzB,IAAI,EAAiC,UAAU,CAAC,CAAC;QAEzE,OAAO;YACL,CAAC,EAAE,IAAA,4BAAW,EAAC,SAAS,CAAC,CAAC,CAAC;YAC3B,CAAC,EAAE,IAAA,+BAAc,EAAC,SAAS,CAAC,CAAC,CAAC;YAC9B,CAAC,EAAE,IAAA,+BAAc,EAAC,SAAS,CAAC,CAAC,CAAC;SAC/B,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,iBAAiB,CAAC,EACtB,MAAM,EACN,OAAO,GACiB;QACxB,MAAM,EAAE,UAAU,EAAE,GAAG,uBAAA,IAAI,4CAAqB;aAC7C,YAAY,EAAE;aACd,WAAW,CAAC,IAAA,gCAAe,EAAC,MAAM,CAAC,EAAE,IAAA,2BAAU,EAAC,OAAO,CAAC,CAAC,CAAC;QAC7D,MAAM,SAAS,GAAG,MAAM,uBAAA,IAAI,wEAAqB,MAAzB,IAAI,EAAiC,UAAU,CAAC,CAAC;QAEzE,OAAO;YACL,CAAC,EAAE,SAAS,CAAC,CAAC;YACd,CAAC,EAAE,IAAA,+BAAc,EAAC,SAAS,CAAC,CAAC,CAAC;YAC9B,CAAC,EAAE,IAAA,+BAAc,EAAC,SAAS,CAAC,CAAC,CAAC;SAC/B,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,mBAAmB,CAAC,EACxB,MAAM,EACN,OAAO,GACmB;QAC1B,MAAM,EAAE,UAAU,EAAE,GAAG,uBAAA,IAAI,4CAAqB;aAC7C,YAAY,EAAE;aACd,aAAa,CAAC,IAAA,gCAAe,EAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,MAAM,uBAAA,IAAI,wEAAqB,MAAzB,IAAI,EAAiC,UAAU,CAAC,CAAC;QAEzE,OAAO;YACL,CAAC,EAAE,SAAS,CAAC,CAAC;YACd,CAAC,EAAE,IAAA,+BAAc,EAAC,SAAS,CAAC,CAAC,CAAC;YAC9B,CAAC,EAAE,IAAA,+BAAc,EAAC,SAAS,CAAC,CAAC,CAAC;SAC/B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,iCAAiC,CAAC,EACtC,MAAM,EACN,OAAO,EACP,eAAe,EACf,KAAK,GACmC;QACxC,MAAM,EAAE,UAAU,EAAE,GAAG,uBAAA,IAAI,4CAAqB;aAC7C,YAAY,EAAE;aACd,2BAA2B,CAC1B,IAAA,gCAAe,EAAC,MAAM,CAAC,EACvB,OAAO,EACP,eAAe,EACf,KAAK,CACN,CAAC;QACJ,MAAM,SAAS,GAAG,MAAM,uBAAA,IAAI,wEAAqB,MAAzB,IAAI,EAAiC,UAAU,CAAC,CAAC;QAEzE,OAAO;YACL,CAAC,EAAE,IAAA,4BAAW,EAAC,SAAS,CAAC,CAAC,CAAC;YAC3B,CAAC,EAAE,IAAA,+BAAc,EAAC,SAAS,CAAC,CAAC,CAAC;YAC9B,CAAC,EAAE,IAAA,+BAAc,EAAC,SAAS,CAAC,CAAC,CAAC;SAC/B,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,oBAAoB;QACxB,MAAM,SAAS,GAAG,uBAAA,IAAI,4CAAqB,CAAC,YAAY,EAAE,CAAC;QAC3D,MAAM,OAAO,GAAG,IAAI,+CAAuB,EAAE,CAAC;QAC9C,MAAM,MAAM,GAAG,MAAM,uBAAA,IAAI,4BAAK,CAAC,WAAW,CAAC;YACzC,SAAS;YACT,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,CAAC,IAAA,8CAAsB,EAAC,MAAM,CAAC,EAAE,CAAC;YACpC,MAAM,uBAAA,IAAI,4DAAS,MAAb,IAAI,EAAU,MAAM,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI;YACzB,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO;SAC7B,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,mBAAmB;QACvB,MAAM,SAAS,GAAG,uBAAA,IAAI,4CAAqB,CAAC,YAAY,EAAE,CAAC;QAC3D,MAAM,OAAO,GAAG,IAAI,iEAA6B,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,MAAM,uBAAA,IAAI,4BAAK,CAAC,WAAW,CAAC;YACzC,SAAS;YACT,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,CAAC,IAAA,8CAAsB,EAAC,MAAM,CAAC,EAAE,CAAC;YACpC,MAAM,uBAAA,IAAI,4DAAS,MAAb,IAAI,EAAU,MAAM,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;QAExB,mDAAmD;QACnD,gGAAgG;QAChG,0EAA0E;QAC1E,wEAAwE;QACxE,wEAAwE;QACxE,oEAAoE;QACpE,oEAAoE;QACpE,qBAAqB;QACrB,EAAE;QACF,sEAAsE;QACtE,sEAAsE;QACtE,sEAAsE;QACtE,0BAA0B;QAC1B,OAAO;YACL,oBAAoB,EAAE,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACtD,0BAA0B,EAAE,CAAC;YAC7B,YAAY,EAAE,CAAC;YACf,gBAAgB,EAAE,CAAC;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC;IACJ,CAAC;CA8GF;AAheD,0CAgeC;0WA5GC,KAAK,+CACH,UAAoE;IAEpE,MAAM,KAAK,GAAG,MAAM,IAAA,qBAAc,EAChC,UAAU,CAAC,IAAI,CACb,IAAA,sBAAU,EAAC,CAAC,KAAc,EAAE,EAAE;QAC5B,MAAM,IAAA,wCAAiB,EAAC,KAAK,CAAC,CAAC;IACjC,CAAC,CAAC,EACF,IAAA,kBAAM,EACJ,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CACb,MAAM,KAAK,0CAAkB,CAAC,SAAS;QACvC,MAAM,KAAK,0CAAkB,CAAC,KAAK,CACtC,CACF,CACF,CAAC;IAEF,IAAI,KAAK,CAAC,MAAM,KAAK,0CAAkB,CAAC,SAAS,EAAE,CAAC;QAClD,OAAO,KAAK,CAAC,MAAM,CAAC;IACtB,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,0CAAkB,CAAC,KAAK,EAAE,CAAC;QAC9C,MAAM,IAAA,wCAAiB,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,oEAAoE;IACpE,qDAAqD;IACrD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;AACpE,CAAC,+DAEQ,KAAc;IACrB,IAAI,IAAA,4CAAqB,EAAC,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,IAAA,wCAAiB,EAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;AAC7C,CAAC,6FAuBuB,SAAiB;IACvC,uBAAA,IAAI,4CAAqB,EAAE,WAAW,EAAE,CAAC;IAEzC,MAAM,cAAc,GAAG,KAAM,CAAC;IAC9B,MAAM,aAAa,GAAG,IAAK,CAAC;IAC5B,MAAM,WAAW,GAAG,EAAE,CAAC;IAEvB,MAAM,sBAAsB,GAAG,CAC7B,UAAU,GAAG,CAAC,EACsB,EAAE,CACtC,uBAAA,IAAI,4BAAK,CAAC,qBAAqB,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,CACjD,IAAA,eAAG,EAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACd,SAAS,EAAE,KAAK,CAAC,YAAY,KAAK,oCAAY,CAAC,aAAa;KAC7D,CAAC,CAAC,EACH,IAAA,sBAAU,EAAC,GAAG,EAAE;QACd,IAAI,UAAU,IAAI,WAAW,EAAE,CAAC;YAC9B,OAAO,IAAA,SAAE,EAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QAClC,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,aAAa,GAAG,CAAC,IAAI,UAAU,EAC/B,cAAc,CACf,CAAC;QACF,OAAO,IAAA,aAAM,EACX,IAAA,SAAE,EAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EACxB,IAAA,YAAK,EAAC,GAAG,EAAE,CACT,IAAA,YAAK,EAAC,KAAK,CAAC,CAAC,IAAI,CACf,IAAA,qBAAS,EAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CACxD,CACF,CACF,CAAC;IACJ,CAAC,CAAC,EACF,IAAA,mBAAO,EAAC,EAAE,SAAS,EAAE,KAAK,EAA4B,CAAC,CACxD,CAAC;IAEJ,uBAAA,IAAI,wCAAwB,sBAAsB,EAAE;SACjD,IAAI,CACH,IAAA,gCAAoB,EAClB,CAAC,CAAyB,EAAE,CAAyB,EAAE,EAAE,CACvD,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,CAC9B,CACF;SACA,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;QACnB,uBAAA,IAAI,gCAAgB,KAAK,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,sCAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC,CAAC,MAAA,CAAC;AACP,CAAC","sourcesContent":["import {\n CloseAppCommand,\n DeviceActionStatus,\n DeviceManagementKitBuilder,\n DeviceStatus,\n GetAppAndVersionCommand,\n isSuccessCommandResult,\n OpenAppCommand,\n} from '@ledgerhq/device-management-kit';\nimport type {\n DeviceActionState,\n DeviceManagementKit,\n} from '@ledgerhq/device-management-kit';\nimport type { Signature } from '@ledgerhq/device-signer-kit-ethereum';\nimport type Transport from '@ledgerhq/hw-transport';\nimport type { Observable } from 'rxjs';\nimport {\n concat,\n defer,\n firstValueFrom,\n of,\n Subject,\n Subscription,\n timer,\n} from 'rxjs';\nimport {\n catchError,\n distinctUntilChanged,\n endWith,\n filter,\n map,\n switchMap,\n} from 'rxjs/operators';\n\nimport {\n AppConfigurationResponse,\n GetAppNameAndVersionResponse,\n GetPublicKeyParams,\n GetPublicKeyResponse,\n LedgerBridge,\n LedgerSignDelegationAuthorizationParams,\n LedgerSignDelegationAuthorizationResponse,\n LedgerSignMessageParams,\n LedgerSignMessageResponse,\n LedgerSignTransactionParams,\n LedgerSignTransactionResponse,\n LedgerSignTypedDataParams,\n LedgerSignTypedDataResponse,\n} from '../ledger-bridge';\nimport {\n isDeviceExchangeError,\n translateDmkError,\n} from './dmk-error-translator';\nimport { EthGetAppConfigurationCommand } from './eth-get-app-configuration-command';\nimport {\n hexToBytes,\n stripHexPrefix,\n stripPathPrefix,\n toHexString,\n} from './internal-utils';\nimport { LedgerDmkTransportMiddleware } from './ledger-dmk-transport-middleware';\n\nexport type LedgerDmkBridgeOptions = {\n transportFactory: Parameters<DeviceManagementKitBuilder['addTransport']>[0];\n};\n\ntype PublicKeyOutput = Pick<\n GetPublicKeyResponse,\n 'address' | 'chainCode' | 'publicKey'\n>;\n\n/**\n * LedgerDmkBridge is a bridge between the LedgerKeyring and the\n * LedgerDmkTransportMiddleware.\n * It initializes and manages the DeviceManagementKit internally.\n * The transport factory is injected via constructor, making it platform-agnostic.\n */\nexport class LedgerDmkBridge implements LedgerBridge<LedgerDmkBridgeOptions> {\n readonly #transportMiddleware: LedgerDmkTransportMiddleware;\n\n readonly #sdk: DeviceManagementKit;\n\n #opts: LedgerDmkBridgeOptions;\n\n #isConnected = false;\n\n #sessionState$ = new Subject<{ connected: boolean }>();\n\n get onSessionStateChange(): Observable<{ connected: boolean }> {\n return this.#sessionState$.asObservable();\n }\n\n #sessionSubscription: Subscription | null = null;\n\n get isDeviceConnected(): boolean {\n return this.#isConnected;\n }\n\n constructor(opts: LedgerDmkBridgeOptions) {\n this.#sdk = new DeviceManagementKitBuilder()\n .addTransport(opts.transportFactory)\n .build();\n this.#opts = opts;\n this.#transportMiddleware = new LedgerDmkTransportMiddleware(this.#sdk);\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * DMK session setup happens externally via `updateSessionId` or `connect`,\n * so this method is a no-op.\n *\n * @returns A promise that resolves immediately.\n */\n async init(): Promise<void> {\n return undefined;\n }\n\n /**\n * Destroys the bridge and cleans up resources.\n *\n * Unsubscribes session monitoring, disposes the transport middleware, and\n * completes the session-state subject so all subscribers are released. A\n * fresh subject is installed afterward so the bridge can be reconnected\n * after destroy. State cleanup happens in a `finally` block so the bridge\n * is marked disconnected even when middleware `dispose()` rejects.\n *\n * @returns A promise that resolves when cleanup is complete.\n */\n async destroy(): Promise<void> {\n this.#sessionSubscription?.unsubscribe();\n this.#sessionSubscription = null;\n\n try {\n await this.#transportMiddleware.dispose();\n } finally {\n this.#isConnected = false;\n this.#sessionState$.next({ connected: false });\n this.#sessionState$.complete();\n this.#sessionState$ = new Subject<{ connected: boolean }>();\n }\n }\n\n /**\n * Returns the bridge options captured at construction.\n *\n * Compatibility shim for the shared {@link LedgerBridge} interface. The DMK\n * bridge does not use runtime-reconfigurable options; this method exists\n * only to satisfy the interface contract.\n *\n * @returns A promise that resolves with the current bridge options.\n */\n async getOptions(): Promise<LedgerDmkBridgeOptions> {\n return this.#opts;\n }\n\n /**\n * Replaces the stored bridge options.\n *\n * Compatibility shim for the shared {@link LedgerBridge} interface. Stored\n * options are not re-applied to the underlying DMK instance or transport\n * middleware; the values used at construction time remain in effect.\n *\n * @param opts - The options to set for the bridge.\n * @returns A promise that resolves when options are set.\n */\n async setOptions(opts: LedgerDmkBridgeOptions): Promise<void> {\n this.#opts = opts;\n }\n\n /**\n * Updates the session ID used for communication.\n *\n * @param sessionId - The session ID from DMK.\n * @returns A promise that resolves with true if the session was updated successfully.\n */\n async updateSessionId(sessionId: string): Promise<boolean> {\n await this.#transportMiddleware.setSessionId(sessionId);\n this.#isConnected = true;\n this.#startSessionMonitoring(sessionId);\n return true;\n }\n\n /**\n * Starts device discovery for the configured DMK transport.\n *\n * @param args - Optional DMK discovery options.\n * @returns An observable that emits discovered devices.\n */\n startDiscovering(\n ...args: Parameters<LedgerDmkTransportMiddleware['startDiscovering']>\n ): ReturnType<LedgerDmkTransportMiddleware['startDiscovering']> {\n return this.#transportMiddleware.startDiscovering(...args);\n }\n\n /**\n * Connects to a discovered device using the configured DMK transport.\n *\n * @param args - The DMK connection arguments.\n * @returns The created session ID.\n */\n async connect(\n ...args: Parameters<LedgerDmkTransportMiddleware['connect']>\n ): ReturnType<LedgerDmkTransportMiddleware['connect']> {\n const sessionId = await this.#transportMiddleware.connect(...args);\n this.#isConnected = true;\n this.#startSessionMonitoring(sessionId);\n\n return sessionId;\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * DMK transport selection happens through the injected transport factory\n * at construction time, so this method is a no-op that always succeeds.\n *\n * @param _transportType - The requested transport type (ignored).\n * @returns A promise that resolves with `true`.\n */\n async updateTransportMethod(\n _transportType: string | Transport,\n ): Promise<boolean> {\n return true;\n }\n\n async openEthApp(): Promise<void> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command: new OpenAppCommand({ appName: 'Ethereum' }),\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n }\n\n async closeApps(): Promise<void> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command: new CloseAppCommand(),\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * The Ethereum signer kit automatically opens the Ethereum app before each\n * signing operation via DMK's `CallTaskInAppDeviceAction`, so this method\n * is a no-op that always succeeds.\n *\n * @returns A promise that resolves with `true`.\n */\n async attemptMakeApp(): Promise<boolean> {\n return true;\n }\n\n /**\n * Retrieves public key/address for a given HD path.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path to derive the public key from.\n * @returns A promise that resolves with the public key response.\n */\n async getPublicKey({\n hdPath,\n }: GetPublicKeyParams): Promise<GetPublicKeyResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .getAddress(stripPathPrefix(hdPath), {\n checkOnDevice: false,\n returnChainCode: true,\n });\n const response =\n await this.#waitForDeviceAction<PublicKeyOutput>(observable);\n\n return {\n publicKey: response.publicKey,\n address: response.address,\n chainCode: response.chainCode,\n };\n }\n\n /**\n * Signs an Ethereum transaction.\n *\n * @param options0 - The parameters object.\n * @param options0.tx - The transaction hex string to sign.\n * @param options0.hdPath - The HD path for signing.\n * @returns A promise that resolves with the transaction signature.\n */\n async deviceSignTransaction({\n tx,\n hdPath,\n }: LedgerSignTransactionParams): Promise<LedgerSignTransactionResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signTransaction(stripPathPrefix(hdPath), hexToBytes(tx));\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: toHexString(signature.v),\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Signs a personal message.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path for signing.\n * @param options0.message - The message to sign.\n * @returns A promise that resolves with the message signature.\n */\n async deviceSignMessage({\n hdPath,\n message,\n }: LedgerSignMessageParams): Promise<LedgerSignMessageResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signMessage(stripPathPrefix(hdPath), hexToBytes(message));\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: signature.v,\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Signs EIP-712 typed data.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path for signing.\n * @param options0.message - The typed data message to sign.\n * @returns A promise that resolves with the typed data signature.\n */\n async deviceSignTypedData({\n hdPath,\n message,\n }: LedgerSignTypedDataParams): Promise<LedgerSignTypedDataResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signTypedData(stripPathPrefix(hdPath), message);\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: signature.v,\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n async deviceSignDelegationAuthorization({\n hdPath,\n chainId,\n contractAddress,\n nonce,\n }: LedgerSignDelegationAuthorizationParams): Promise<LedgerSignDelegationAuthorizationResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signDelegationAuthorization(\n stripPathPrefix(hdPath),\n chainId,\n contractAddress,\n nonce,\n );\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: toHexString(signature.v),\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Retrieves the current app name and version.\n *\n * @returns A promise that resolves with the app name and version.\n */\n async getAppNameAndVersion(): Promise<GetAppNameAndVersionResponse> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const command = new GetAppAndVersionCommand();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command,\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n\n return {\n appName: result.data.name,\n version: result.data.version,\n };\n }\n\n /**\n * Retrieves the Ethereum app configuration using the eth-specific\n * GetAppConfiguration APDU command (CLA 0xE0, INS 0x06).\n *\n * @returns A promise that resolves with the app configuration.\n */\n async getAppConfiguration(): Promise<AppConfigurationResponse> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const command = new EthGetAppConfigurationCommand();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command,\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n\n const { data } = result;\n\n // The `ethapp.adoc` spec for `getAppConfiguration`\n // (https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.adoc#get-app-configuration)\n // defines four flag bits. This bridge only consumes three (blind signing,\n // web3 checks enabled, web3 checks opt-in). The fourth — `0x02` *ERC 20\n // Token information needs to be provided externally* — is intentionally\n // mapped to `erc20ProvisioningNecessary: 0` because the rest of the\n // keyring does not implement the `PROVIDE ERC 20 TOKEN INFORMATION`\n // provisioning flow.\n //\n // TODO: The shared `AppConfigurationResponse` interface also requires\n // `starkEnabled` and `starkv2Supported`, which are not exposed by the\n // `getAppConfiguration` APDU at all. They are stubbed to 0 to satisfy\n // the interface contract.\n return {\n arbitraryDataEnabled: data.blindSigningEnabled ? 1 : 0,\n erc20ProvisioningNecessary: 0,\n starkEnabled: 0,\n starkv2Supported: 0,\n version: data.version,\n };\n }\n\n async #waitForDeviceAction<TOutput>(\n observable: Observable<DeviceActionState<TOutput, unknown, unknown>>,\n ): Promise<TOutput> {\n const state = await firstValueFrom(\n observable.pipe(\n catchError((error: unknown) => {\n throw translateDmkError(error);\n }),\n filter(\n ({ status }) =>\n status === DeviceActionStatus.Completed ||\n status === DeviceActionStatus.Error,\n ),\n ),\n );\n\n if (state.status === DeviceActionStatus.Completed) {\n return state.output;\n }\n\n if (state.status === DeviceActionStatus.Error) {\n throw translateDmkError(state.error);\n }\n\n // Unreachable: the filter above only lets Completed or Error states\n // through. Defensive guard retained for type safety.\n throw new Error('Ledger device action ended without completion.');\n }\n\n #toError(error: unknown): Error {\n if (isDeviceExchangeError(error)) {\n return translateDmkError(error);\n }\n\n if (error instanceof Error) {\n return error;\n }\n\n return new Error('Ledger command failed.');\n }\n\n /**\n * Monitors the DMK session connection state with exponential backoff retries.\n *\n * This is necessary because the DMK does not emit disconnection events on its\n * own — the bridge must actively poll the session state to detect when a\n * Ledger device is unplugged, the Bluetooth/WUSB link drops, or the session\n * is invalidated. Without this monitoring the keyring would retain a stale\n * `isDeviceConnected = true` and subsequent signing requests would hang or\n * fail with cryptic transport errors.\n *\n * Subscribes to the device session state and emits connection changes through\n * {@link #sessionState$}. On error, retries up to 10 times with exponential\n * backoff (capped at 30 s) and emits a `connected: false` state in between\n * attempts. Once the retry limit is exhausted the stream ends with a final\n * `connected: false`. Duplicate consecutive states are suppressed via\n * `distinctUntilChanged`.\n *\n * Any previous monitoring subscription is cancelled before a new one is created.\n *\n * @param sessionId - The DMK session ID to monitor.\n */\n #startSessionMonitoring(sessionId: string): void {\n this.#sessionSubscription?.unsubscribe();\n\n const MAX_BACKOFF_MS = 30_000;\n const BASE_DELAY_MS = 1_000;\n const MAX_RETRIES = 10;\n\n const createMonitoringStream = (\n retryCount = 0,\n ): Observable<{ connected: boolean }> =>\n this.#sdk.getDeviceSessionState({ sessionId }).pipe(\n map((state) => ({\n connected: state.deviceStatus !== DeviceStatus.NOT_CONNECTED,\n })),\n catchError(() => {\n if (retryCount >= MAX_RETRIES) {\n return of({ connected: false });\n }\n const delay = Math.min(\n BASE_DELAY_MS * 2 ** retryCount,\n MAX_BACKOFF_MS,\n );\n return concat(\n of({ connected: false }),\n defer(() =>\n timer(delay).pipe(\n switchMap(() => createMonitoringStream(retryCount + 1)),\n ),\n ),\n );\n }),\n endWith({ connected: false } as { connected: boolean }),\n );\n\n this.#sessionSubscription = createMonitoringStream()\n .pipe(\n distinctUntilChanged(\n (a: { connected: boolean }, b: { connected: boolean }) =>\n a.connected === b.connected,\n ),\n )\n .subscribe((state) => {\n this.#isConnected = state.connected;\n this.#sessionState$.next(state);\n });\n }\n}\n"]}
1
+ {"version":3,"file":"ledger-dmk-bridge.cjs","sourceRoot":"","sources":["../../src/dmk/ledger-dmk-bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CloseAppCommand,\n DeviceActionStatus,\n DeviceManagementKitBuilder,\n DeviceStatus,\n GetAppAndVersionCommand,\n isSuccessCommandResult,\n OpenAppCommand,\n} from '@ledgerhq/device-management-kit';\nimport type {\n DeviceActionState,\n DeviceManagementKit,\n} from '@ledgerhq/device-management-kit';\nimport type { Signature } from '@ledgerhq/device-signer-kit-ethereum';\nimport type Transport from '@ledgerhq/hw-transport';\nimport { getDMKErrorFromTag } from '@metamask/hw-wallet-sdk';\nimport type { Observable } from 'rxjs';\nimport {\n concat,\n defer,\n firstValueFrom,\n of,\n Subject,\n Subscription,\n timer,\n} from 'rxjs';\nimport {\n catchError,\n distinctUntilChanged,\n endWith,\n filter,\n map,\n switchMap,\n} from 'rxjs/operators';\n\nimport { createDMKError } from '../errors';\nimport {\n AppConfigurationResponse,\n GetAppNameAndVersionResponse,\n GetPublicKeyParams,\n GetPublicKeyResponse,\n LedgerBridge,\n LedgerSignDelegationAuthorizationParams,\n LedgerSignDelegationAuthorizationResponse,\n LedgerSignMessageParams,\n LedgerSignMessageResponse,\n LedgerSignTransactionParams,\n LedgerSignTransactionResponse,\n LedgerSignTypedDataParams,\n LedgerSignTypedDataResponse,\n} from '../ledger-bridge';\nimport {\n isDeviceExchangeError,\n translateDmkError,\n} from './dmk-error-translator';\nimport { EthGetAppConfigurationCommand } from './eth-get-app-configuration-command';\nimport {\n hexToBytes,\n stripHexPrefix,\n stripPathPrefix,\n toHexString,\n} from './internal-utils';\nimport { LedgerDmkTransportMiddleware } from './ledger-dmk-transport-middleware';\n\nexport type LedgerDmkBridgeOptions = {\n transportFactory: Parameters<DeviceManagementKitBuilder['addTransport']>[0];\n};\n\ntype PublicKeyOutput = Pick<\n GetPublicKeyResponse,\n 'address' | 'chainCode' | 'publicKey'\n>;\n\n/**\n * LedgerDmkBridge is a bridge between the LedgerKeyring and the\n * LedgerDmkTransportMiddleware.\n * It initializes and manages the DeviceManagementKit internally.\n * The transport factory is injected via constructor, making it platform-agnostic.\n */\nexport class LedgerDmkBridge implements LedgerBridge<LedgerDmkBridgeOptions> {\n readonly #transportMiddleware: LedgerDmkTransportMiddleware;\n\n readonly #sdk: DeviceManagementKit;\n\n #opts: LedgerDmkBridgeOptions;\n\n #isConnected = false;\n\n #sessionState$ = new Subject<{ connected: boolean }>();\n\n get onSessionStateChange(): Observable<{ connected: boolean }> {\n return this.#sessionState$.asObservable();\n }\n\n #sessionSubscription: Subscription | null = null;\n\n get isDeviceConnected(): boolean {\n return this.#isConnected;\n }\n\n constructor(opts: LedgerDmkBridgeOptions) {\n this.#sdk = new DeviceManagementKitBuilder()\n .addTransport(opts.transportFactory)\n .build();\n this.#opts = opts;\n this.#transportMiddleware = new LedgerDmkTransportMiddleware(this.#sdk);\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * DMK session setup happens externally via `updateSessionId` or `connect`,\n * so this method is a no-op.\n *\n * @returns A promise that resolves immediately.\n */\n async init(): Promise<void> {\n return undefined;\n }\n\n /**\n * Destroys the bridge and cleans up resources.\n *\n * Unsubscribes session monitoring, disposes the transport middleware, and\n * completes the session-state subject so all subscribers are released. A\n * fresh subject is installed afterward so the bridge can be reconnected\n * after destroy. State cleanup happens in a `finally` block so the bridge\n * is marked disconnected even when middleware `dispose()` rejects.\n *\n * @returns A promise that resolves when cleanup is complete.\n */\n async destroy(): Promise<void> {\n this.#sessionSubscription?.unsubscribe();\n this.#sessionSubscription = null;\n\n try {\n await this.#transportMiddleware.dispose();\n } finally {\n this.#isConnected = false;\n this.#sessionState$.next({ connected: false });\n this.#sessionState$.complete();\n this.#sessionState$ = new Subject<{ connected: boolean }>();\n }\n }\n\n /**\n * Returns the bridge options captured at construction.\n *\n * Compatibility shim for the shared {@link LedgerBridge} interface. The DMK\n * bridge does not use runtime-reconfigurable options; this method exists\n * only to satisfy the interface contract.\n *\n * @returns A promise that resolves with the current bridge options.\n */\n async getOptions(): Promise<LedgerDmkBridgeOptions> {\n return this.#opts;\n }\n\n /**\n * Replaces the stored bridge options.\n *\n * Compatibility shim for the shared {@link LedgerBridge} interface. Stored\n * options are not re-applied to the underlying DMK instance or transport\n * middleware; the values used at construction time remain in effect.\n *\n * @param opts - The options to set for the bridge.\n * @returns A promise that resolves when options are set.\n */\n async setOptions(opts: LedgerDmkBridgeOptions): Promise<void> {\n this.#opts = opts;\n }\n\n /**\n * Updates the session ID used for communication.\n *\n * @param sessionId - The session ID from DMK.\n * @returns A promise that resolves with true if the session was updated successfully.\n */\n async updateSessionId(sessionId: string): Promise<boolean> {\n await this.#transportMiddleware.setSessionId(sessionId);\n this.#isConnected = true;\n this.#startSessionMonitoring(sessionId);\n return true;\n }\n\n /**\n * Starts device discovery for the configured DMK transport.\n *\n * @param args - Optional DMK discovery options.\n * @returns An observable that emits discovered devices.\n */\n startDiscovering(\n ...args: Parameters<LedgerDmkTransportMiddleware['startDiscovering']>\n ): ReturnType<LedgerDmkTransportMiddleware['startDiscovering']> {\n return this.#transportMiddleware.startDiscovering(...args);\n }\n\n /**\n * Connects to a discovered device using the configured DMK transport.\n *\n * @param args - The DMK connection arguments.\n * @returns The created session ID.\n */\n async connect(\n ...args: Parameters<LedgerDmkTransportMiddleware['connect']>\n ): ReturnType<LedgerDmkTransportMiddleware['connect']> {\n const sessionId = await this.#transportMiddleware.connect(...args);\n this.#isConnected = true;\n this.#startSessionMonitoring(sessionId);\n\n return sessionId;\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * DMK transport selection happens through the injected transport factory\n * at construction time, so this method is a no-op that always succeeds.\n *\n * @param _transportType - The requested transport type (ignored).\n * @returns A promise that resolves with `true`.\n */\n async updateTransportMethod(\n _transportType: string | Transport,\n ): Promise<boolean> {\n return true;\n }\n\n async openEthApp(): Promise<void> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command: new OpenAppCommand({ appName: 'Ethereum' }),\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n }\n\n async closeApps(): Promise<void> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command: new CloseAppCommand(),\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * The Ethereum signer kit automatically opens the Ethereum app before each\n * signing operation via DMK's `CallTaskInAppDeviceAction`, so this method\n * is a no-op that always succeeds.\n *\n * @returns A promise that resolves with `true`.\n */\n async attemptMakeApp(): Promise<boolean> {\n return true;\n }\n\n /**\n * Retrieves public key/address for a given HD path.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path to derive the public key from.\n * @returns A promise that resolves with the public key response.\n */\n async getPublicKey({\n hdPath,\n }: GetPublicKeyParams): Promise<GetPublicKeyResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .getAddress(stripPathPrefix(hdPath), {\n checkOnDevice: false,\n returnChainCode: true,\n });\n const response =\n await this.#waitForDeviceAction<PublicKeyOutput>(observable);\n\n return {\n publicKey: response.publicKey,\n address: response.address,\n chainCode: response.chainCode,\n };\n }\n\n /**\n * Signs an Ethereum transaction.\n *\n * @param options0 - The parameters object.\n * @param options0.tx - The transaction hex string to sign.\n * @param options0.hdPath - The HD path for signing.\n * @returns A promise that resolves with the transaction signature.\n */\n async deviceSignTransaction({\n tx,\n hdPath,\n }: LedgerSignTransactionParams): Promise<LedgerSignTransactionResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signTransaction(stripPathPrefix(hdPath), hexToBytes(tx));\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: toHexString(signature.v),\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Signs a personal message.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path for signing.\n * @param options0.message - The message to sign.\n * @returns A promise that resolves with the message signature.\n */\n async deviceSignMessage({\n hdPath,\n message,\n }: LedgerSignMessageParams): Promise<LedgerSignMessageResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signMessage(stripPathPrefix(hdPath), hexToBytes(message));\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: signature.v,\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Signs EIP-712 typed data.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path for signing.\n * @param options0.message - The typed data message to sign.\n * @returns A promise that resolves with the typed data signature.\n */\n async deviceSignTypedData({\n hdPath,\n message,\n }: LedgerSignTypedDataParams): Promise<LedgerSignTypedDataResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signTypedData(stripPathPrefix(hdPath), message);\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: signature.v,\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n async deviceSignDelegationAuthorization({\n hdPath,\n chainId,\n contractAddress,\n nonce,\n }: LedgerSignDelegationAuthorizationParams): Promise<LedgerSignDelegationAuthorizationResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signDelegationAuthorization(\n stripPathPrefix(hdPath),\n chainId,\n contractAddress,\n nonce,\n );\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: toHexString(signature.v),\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Retrieves the current app name and version.\n *\n * @returns A promise that resolves with the app name and version.\n */\n async getAppNameAndVersion(): Promise<GetAppNameAndVersionResponse> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const command = new GetAppAndVersionCommand();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command,\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n\n return {\n appName: result.data.name,\n version: result.data.version,\n };\n }\n\n /**\n * Retrieves the Ethereum app configuration using the eth-specific\n * GetAppConfiguration APDU command (CLA 0xE0, INS 0x06).\n *\n * @returns A promise that resolves with the app configuration.\n */\n async getAppConfiguration(): Promise<AppConfigurationResponse> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const command = new EthGetAppConfigurationCommand();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command,\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n\n const { data } = result;\n\n // The `ethapp.adoc` spec for `getAppConfiguration`\n // (https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.adoc#get-app-configuration)\n // defines four flag bits. This bridge only consumes three (blind signing,\n // web3 checks enabled, web3 checks opt-in). The fourth — `0x02` *ERC 20\n // Token information needs to be provided externally* — is intentionally\n // mapped to `erc20ProvisioningNecessary: 0` because the rest of the\n // keyring does not implement the `PROVIDE ERC 20 TOKEN INFORMATION`\n // provisioning flow.\n //\n // TODO: The shared `AppConfigurationResponse` interface also requires\n // `starkEnabled` and `starkv2Supported`, which are not exposed by the\n // `getAppConfiguration` APDU at all. They are stubbed to 0 to satisfy\n // the interface contract.\n return {\n arbitraryDataEnabled: data.blindSigningEnabled ? 1 : 0,\n erc20ProvisioningNecessary: 0,\n starkEnabled: 0,\n starkv2Supported: 0,\n version: data.version,\n };\n }\n\n async #waitForDeviceAction<TOutput>(\n observable: Observable<DeviceActionState<TOutput, unknown, unknown>>,\n ): Promise<TOutput> {\n const state = await firstValueFrom(\n observable.pipe(\n catchError((error: unknown) => {\n throw translateDmkError(error);\n }),\n filter(\n ({ status }) =>\n status === DeviceActionStatus.Completed ||\n status === DeviceActionStatus.Error,\n ),\n ),\n );\n\n if (state.status === DeviceActionStatus.Completed) {\n return state.output;\n }\n\n if (state.status === DeviceActionStatus.Error) {\n throw translateDmkError(state.error);\n }\n\n // Unreachable: the filter above only lets Completed or Error states\n // through. Defensive guard retained for type safety.\n throw new Error('Ledger device action ended without completion.');\n }\n\n #toError(error: unknown): Error {\n // DMK connection/session errors identified by _tag (e.g.\n // DeviceSessionNotFound, DeviceLockedError) carry no hex APDU code.\n // Resolve them to a HardwareWalletError before falling through.\n const tagResolution = getDMKErrorFromTag(error);\n if (tagResolution) {\n return createDMKError(tagResolution.tag);\n }\n\n if (isDeviceExchangeError(error)) {\n return translateDmkError(error);\n }\n\n if (error instanceof Error) {\n return error;\n }\n\n return new Error('Ledger command failed.');\n }\n\n /**\n * Monitors the DMK session connection state with exponential backoff retries.\n *\n * This is necessary because the DMK does not emit disconnection events on its\n * own — the bridge must actively poll the session state to detect when a\n * Ledger device is unplugged, the Bluetooth/WUSB link drops, or the session\n * is invalidated. Without this monitoring the keyring would retain a stale\n * `isDeviceConnected = true` and subsequent signing requests would hang or\n * fail with cryptic transport errors.\n *\n * Subscribes to the device session state and emits connection changes through\n * {@link #sessionState$}. On error, retries up to 10 times with exponential\n * backoff (capped at 30 s) and emits a `connected: false` state in between\n * attempts. Once the retry limit is exhausted the stream ends with a final\n * `connected: false`. Duplicate consecutive states are suppressed via\n * `distinctUntilChanged`.\n *\n * Any previous monitoring subscription is cancelled before a new one is created.\n *\n * @param sessionId - The DMK session ID to monitor.\n */\n #startSessionMonitoring(sessionId: string): void {\n this.#sessionSubscription?.unsubscribe();\n\n const MAX_BACKOFF_MS = 30_000;\n const BASE_DELAY_MS = 1_000;\n const MAX_RETRIES = 10;\n\n const createMonitoringStream = (\n retryCount = 0,\n ): Observable<{ connected: boolean }> =>\n this.#sdk.getDeviceSessionState({ sessionId }).pipe(\n map((state) => ({\n connected: state.deviceStatus !== DeviceStatus.NOT_CONNECTED,\n })),\n catchError(() => {\n if (retryCount >= MAX_RETRIES) {\n return of({ connected: false });\n }\n const delay = Math.min(\n BASE_DELAY_MS * 2 ** retryCount,\n MAX_BACKOFF_MS,\n );\n return concat(\n of({ connected: false }),\n defer(() =>\n timer(delay).pipe(\n switchMap(() => createMonitoringStream(retryCount + 1)),\n ),\n ),\n );\n }),\n endWith({ connected: false } as { connected: boolean }),\n );\n\n this.#sessionSubscription = createMonitoringStream()\n .pipe(\n distinctUntilChanged(\n (a: { connected: boolean }, b: { connected: boolean }) =>\n a.connected === b.connected,\n ),\n )\n .subscribe((state) => {\n this.#isConnected = state.connected;\n this.#sessionState$.next(state);\n });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-dmk-bridge.d.cts","sourceRoot":"","sources":["../../src/dmk/ledger-dmk-bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ledger-dmk-bridge.d.cts","sourceRoot":"","sources":["../../src/dmk/ledger-dmk-bridge.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-dmk-bridge.d.mts","sourceRoot":"","sources":["../../src/dmk/ledger-dmk-bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ledger-dmk-bridge.d.mts","sourceRoot":"","sources":["../../src/dmk/ledger-dmk-bridge.ts"],"names":[],"mappings":"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"}
@@ -11,8 +11,10 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
11
11
  };
12
12
  var _LedgerDmkBridge_instances, _LedgerDmkBridge_transportMiddleware, _LedgerDmkBridge_sdk, _LedgerDmkBridge_opts, _LedgerDmkBridge_isConnected, _LedgerDmkBridge_sessionState$, _LedgerDmkBridge_sessionSubscription, _LedgerDmkBridge_waitForDeviceAction, _LedgerDmkBridge_toError, _LedgerDmkBridge_startSessionMonitoring;
13
13
  import { CloseAppCommand, DeviceActionStatus, DeviceManagementKitBuilder, DeviceStatus, GetAppAndVersionCommand, isSuccessCommandResult, OpenAppCommand } from "@ledgerhq/device-management-kit";
14
+ import { getDMKErrorFromTag } from "@metamask/hw-wallet-sdk";
14
15
  import { concat, defer, firstValueFrom, of, Subject, Subscription, timer } from "rxjs";
15
16
  import { catchError, distinctUntilChanged, endWith, filter, map, switchMap } from "rxjs/operators";
17
+ import { createDMKError } from "../errors.mjs";
16
18
  import { isDeviceExchangeError, translateDmkError } from "./dmk-error-translator.mjs";
17
19
  import { EthGetAppConfigurationCommand } from "./eth-get-app-configuration-command.mjs";
18
20
  import { hexToBytes, stripHexPrefix, stripPathPrefix, toHexString } from "./internal-utils.mjs";
@@ -344,6 +346,13 @@ _LedgerDmkBridge_transportMiddleware = new WeakMap(), _LedgerDmkBridge_sdk = new
344
346
  // through. Defensive guard retained for type safety.
345
347
  throw new Error('Ledger device action ended without completion.');
346
348
  }, _LedgerDmkBridge_toError = function _LedgerDmkBridge_toError(error) {
349
+ // DMK connection/session errors identified by _tag (e.g.
350
+ // DeviceSessionNotFound, DeviceLockedError) carry no hex APDU code.
351
+ // Resolve them to a HardwareWalletError before falling through.
352
+ const tagResolution = getDMKErrorFromTag(error);
353
+ if (tagResolution) {
354
+ return createDMKError(tagResolution.tag);
355
+ }
347
356
  if (isDeviceExchangeError(error)) {
348
357
  return translateDmkError(error);
349
358
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-dmk-bridge.mjs","sourceRoot":"","sources":["../../src/dmk/ledger-dmk-bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CloseAppCommand,\n DeviceActionStatus,\n DeviceManagementKitBuilder,\n DeviceStatus,\n GetAppAndVersionCommand,\n isSuccessCommandResult,\n OpenAppCommand,\n} from '@ledgerhq/device-management-kit';\nimport type {\n DeviceActionState,\n DeviceManagementKit,\n} from '@ledgerhq/device-management-kit';\nimport type { Signature } from '@ledgerhq/device-signer-kit-ethereum';\nimport type Transport from '@ledgerhq/hw-transport';\nimport type { Observable } from 'rxjs';\nimport {\n concat,\n defer,\n firstValueFrom,\n of,\n Subject,\n Subscription,\n timer,\n} from 'rxjs';\nimport {\n catchError,\n distinctUntilChanged,\n endWith,\n filter,\n map,\n switchMap,\n} from 'rxjs/operators';\n\nimport {\n AppConfigurationResponse,\n GetAppNameAndVersionResponse,\n GetPublicKeyParams,\n GetPublicKeyResponse,\n LedgerBridge,\n LedgerSignDelegationAuthorizationParams,\n LedgerSignDelegationAuthorizationResponse,\n LedgerSignMessageParams,\n LedgerSignMessageResponse,\n LedgerSignTransactionParams,\n LedgerSignTransactionResponse,\n LedgerSignTypedDataParams,\n LedgerSignTypedDataResponse,\n} from '../ledger-bridge';\nimport {\n isDeviceExchangeError,\n translateDmkError,\n} from './dmk-error-translator';\nimport { EthGetAppConfigurationCommand } from './eth-get-app-configuration-command';\nimport {\n hexToBytes,\n stripHexPrefix,\n stripPathPrefix,\n toHexString,\n} from './internal-utils';\nimport { LedgerDmkTransportMiddleware } from './ledger-dmk-transport-middleware';\n\nexport type LedgerDmkBridgeOptions = {\n transportFactory: Parameters<DeviceManagementKitBuilder['addTransport']>[0];\n};\n\ntype PublicKeyOutput = Pick<\n GetPublicKeyResponse,\n 'address' | 'chainCode' | 'publicKey'\n>;\n\n/**\n * LedgerDmkBridge is a bridge between the LedgerKeyring and the\n * LedgerDmkTransportMiddleware.\n * It initializes and manages the DeviceManagementKit internally.\n * The transport factory is injected via constructor, making it platform-agnostic.\n */\nexport class LedgerDmkBridge implements LedgerBridge<LedgerDmkBridgeOptions> {\n readonly #transportMiddleware: LedgerDmkTransportMiddleware;\n\n readonly #sdk: DeviceManagementKit;\n\n #opts: LedgerDmkBridgeOptions;\n\n #isConnected = false;\n\n #sessionState$ = new Subject<{ connected: boolean }>();\n\n get onSessionStateChange(): Observable<{ connected: boolean }> {\n return this.#sessionState$.asObservable();\n }\n\n #sessionSubscription: Subscription | null = null;\n\n get isDeviceConnected(): boolean {\n return this.#isConnected;\n }\n\n constructor(opts: LedgerDmkBridgeOptions) {\n this.#sdk = new DeviceManagementKitBuilder()\n .addTransport(opts.transportFactory)\n .build();\n this.#opts = opts;\n this.#transportMiddleware = new LedgerDmkTransportMiddleware(this.#sdk);\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * DMK session setup happens externally via `updateSessionId` or `connect`,\n * so this method is a no-op.\n *\n * @returns A promise that resolves immediately.\n */\n async init(): Promise<void> {\n return undefined;\n }\n\n /**\n * Destroys the bridge and cleans up resources.\n *\n * Unsubscribes session monitoring, disposes the transport middleware, and\n * completes the session-state subject so all subscribers are released. A\n * fresh subject is installed afterward so the bridge can be reconnected\n * after destroy. State cleanup happens in a `finally` block so the bridge\n * is marked disconnected even when middleware `dispose()` rejects.\n *\n * @returns A promise that resolves when cleanup is complete.\n */\n async destroy(): Promise<void> {\n this.#sessionSubscription?.unsubscribe();\n this.#sessionSubscription = null;\n\n try {\n await this.#transportMiddleware.dispose();\n } finally {\n this.#isConnected = false;\n this.#sessionState$.next({ connected: false });\n this.#sessionState$.complete();\n this.#sessionState$ = new Subject<{ connected: boolean }>();\n }\n }\n\n /**\n * Returns the bridge options captured at construction.\n *\n * Compatibility shim for the shared {@link LedgerBridge} interface. The DMK\n * bridge does not use runtime-reconfigurable options; this method exists\n * only to satisfy the interface contract.\n *\n * @returns A promise that resolves with the current bridge options.\n */\n async getOptions(): Promise<LedgerDmkBridgeOptions> {\n return this.#opts;\n }\n\n /**\n * Replaces the stored bridge options.\n *\n * Compatibility shim for the shared {@link LedgerBridge} interface. Stored\n * options are not re-applied to the underlying DMK instance or transport\n * middleware; the values used at construction time remain in effect.\n *\n * @param opts - The options to set for the bridge.\n * @returns A promise that resolves when options are set.\n */\n async setOptions(opts: LedgerDmkBridgeOptions): Promise<void> {\n this.#opts = opts;\n }\n\n /**\n * Updates the session ID used for communication.\n *\n * @param sessionId - The session ID from DMK.\n * @returns A promise that resolves with true if the session was updated successfully.\n */\n async updateSessionId(sessionId: string): Promise<boolean> {\n await this.#transportMiddleware.setSessionId(sessionId);\n this.#isConnected = true;\n this.#startSessionMonitoring(sessionId);\n return true;\n }\n\n /**\n * Starts device discovery for the configured DMK transport.\n *\n * @param args - Optional DMK discovery options.\n * @returns An observable that emits discovered devices.\n */\n startDiscovering(\n ...args: Parameters<LedgerDmkTransportMiddleware['startDiscovering']>\n ): ReturnType<LedgerDmkTransportMiddleware['startDiscovering']> {\n return this.#transportMiddleware.startDiscovering(...args);\n }\n\n /**\n * Connects to a discovered device using the configured DMK transport.\n *\n * @param args - The DMK connection arguments.\n * @returns The created session ID.\n */\n async connect(\n ...args: Parameters<LedgerDmkTransportMiddleware['connect']>\n ): ReturnType<LedgerDmkTransportMiddleware['connect']> {\n const sessionId = await this.#transportMiddleware.connect(...args);\n this.#isConnected = true;\n this.#startSessionMonitoring(sessionId);\n\n return sessionId;\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * DMK transport selection happens through the injected transport factory\n * at construction time, so this method is a no-op that always succeeds.\n *\n * @param _transportType - The requested transport type (ignored).\n * @returns A promise that resolves with `true`.\n */\n async updateTransportMethod(\n _transportType: string | Transport,\n ): Promise<boolean> {\n return true;\n }\n\n async openEthApp(): Promise<void> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command: new OpenAppCommand({ appName: 'Ethereum' }),\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n }\n\n async closeApps(): Promise<void> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command: new CloseAppCommand(),\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * The Ethereum signer kit automatically opens the Ethereum app before each\n * signing operation via DMK's `CallTaskInAppDeviceAction`, so this method\n * is a no-op that always succeeds.\n *\n * @returns A promise that resolves with `true`.\n */\n async attemptMakeApp(): Promise<boolean> {\n return true;\n }\n\n /**\n * Retrieves public key/address for a given HD path.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path to derive the public key from.\n * @returns A promise that resolves with the public key response.\n */\n async getPublicKey({\n hdPath,\n }: GetPublicKeyParams): Promise<GetPublicKeyResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .getAddress(stripPathPrefix(hdPath), {\n checkOnDevice: false,\n returnChainCode: true,\n });\n const response =\n await this.#waitForDeviceAction<PublicKeyOutput>(observable);\n\n return {\n publicKey: response.publicKey,\n address: response.address,\n chainCode: response.chainCode,\n };\n }\n\n /**\n * Signs an Ethereum transaction.\n *\n * @param options0 - The parameters object.\n * @param options0.tx - The transaction hex string to sign.\n * @param options0.hdPath - The HD path for signing.\n * @returns A promise that resolves with the transaction signature.\n */\n async deviceSignTransaction({\n tx,\n hdPath,\n }: LedgerSignTransactionParams): Promise<LedgerSignTransactionResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signTransaction(stripPathPrefix(hdPath), hexToBytes(tx));\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: toHexString(signature.v),\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Signs a personal message.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path for signing.\n * @param options0.message - The message to sign.\n * @returns A promise that resolves with the message signature.\n */\n async deviceSignMessage({\n hdPath,\n message,\n }: LedgerSignMessageParams): Promise<LedgerSignMessageResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signMessage(stripPathPrefix(hdPath), hexToBytes(message));\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: signature.v,\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Signs EIP-712 typed data.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path for signing.\n * @param options0.message - The typed data message to sign.\n * @returns A promise that resolves with the typed data signature.\n */\n async deviceSignTypedData({\n hdPath,\n message,\n }: LedgerSignTypedDataParams): Promise<LedgerSignTypedDataResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signTypedData(stripPathPrefix(hdPath), message);\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: signature.v,\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n async deviceSignDelegationAuthorization({\n hdPath,\n chainId,\n contractAddress,\n nonce,\n }: LedgerSignDelegationAuthorizationParams): Promise<LedgerSignDelegationAuthorizationResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signDelegationAuthorization(\n stripPathPrefix(hdPath),\n chainId,\n contractAddress,\n nonce,\n );\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: toHexString(signature.v),\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Retrieves the current app name and version.\n *\n * @returns A promise that resolves with the app name and version.\n */\n async getAppNameAndVersion(): Promise<GetAppNameAndVersionResponse> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const command = new GetAppAndVersionCommand();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command,\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n\n return {\n appName: result.data.name,\n version: result.data.version,\n };\n }\n\n /**\n * Retrieves the Ethereum app configuration using the eth-specific\n * GetAppConfiguration APDU command (CLA 0xE0, INS 0x06).\n *\n * @returns A promise that resolves with the app configuration.\n */\n async getAppConfiguration(): Promise<AppConfigurationResponse> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const command = new EthGetAppConfigurationCommand();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command,\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n\n const { data } = result;\n\n // The `ethapp.adoc` spec for `getAppConfiguration`\n // (https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.adoc#get-app-configuration)\n // defines four flag bits. This bridge only consumes three (blind signing,\n // web3 checks enabled, web3 checks opt-in). The fourth — `0x02` *ERC 20\n // Token information needs to be provided externally* — is intentionally\n // mapped to `erc20ProvisioningNecessary: 0` because the rest of the\n // keyring does not implement the `PROVIDE ERC 20 TOKEN INFORMATION`\n // provisioning flow.\n //\n // TODO: The shared `AppConfigurationResponse` interface also requires\n // `starkEnabled` and `starkv2Supported`, which are not exposed by the\n // `getAppConfiguration` APDU at all. They are stubbed to 0 to satisfy\n // the interface contract.\n return {\n arbitraryDataEnabled: data.blindSigningEnabled ? 1 : 0,\n erc20ProvisioningNecessary: 0,\n starkEnabled: 0,\n starkv2Supported: 0,\n version: data.version,\n };\n }\n\n async #waitForDeviceAction<TOutput>(\n observable: Observable<DeviceActionState<TOutput, unknown, unknown>>,\n ): Promise<TOutput> {\n const state = await firstValueFrom(\n observable.pipe(\n catchError((error: unknown) => {\n throw translateDmkError(error);\n }),\n filter(\n ({ status }) =>\n status === DeviceActionStatus.Completed ||\n status === DeviceActionStatus.Error,\n ),\n ),\n );\n\n if (state.status === DeviceActionStatus.Completed) {\n return state.output;\n }\n\n if (state.status === DeviceActionStatus.Error) {\n throw translateDmkError(state.error);\n }\n\n // Unreachable: the filter above only lets Completed or Error states\n // through. Defensive guard retained for type safety.\n throw new Error('Ledger device action ended without completion.');\n }\n\n #toError(error: unknown): Error {\n if (isDeviceExchangeError(error)) {\n return translateDmkError(error);\n }\n\n if (error instanceof Error) {\n return error;\n }\n\n return new Error('Ledger command failed.');\n }\n\n /**\n * Monitors the DMK session connection state with exponential backoff retries.\n *\n * This is necessary because the DMK does not emit disconnection events on its\n * own — the bridge must actively poll the session state to detect when a\n * Ledger device is unplugged, the Bluetooth/WUSB link drops, or the session\n * is invalidated. Without this monitoring the keyring would retain a stale\n * `isDeviceConnected = true` and subsequent signing requests would hang or\n * fail with cryptic transport errors.\n *\n * Subscribes to the device session state and emits connection changes through\n * {@link #sessionState$}. On error, retries up to 10 times with exponential\n * backoff (capped at 30 s) and emits a `connected: false` state in between\n * attempts. Once the retry limit is exhausted the stream ends with a final\n * `connected: false`. Duplicate consecutive states are suppressed via\n * `distinctUntilChanged`.\n *\n * Any previous monitoring subscription is cancelled before a new one is created.\n *\n * @param sessionId - The DMK session ID to monitor.\n */\n #startSessionMonitoring(sessionId: string): void {\n this.#sessionSubscription?.unsubscribe();\n\n const MAX_BACKOFF_MS = 30_000;\n const BASE_DELAY_MS = 1_000;\n const MAX_RETRIES = 10;\n\n const createMonitoringStream = (\n retryCount = 0,\n ): Observable<{ connected: boolean }> =>\n this.#sdk.getDeviceSessionState({ sessionId }).pipe(\n map((state) => ({\n connected: state.deviceStatus !== DeviceStatus.NOT_CONNECTED,\n })),\n catchError(() => {\n if (retryCount >= MAX_RETRIES) {\n return of({ connected: false });\n }\n const delay = Math.min(\n BASE_DELAY_MS * 2 ** retryCount,\n MAX_BACKOFF_MS,\n );\n return concat(\n of({ connected: false }),\n defer(() =>\n timer(delay).pipe(\n switchMap(() => createMonitoringStream(retryCount + 1)),\n ),\n ),\n );\n }),\n endWith({ connected: false } as { connected: boolean }),\n );\n\n this.#sessionSubscription = createMonitoringStream()\n .pipe(\n distinctUntilChanged(\n (a: { connected: boolean }, b: { connected: boolean }) =>\n a.connected === b.connected,\n ),\n )\n .subscribe((state) => {\n this.#isConnected = state.connected;\n this.#sessionState$.next(state);\n });\n }\n}\n"]}
1
+ {"version":3,"file":"ledger-dmk-bridge.mjs","sourceRoot":"","sources":["../../src/dmk/ledger-dmk-bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CloseAppCommand,\n DeviceActionStatus,\n DeviceManagementKitBuilder,\n DeviceStatus,\n GetAppAndVersionCommand,\n isSuccessCommandResult,\n OpenAppCommand,\n} from '@ledgerhq/device-management-kit';\nimport type {\n DeviceActionState,\n DeviceManagementKit,\n} from '@ledgerhq/device-management-kit';\nimport type { Signature } from '@ledgerhq/device-signer-kit-ethereum';\nimport type Transport from '@ledgerhq/hw-transport';\nimport { getDMKErrorFromTag } from '@metamask/hw-wallet-sdk';\nimport type { Observable } from 'rxjs';\nimport {\n concat,\n defer,\n firstValueFrom,\n of,\n Subject,\n Subscription,\n timer,\n} from 'rxjs';\nimport {\n catchError,\n distinctUntilChanged,\n endWith,\n filter,\n map,\n switchMap,\n} from 'rxjs/operators';\n\nimport { createDMKError } from '../errors';\nimport {\n AppConfigurationResponse,\n GetAppNameAndVersionResponse,\n GetPublicKeyParams,\n GetPublicKeyResponse,\n LedgerBridge,\n LedgerSignDelegationAuthorizationParams,\n LedgerSignDelegationAuthorizationResponse,\n LedgerSignMessageParams,\n LedgerSignMessageResponse,\n LedgerSignTransactionParams,\n LedgerSignTransactionResponse,\n LedgerSignTypedDataParams,\n LedgerSignTypedDataResponse,\n} from '../ledger-bridge';\nimport {\n isDeviceExchangeError,\n translateDmkError,\n} from './dmk-error-translator';\nimport { EthGetAppConfigurationCommand } from './eth-get-app-configuration-command';\nimport {\n hexToBytes,\n stripHexPrefix,\n stripPathPrefix,\n toHexString,\n} from './internal-utils';\nimport { LedgerDmkTransportMiddleware } from './ledger-dmk-transport-middleware';\n\nexport type LedgerDmkBridgeOptions = {\n transportFactory: Parameters<DeviceManagementKitBuilder['addTransport']>[0];\n};\n\ntype PublicKeyOutput = Pick<\n GetPublicKeyResponse,\n 'address' | 'chainCode' | 'publicKey'\n>;\n\n/**\n * LedgerDmkBridge is a bridge between the LedgerKeyring and the\n * LedgerDmkTransportMiddleware.\n * It initializes and manages the DeviceManagementKit internally.\n * The transport factory is injected via constructor, making it platform-agnostic.\n */\nexport class LedgerDmkBridge implements LedgerBridge<LedgerDmkBridgeOptions> {\n readonly #transportMiddleware: LedgerDmkTransportMiddleware;\n\n readonly #sdk: DeviceManagementKit;\n\n #opts: LedgerDmkBridgeOptions;\n\n #isConnected = false;\n\n #sessionState$ = new Subject<{ connected: boolean }>();\n\n get onSessionStateChange(): Observable<{ connected: boolean }> {\n return this.#sessionState$.asObservable();\n }\n\n #sessionSubscription: Subscription | null = null;\n\n get isDeviceConnected(): boolean {\n return this.#isConnected;\n }\n\n constructor(opts: LedgerDmkBridgeOptions) {\n this.#sdk = new DeviceManagementKitBuilder()\n .addTransport(opts.transportFactory)\n .build();\n this.#opts = opts;\n this.#transportMiddleware = new LedgerDmkTransportMiddleware(this.#sdk);\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * DMK session setup happens externally via `updateSessionId` or `connect`,\n * so this method is a no-op.\n *\n * @returns A promise that resolves immediately.\n */\n async init(): Promise<void> {\n return undefined;\n }\n\n /**\n * Destroys the bridge and cleans up resources.\n *\n * Unsubscribes session monitoring, disposes the transport middleware, and\n * completes the session-state subject so all subscribers are released. A\n * fresh subject is installed afterward so the bridge can be reconnected\n * after destroy. State cleanup happens in a `finally` block so the bridge\n * is marked disconnected even when middleware `dispose()` rejects.\n *\n * @returns A promise that resolves when cleanup is complete.\n */\n async destroy(): Promise<void> {\n this.#sessionSubscription?.unsubscribe();\n this.#sessionSubscription = null;\n\n try {\n await this.#transportMiddleware.dispose();\n } finally {\n this.#isConnected = false;\n this.#sessionState$.next({ connected: false });\n this.#sessionState$.complete();\n this.#sessionState$ = new Subject<{ connected: boolean }>();\n }\n }\n\n /**\n * Returns the bridge options captured at construction.\n *\n * Compatibility shim for the shared {@link LedgerBridge} interface. The DMK\n * bridge does not use runtime-reconfigurable options; this method exists\n * only to satisfy the interface contract.\n *\n * @returns A promise that resolves with the current bridge options.\n */\n async getOptions(): Promise<LedgerDmkBridgeOptions> {\n return this.#opts;\n }\n\n /**\n * Replaces the stored bridge options.\n *\n * Compatibility shim for the shared {@link LedgerBridge} interface. Stored\n * options are not re-applied to the underlying DMK instance or transport\n * middleware; the values used at construction time remain in effect.\n *\n * @param opts - The options to set for the bridge.\n * @returns A promise that resolves when options are set.\n */\n async setOptions(opts: LedgerDmkBridgeOptions): Promise<void> {\n this.#opts = opts;\n }\n\n /**\n * Updates the session ID used for communication.\n *\n * @param sessionId - The session ID from DMK.\n * @returns A promise that resolves with true if the session was updated successfully.\n */\n async updateSessionId(sessionId: string): Promise<boolean> {\n await this.#transportMiddleware.setSessionId(sessionId);\n this.#isConnected = true;\n this.#startSessionMonitoring(sessionId);\n return true;\n }\n\n /**\n * Starts device discovery for the configured DMK transport.\n *\n * @param args - Optional DMK discovery options.\n * @returns An observable that emits discovered devices.\n */\n startDiscovering(\n ...args: Parameters<LedgerDmkTransportMiddleware['startDiscovering']>\n ): ReturnType<LedgerDmkTransportMiddleware['startDiscovering']> {\n return this.#transportMiddleware.startDiscovering(...args);\n }\n\n /**\n * Connects to a discovered device using the configured DMK transport.\n *\n * @param args - The DMK connection arguments.\n * @returns The created session ID.\n */\n async connect(\n ...args: Parameters<LedgerDmkTransportMiddleware['connect']>\n ): ReturnType<LedgerDmkTransportMiddleware['connect']> {\n const sessionId = await this.#transportMiddleware.connect(...args);\n this.#isConnected = true;\n this.#startSessionMonitoring(sessionId);\n\n return sessionId;\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * DMK transport selection happens through the injected transport factory\n * at construction time, so this method is a no-op that always succeeds.\n *\n * @param _transportType - The requested transport type (ignored).\n * @returns A promise that resolves with `true`.\n */\n async updateTransportMethod(\n _transportType: string | Transport,\n ): Promise<boolean> {\n return true;\n }\n\n async openEthApp(): Promise<void> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command: new OpenAppCommand({ appName: 'Ethereum' }),\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n }\n\n async closeApps(): Promise<void> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command: new CloseAppCommand(),\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n }\n\n /**\n * Compatibility shim for the shared {@link LedgerBridge} interface.\n *\n * The Ethereum signer kit automatically opens the Ethereum app before each\n * signing operation via DMK's `CallTaskInAppDeviceAction`, so this method\n * is a no-op that always succeeds.\n *\n * @returns A promise that resolves with `true`.\n */\n async attemptMakeApp(): Promise<boolean> {\n return true;\n }\n\n /**\n * Retrieves public key/address for a given HD path.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path to derive the public key from.\n * @returns A promise that resolves with the public key response.\n */\n async getPublicKey({\n hdPath,\n }: GetPublicKeyParams): Promise<GetPublicKeyResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .getAddress(stripPathPrefix(hdPath), {\n checkOnDevice: false,\n returnChainCode: true,\n });\n const response =\n await this.#waitForDeviceAction<PublicKeyOutput>(observable);\n\n return {\n publicKey: response.publicKey,\n address: response.address,\n chainCode: response.chainCode,\n };\n }\n\n /**\n * Signs an Ethereum transaction.\n *\n * @param options0 - The parameters object.\n * @param options0.tx - The transaction hex string to sign.\n * @param options0.hdPath - The HD path for signing.\n * @returns A promise that resolves with the transaction signature.\n */\n async deviceSignTransaction({\n tx,\n hdPath,\n }: LedgerSignTransactionParams): Promise<LedgerSignTransactionResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signTransaction(stripPathPrefix(hdPath), hexToBytes(tx));\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: toHexString(signature.v),\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Signs a personal message.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path for signing.\n * @param options0.message - The message to sign.\n * @returns A promise that resolves with the message signature.\n */\n async deviceSignMessage({\n hdPath,\n message,\n }: LedgerSignMessageParams): Promise<LedgerSignMessageResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signMessage(stripPathPrefix(hdPath), hexToBytes(message));\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: signature.v,\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Signs EIP-712 typed data.\n *\n * @param options0 - The parameters object.\n * @param options0.hdPath - The HD path for signing.\n * @param options0.message - The typed data message to sign.\n * @returns A promise that resolves with the typed data signature.\n */\n async deviceSignTypedData({\n hdPath,\n message,\n }: LedgerSignTypedDataParams): Promise<LedgerSignTypedDataResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signTypedData(stripPathPrefix(hdPath), message);\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: signature.v,\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n async deviceSignDelegationAuthorization({\n hdPath,\n chainId,\n contractAddress,\n nonce,\n }: LedgerSignDelegationAuthorizationParams): Promise<LedgerSignDelegationAuthorizationResponse> {\n const { observable } = this.#transportMiddleware\n .getEthSigner()\n .signDelegationAuthorization(\n stripPathPrefix(hdPath),\n chainId,\n contractAddress,\n nonce,\n );\n const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n return {\n v: toHexString(signature.v),\n r: stripHexPrefix(signature.r),\n s: stripHexPrefix(signature.s),\n };\n }\n\n /**\n * Retrieves the current app name and version.\n *\n * @returns A promise that resolves with the app name and version.\n */\n async getAppNameAndVersion(): Promise<GetAppNameAndVersionResponse> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const command = new GetAppAndVersionCommand();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command,\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n\n return {\n appName: result.data.name,\n version: result.data.version,\n };\n }\n\n /**\n * Retrieves the Ethereum app configuration using the eth-specific\n * GetAppConfiguration APDU command (CLA 0xE0, INS 0x06).\n *\n * @returns A promise that resolves with the app configuration.\n */\n async getAppConfiguration(): Promise<AppConfigurationResponse> {\n const sessionId = this.#transportMiddleware.getSessionId();\n const command = new EthGetAppConfigurationCommand();\n const result = await this.#sdk.sendCommand({\n sessionId,\n command,\n });\n\n if (!isSuccessCommandResult(result)) {\n throw this.#toError(result.error);\n }\n\n const { data } = result;\n\n // The `ethapp.adoc` spec for `getAppConfiguration`\n // (https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.adoc#get-app-configuration)\n // defines four flag bits. This bridge only consumes three (blind signing,\n // web3 checks enabled, web3 checks opt-in). The fourth — `0x02` *ERC 20\n // Token information needs to be provided externally* — is intentionally\n // mapped to `erc20ProvisioningNecessary: 0` because the rest of the\n // keyring does not implement the `PROVIDE ERC 20 TOKEN INFORMATION`\n // provisioning flow.\n //\n // TODO: The shared `AppConfigurationResponse` interface also requires\n // `starkEnabled` and `starkv2Supported`, which are not exposed by the\n // `getAppConfiguration` APDU at all. They are stubbed to 0 to satisfy\n // the interface contract.\n return {\n arbitraryDataEnabled: data.blindSigningEnabled ? 1 : 0,\n erc20ProvisioningNecessary: 0,\n starkEnabled: 0,\n starkv2Supported: 0,\n version: data.version,\n };\n }\n\n async #waitForDeviceAction<TOutput>(\n observable: Observable<DeviceActionState<TOutput, unknown, unknown>>,\n ): Promise<TOutput> {\n const state = await firstValueFrom(\n observable.pipe(\n catchError((error: unknown) => {\n throw translateDmkError(error);\n }),\n filter(\n ({ status }) =>\n status === DeviceActionStatus.Completed ||\n status === DeviceActionStatus.Error,\n ),\n ),\n );\n\n if (state.status === DeviceActionStatus.Completed) {\n return state.output;\n }\n\n if (state.status === DeviceActionStatus.Error) {\n throw translateDmkError(state.error);\n }\n\n // Unreachable: the filter above only lets Completed or Error states\n // through. Defensive guard retained for type safety.\n throw new Error('Ledger device action ended without completion.');\n }\n\n #toError(error: unknown): Error {\n // DMK connection/session errors identified by _tag (e.g.\n // DeviceSessionNotFound, DeviceLockedError) carry no hex APDU code.\n // Resolve them to a HardwareWalletError before falling through.\n const tagResolution = getDMKErrorFromTag(error);\n if (tagResolution) {\n return createDMKError(tagResolution.tag);\n }\n\n if (isDeviceExchangeError(error)) {\n return translateDmkError(error);\n }\n\n if (error instanceof Error) {\n return error;\n }\n\n return new Error('Ledger command failed.');\n }\n\n /**\n * Monitors the DMK session connection state with exponential backoff retries.\n *\n * This is necessary because the DMK does not emit disconnection events on its\n * own — the bridge must actively poll the session state to detect when a\n * Ledger device is unplugged, the Bluetooth/WUSB link drops, or the session\n * is invalidated. Without this monitoring the keyring would retain a stale\n * `isDeviceConnected = true` and subsequent signing requests would hang or\n * fail with cryptic transport errors.\n *\n * Subscribes to the device session state and emits connection changes through\n * {@link #sessionState$}. On error, retries up to 10 times with exponential\n * backoff (capped at 30 s) and emits a `connected: false` state in between\n * attempts. Once the retry limit is exhausted the stream ends with a final\n * `connected: false`. Duplicate consecutive states are suppressed via\n * `distinctUntilChanged`.\n *\n * Any previous monitoring subscription is cancelled before a new one is created.\n *\n * @param sessionId - The DMK session ID to monitor.\n */\n #startSessionMonitoring(sessionId: string): void {\n this.#sessionSubscription?.unsubscribe();\n\n const MAX_BACKOFF_MS = 30_000;\n const BASE_DELAY_MS = 1_000;\n const MAX_RETRIES = 10;\n\n const createMonitoringStream = (\n retryCount = 0,\n ): Observable<{ connected: boolean }> =>\n this.#sdk.getDeviceSessionState({ sessionId }).pipe(\n map((state) => ({\n connected: state.deviceStatus !== DeviceStatus.NOT_CONNECTED,\n })),\n catchError(() => {\n if (retryCount >= MAX_RETRIES) {\n return of({ connected: false });\n }\n const delay = Math.min(\n BASE_DELAY_MS * 2 ** retryCount,\n MAX_BACKOFF_MS,\n );\n return concat(\n of({ connected: false }),\n defer(() =>\n timer(delay).pipe(\n switchMap(() => createMonitoringStream(retryCount + 1)),\n ),\n ),\n );\n }),\n endWith({ connected: false } as { connected: boolean }),\n );\n\n this.#sessionSubscription = createMonitoringStream()\n .pipe(\n distinctUntilChanged(\n (a: { connected: boolean }, b: { connected: boolean }) =>\n a.connected === b.connected,\n ),\n )\n .subscribe((state) => {\n this.#isConnected = state.connected;\n this.#sessionState$.next(state);\n });\n }\n}\n"]}