@ledgerhq/errors
Advanced tools
Comparing version 6.16.0 to 6.16.1-nightly.0
# @ledgerhq/errors | ||
## 6.16.1-nightly.0 | ||
### Patch Changes | ||
- [#5171](https://github.com/LedgerHQ/ledger-live/pull/5171) [`52a373273d`](https://github.com/LedgerHQ/ledger-live/commit/52a373273dee3b2cb5a3e8d2d4b05f90616d71a2) Thanks [@alexandremgo](https://github.com/alexandremgo)! - Feat: new abort timeout on opening transport and APDU exchange | ||
On `@ledgerhq/hw-transport` | ||
- `exchange` adding an optional `abortTimeoutMs` arg to its definition | ||
- `send` taking an optional `abortTimeoutMs` and passing it to `exchange` | ||
- Some documentation and tracing | ||
On `@ledgerhq/react-native-hw-transport-ble` | ||
- `open`: enabling optional timeout when opening a transport instance | ||
- `exchange`: enabling optional timeout on APDU exchange, calling `cancelPendingOperations` on timeout | ||
- `cancelPendingOperations`: using a `currentTransactionIds` array of transactions id for each `write`, we can try to abort completely pending writes | ||
- More documentation + tracing + simple unit tests | ||
## 6.16.0 | ||
@@ -4,0 +23,0 @@ |
@@ -60,3 +60,3 @@ import { serializeError, deserializeError, createCustomErrorClass, addCustomErrorDeserializer, LedgerErrorConstructor } from "./helpers"; | ||
}>; | ||
export declare const LockedDeviceError: LedgerErrorConstructor<{ | ||
export declare const DeviceNeedsRestart: LedgerErrorConstructor<{ | ||
[key: string]: unknown; | ||
@@ -271,2 +271,5 @@ }>; | ||
}>; | ||
export declare const TransportExchangeTimeoutError: LedgerErrorConstructor<{ | ||
[key: string]: unknown; | ||
}>; | ||
export declare const DeviceShouldStayInApp: LedgerErrorConstructor<{ | ||
@@ -350,2 +353,3 @@ [key: string]: unknown; | ||
}>; | ||
export type CustomErrorClassType = ReturnType<typeof createCustomErrorClass>; | ||
/** | ||
@@ -425,6 +429,19 @@ * Type of a Transport error used to represent all equivalent errors coming from all possible implementation of Transport | ||
*/ | ||
export declare function TransportStatusError(statusCode: number): void; | ||
export declare namespace TransportStatusError { | ||
var prototype: Error; | ||
export declare class TransportStatusError extends Error { | ||
statusCode: number; | ||
statusText: string; | ||
/** | ||
* @param statusCode The error status code coming from a Transport implementation | ||
* @param options containing: | ||
* - canBeMappedToChildError: enable the mapping of TransportStatusError to an error extending/inheriting from it | ||
* . Ex: LockedDeviceError. Default to true. | ||
*/ | ||
constructor(statusCode: number, { canBeMappedToChildError }?: { | ||
canBeMappedToChildError?: boolean; | ||
}); | ||
} | ||
export declare class LockedDeviceError extends TransportStatusError { | ||
constructor(message?: string); | ||
} | ||
export type TransportStatusErrorClassType = typeof TransportStatusError | typeof LockedDeviceError; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -22,3 +22,3 @@ import { serializeError, deserializeError, createCustomErrorClass, addCustomErrorDeserializer, } from "./helpers"; | ||
export const DeviceSocketNoBulkStatus = createCustomErrorClass("DeviceSocketNoBulkStatus"); | ||
export const LockedDeviceError = createCustomErrorClass("LockedDeviceError"); | ||
export const DeviceNeedsRestart = createCustomErrorClass("DeviceSocketNoBulkStatus"); | ||
export const UnresponsiveDeviceError = createCustomErrorClass("UnresponsiveDeviceError"); | ||
@@ -94,2 +94,3 @@ export const DisconnectedDevice = createCustomErrorClass("DisconnectedDevice"); | ||
export const TransactionHasBeenValidatedError = createCustomErrorClass("TransactionHasBeenValidatedError"); | ||
export const TransportExchangeTimeoutError = createCustomErrorClass("TransportExchangeTimeoutError"); | ||
export const DeviceShouldStayInApp = createCustomErrorClass("DeviceShouldStayInApp"); | ||
@@ -233,19 +234,34 @@ export const WebsocketConnectionError = createCustomErrorClass("WebsocketConnectionError"); | ||
*/ | ||
export function TransportStatusError(statusCode) { | ||
const statusText = Object.keys(StatusCodes).find(k => StatusCodes[k] === statusCode) || "UNKNOWN_ERROR"; | ||
const smsg = getAltStatusMessage(statusCode) || statusText; | ||
const statusCodeStr = statusCode.toString(16); | ||
const message = `Ledger device: ${smsg} (0x${statusCodeStr})`; | ||
// Maps to a LockedDeviceError | ||
if (statusCode === StatusCodes.LOCKED_DEVICE) { | ||
throw new LockedDeviceError(message); | ||
export class TransportStatusError extends Error { | ||
/** | ||
* @param statusCode The error status code coming from a Transport implementation | ||
* @param options containing: | ||
* - canBeMappedToChildError: enable the mapping of TransportStatusError to an error extending/inheriting from it | ||
* . Ex: LockedDeviceError. Default to true. | ||
*/ | ||
constructor(statusCode, { canBeMappedToChildError = true } = {}) { | ||
const statusText = Object.keys(StatusCodes).find(k => StatusCodes[k] === statusCode) || "UNKNOWN_ERROR"; | ||
const smsg = getAltStatusMessage(statusCode) || statusText; | ||
const statusCodeStr = statusCode.toString(16); | ||
const message = `Ledger device: ${smsg} (0x${statusCodeStr})`; | ||
super(message); | ||
this.name = "TransportStatusError"; | ||
this.statusCode = statusCode; | ||
this.statusText = statusText; | ||
// Maps to a LockedDeviceError | ||
if (canBeMappedToChildError && statusCode === StatusCodes.LOCKED_DEVICE) { | ||
return new LockedDeviceError(message); | ||
} | ||
} | ||
this.name = "TransportStatusError"; | ||
this.message = message; | ||
this.stack = new Error(message).stack; | ||
this.statusCode = statusCode; | ||
this.statusText = statusText; | ||
} | ||
TransportStatusError.prototype = new Error(); | ||
export class LockedDeviceError extends TransportStatusError { | ||
constructor(message) { | ||
super(StatusCodes.LOCKED_DEVICE, { canBeMappedToChildError: false }); | ||
if (message) { | ||
this.message = message; | ||
} | ||
this.name = "LockedDeviceError"; | ||
} | ||
} | ||
addCustomErrorDeserializer("TransportStatusError", e => new TransportStatusError(e.statusCode)); | ||
//# sourceMappingURL=index.js.map |
@@ -70,7 +70,22 @@ import { AmountRequired, CurrencyNotSupported, TransportStatusError, StatusCodes } from "./index"; | ||
}); | ||
test("transport status error contains message", () => { | ||
const error = new TransportStatusError(StatusCodes.UNKNOWN_APDU); | ||
expect(error.stack).toContain("Ledger device: UNKNOWN_APDU (0x6d02)"); | ||
describe("TransportStatusError", () => { | ||
test("TransportStatusError contains the expected name, message, stack, status code and status message (non-regression)", () => { | ||
const error = new TransportStatusError(StatusCodes.UNKNOWN_APDU); | ||
console.log(`${JSON.stringify(error)}`); | ||
expect(error.name).toEqual("TransportStatusError"); | ||
expect(error.message).toEqual("Ledger device: UNKNOWN_APDU (0x6d02)"); | ||
expect(error.stack).toContain("Ledger device: UNKNOWN_APDU (0x6d02)"); | ||
expect(error.statusText).toEqual("UNKNOWN_APDU"); | ||
expect(error.statusCode).toEqual(0x6d02); | ||
}); | ||
test.only("TransportStatusError should be mapped to a LockedDeviceError on status code 0x5515", () => { | ||
const error = new TransportStatusError(StatusCodes.LOCKED_DEVICE); | ||
expect(error.name).toEqual("LockedDeviceError"); | ||
expect(error.message).toEqual("Ledger device: Locked device (0x5515)"); | ||
expect(error.stack).toContain("Ledger device: Locked device (0x5515)"); | ||
expect(error.statusText).toEqual("LOCKED_DEVICE"); | ||
expect(error.statusCode).toEqual(0x5515); | ||
}); | ||
}); | ||
}); | ||
//# sourceMappingURL=index.test.js.map |
@@ -60,3 +60,3 @@ import { serializeError, deserializeError, createCustomErrorClass, addCustomErrorDeserializer, LedgerErrorConstructor } from "./helpers"; | ||
}>; | ||
export declare const LockedDeviceError: LedgerErrorConstructor<{ | ||
export declare const DeviceNeedsRestart: LedgerErrorConstructor<{ | ||
[key: string]: unknown; | ||
@@ -271,2 +271,5 @@ }>; | ||
}>; | ||
export declare const TransportExchangeTimeoutError: LedgerErrorConstructor<{ | ||
[key: string]: unknown; | ||
}>; | ||
export declare const DeviceShouldStayInApp: LedgerErrorConstructor<{ | ||
@@ -350,2 +353,3 @@ [key: string]: unknown; | ||
}>; | ||
export type CustomErrorClassType = ReturnType<typeof createCustomErrorClass>; | ||
/** | ||
@@ -425,6 +429,19 @@ * Type of a Transport error used to represent all equivalent errors coming from all possible implementation of Transport | ||
*/ | ||
export declare function TransportStatusError(statusCode: number): void; | ||
export declare namespace TransportStatusError { | ||
var prototype: Error; | ||
export declare class TransportStatusError extends Error { | ||
statusCode: number; | ||
statusText: string; | ||
/** | ||
* @param statusCode The error status code coming from a Transport implementation | ||
* @param options containing: | ||
* - canBeMappedToChildError: enable the mapping of TransportStatusError to an error extending/inheriting from it | ||
* . Ex: LockedDeviceError. Default to true. | ||
*/ | ||
constructor(statusCode: number, { canBeMappedToChildError }?: { | ||
canBeMappedToChildError?: boolean; | ||
}); | ||
} | ||
export declare class LockedDeviceError extends TransportStatusError { | ||
constructor(message?: string); | ||
} | ||
export type TransportStatusErrorClassType = typeof TransportStatusError | typeof LockedDeviceError; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ManagerNotEnoughSpaceError = exports.ManagerFirmwareNotEnoughSpaceError = exports.ManagerDeviceLockedError = exports.ManagerAppDepUninstallRequired = exports.ManagerAppDepInstallRequired = exports.ManagerAppRelyOnBTCError = exports.ManagerAppAlreadyInstalledError = exports.LedgerAPINotAvailable = exports.LedgerAPIErrorWithMessage = exports.LedgerAPIError = exports.UnknownMCU = exports.LatestMCUInstalledError = exports.InvalidAddressBecauseDestinationIsAlsoSource = exports.InvalidNonce = exports.InvalidAddress = exports.InvalidXRPTag = exports.HardResetFail = exports.FirmwareNotRecognized = exports.FeeEstimationFailed = exports.EthAppPleaseEnableContractData = exports.EnpointConfigError = exports.DeviceOnboardingStatePollingError = exports.DeviceExtractOnboardingStateError = exports.DisconnectedDeviceDuringOperation = exports.DisconnectedDevice = exports.UnresponsiveDeviceError = exports.LockedDeviceError = exports.DeviceSocketNoBulkStatus = exports.DeviceSocketFail = exports.DeviceNameInvalid = exports.DeviceHalted = exports.DeviceInOSUExpected = exports.DeviceOnDashboardUnexpected = exports.DeviceOnDashboardExpected = exports.DeviceNotGenuineError = exports.DeviceGenuineSocketEarlyClose = exports.DeviceAppVerifyNotSupported = exports.CurrencyNotSupported = exports.ClaimRewardsFeesWarning = exports.CashAddrNotSupported = exports.CantOpenDevice = exports.BtcUnmatchedApp = exports.BluetoothRequired = exports.AmountRequired = exports.AccountNotSupported = exports.AccountNameRequiredError = exports.addCustomErrorDeserializer = exports.createCustomErrorClass = exports.deserializeError = exports.serializeError = void 0; | ||
exports.CantScanQRCode = exports.ETHAddressNonEIP = exports.WrongAppForCurrency = exports.WrongDeviceForAccount = exports.WebsocketConnectionFailed = exports.WebsocketConnectionError = exports.DeviceShouldStayInApp = exports.TransactionHasBeenValidatedError = exports.TransportWebUSBGestureRequired = exports.TransportRaceCondition = exports.TransportInterfaceNotAvailable = exports.TransportOpenUserCancelled = exports.ExpertModeRequired = exports.UserRefusedOnDevice = exports.UserRefusedAllowManager = exports.UserRefusedFirmwareUpdate = exports.UserRefusedAddress = exports.UserRefusedDeviceNameChange = exports.UpdateYourApp = exports.UpdateIncorrectSig = exports.UpdateIncorrectHash = exports.UpdateFetchFileFail = exports.UnavailableTezosOriginatedAccountSend = exports.UnavailableTezosOriginatedAccountReceive = exports.RecipientRequired = exports.MCUNotGenuineToDashboard = exports.UnexpectedBootloader = exports.TimeoutTagged = exports.RecommendUndelegation = exports.RecommendSubAccountsToEmpty = exports.PasswordIncorrectError = exports.PasswordsDontMatchError = exports.MaxFeeTooLow = exports.PriorityFeeHigherThanMaxFee = exports.PriorityFeeTooHigh = exports.PriorityFeeTooLow = exports.GasLessThanEstimate = exports.NotSupportedLegacyAddress = exports.NotEnoughGasSwap = exports.NotEnoughGas = exports.NoAccessToCamera = exports.NotEnoughBalanceBecauseDestinationNotCreated = exports.NotEnoughSpendableBalance = exports.NotEnoughBalanceInParentAccount = exports.NotEnoughBalanceToDelegate = exports.NotEnoughBalance = exports.NoAddressesFound = exports.NetworkError = exports.NetworkDown = exports.ManagerUninstallBTCDep = void 0; | ||
exports.TransportStatusError = exports.getAltStatusMessage = exports.StatusCodes = exports.TransportError = exports.HwTransportError = exports.HwTransportErrorType = exports.DBNotReset = exports.DBWrongPassword = exports.NoDBPathGiven = exports.LanguageNotFound = exports.DustLimit = exports.OpReturnDataSizeLimit = exports.ReplacementTransactionUnderpriced = exports.FirmwareOrAppUpdateRequired = exports.LedgerAPI5xx = exports.LedgerAPI4xx = exports.GenuineCheckFailed = exports.PeerRemovedPairing = exports.PairingFailed = exports.SyncError = exports.PendingOperation = exports.FeeTooHigh = exports.FeeRequired = exports.FeeNotLoadedSwap = exports.FeeNotLoaded = void 0; | ||
exports.ManagerNotEnoughSpaceError = exports.ManagerFirmwareNotEnoughSpaceError = exports.ManagerDeviceLockedError = exports.ManagerAppDepUninstallRequired = exports.ManagerAppDepInstallRequired = exports.ManagerAppRelyOnBTCError = exports.ManagerAppAlreadyInstalledError = exports.LedgerAPINotAvailable = exports.LedgerAPIErrorWithMessage = exports.LedgerAPIError = exports.UnknownMCU = exports.LatestMCUInstalledError = exports.InvalidAddressBecauseDestinationIsAlsoSource = exports.InvalidNonce = exports.InvalidAddress = exports.InvalidXRPTag = exports.HardResetFail = exports.FirmwareNotRecognized = exports.FeeEstimationFailed = exports.EthAppPleaseEnableContractData = exports.EnpointConfigError = exports.DeviceOnboardingStatePollingError = exports.DeviceExtractOnboardingStateError = exports.DisconnectedDeviceDuringOperation = exports.DisconnectedDevice = exports.UnresponsiveDeviceError = exports.DeviceNeedsRestart = exports.DeviceSocketNoBulkStatus = exports.DeviceSocketFail = exports.DeviceNameInvalid = exports.DeviceHalted = exports.DeviceInOSUExpected = exports.DeviceOnDashboardUnexpected = exports.DeviceOnDashboardExpected = exports.DeviceNotGenuineError = exports.DeviceGenuineSocketEarlyClose = exports.DeviceAppVerifyNotSupported = exports.CurrencyNotSupported = exports.ClaimRewardsFeesWarning = exports.CashAddrNotSupported = exports.CantOpenDevice = exports.BtcUnmatchedApp = exports.BluetoothRequired = exports.AmountRequired = exports.AccountNotSupported = exports.AccountNameRequiredError = exports.addCustomErrorDeserializer = exports.createCustomErrorClass = exports.deserializeError = exports.serializeError = void 0; | ||
exports.ETHAddressNonEIP = exports.WrongAppForCurrency = exports.WrongDeviceForAccount = exports.WebsocketConnectionFailed = exports.WebsocketConnectionError = exports.DeviceShouldStayInApp = exports.TransportExchangeTimeoutError = exports.TransactionHasBeenValidatedError = exports.TransportWebUSBGestureRequired = exports.TransportRaceCondition = exports.TransportInterfaceNotAvailable = exports.TransportOpenUserCancelled = exports.ExpertModeRequired = exports.UserRefusedOnDevice = exports.UserRefusedAllowManager = exports.UserRefusedFirmwareUpdate = exports.UserRefusedAddress = exports.UserRefusedDeviceNameChange = exports.UpdateYourApp = exports.UpdateIncorrectSig = exports.UpdateIncorrectHash = exports.UpdateFetchFileFail = exports.UnavailableTezosOriginatedAccountSend = exports.UnavailableTezosOriginatedAccountReceive = exports.RecipientRequired = exports.MCUNotGenuineToDashboard = exports.UnexpectedBootloader = exports.TimeoutTagged = exports.RecommendUndelegation = exports.RecommendSubAccountsToEmpty = exports.PasswordIncorrectError = exports.PasswordsDontMatchError = exports.MaxFeeTooLow = exports.PriorityFeeHigherThanMaxFee = exports.PriorityFeeTooHigh = exports.PriorityFeeTooLow = exports.GasLessThanEstimate = exports.NotSupportedLegacyAddress = exports.NotEnoughGasSwap = exports.NotEnoughGas = exports.NoAccessToCamera = exports.NotEnoughBalanceBecauseDestinationNotCreated = exports.NotEnoughSpendableBalance = exports.NotEnoughBalanceInParentAccount = exports.NotEnoughBalanceToDelegate = exports.NotEnoughBalance = exports.NoAddressesFound = exports.NetworkError = exports.NetworkDown = exports.ManagerUninstallBTCDep = void 0; | ||
exports.LockedDeviceError = exports.TransportStatusError = exports.getAltStatusMessage = exports.StatusCodes = exports.TransportError = exports.HwTransportError = exports.HwTransportErrorType = exports.DBNotReset = exports.DBWrongPassword = exports.NoDBPathGiven = exports.LanguageNotFound = exports.DustLimit = exports.OpReturnDataSizeLimit = exports.ReplacementTransactionUnderpriced = exports.FirmwareOrAppUpdateRequired = exports.LedgerAPI5xx = exports.LedgerAPI4xx = exports.GenuineCheckFailed = exports.PeerRemovedPairing = exports.PairingFailed = exports.SyncError = exports.PendingOperation = exports.FeeTooHigh = exports.FeeRequired = exports.FeeNotLoadedSwap = exports.FeeNotLoaded = exports.CantScanQRCode = void 0; | ||
const helpers_1 = require("./helpers"); | ||
@@ -30,3 +30,3 @@ Object.defineProperty(exports, "serializeError", { enumerable: true, get: function () { return helpers_1.serializeError; } }); | ||
exports.DeviceSocketNoBulkStatus = (0, helpers_1.createCustomErrorClass)("DeviceSocketNoBulkStatus"); | ||
exports.LockedDeviceError = (0, helpers_1.createCustomErrorClass)("LockedDeviceError"); | ||
exports.DeviceNeedsRestart = (0, helpers_1.createCustomErrorClass)("DeviceSocketNoBulkStatus"); | ||
exports.UnresponsiveDeviceError = (0, helpers_1.createCustomErrorClass)("UnresponsiveDeviceError"); | ||
@@ -102,2 +102,3 @@ exports.DisconnectedDevice = (0, helpers_1.createCustomErrorClass)("DisconnectedDevice"); | ||
exports.TransactionHasBeenValidatedError = (0, helpers_1.createCustomErrorClass)("TransactionHasBeenValidatedError"); | ||
exports.TransportExchangeTimeoutError = (0, helpers_1.createCustomErrorClass)("TransportExchangeTimeoutError"); | ||
exports.DeviceShouldStayInApp = (0, helpers_1.createCustomErrorClass)("DeviceShouldStayInApp"); | ||
@@ -244,20 +245,36 @@ exports.WebsocketConnectionError = (0, helpers_1.createCustomErrorClass)("WebsocketConnectionError"); | ||
*/ | ||
function TransportStatusError(statusCode) { | ||
const statusText = Object.keys(exports.StatusCodes).find(k => exports.StatusCodes[k] === statusCode) || "UNKNOWN_ERROR"; | ||
const smsg = getAltStatusMessage(statusCode) || statusText; | ||
const statusCodeStr = statusCode.toString(16); | ||
const message = `Ledger device: ${smsg} (0x${statusCodeStr})`; | ||
// Maps to a LockedDeviceError | ||
if (statusCode === exports.StatusCodes.LOCKED_DEVICE) { | ||
throw new exports.LockedDeviceError(message); | ||
class TransportStatusError extends Error { | ||
/** | ||
* @param statusCode The error status code coming from a Transport implementation | ||
* @param options containing: | ||
* - canBeMappedToChildError: enable the mapping of TransportStatusError to an error extending/inheriting from it | ||
* . Ex: LockedDeviceError. Default to true. | ||
*/ | ||
constructor(statusCode, { canBeMappedToChildError = true } = {}) { | ||
const statusText = Object.keys(exports.StatusCodes).find(k => exports.StatusCodes[k] === statusCode) || "UNKNOWN_ERROR"; | ||
const smsg = getAltStatusMessage(statusCode) || statusText; | ||
const statusCodeStr = statusCode.toString(16); | ||
const message = `Ledger device: ${smsg} (0x${statusCodeStr})`; | ||
super(message); | ||
this.name = "TransportStatusError"; | ||
this.statusCode = statusCode; | ||
this.statusText = statusText; | ||
// Maps to a LockedDeviceError | ||
if (canBeMappedToChildError && statusCode === exports.StatusCodes.LOCKED_DEVICE) { | ||
return new LockedDeviceError(message); | ||
} | ||
} | ||
this.name = "TransportStatusError"; | ||
this.message = message; | ||
this.stack = new Error(message).stack; | ||
this.statusCode = statusCode; | ||
this.statusText = statusText; | ||
} | ||
exports.TransportStatusError = TransportStatusError; | ||
TransportStatusError.prototype = new Error(); | ||
class LockedDeviceError extends TransportStatusError { | ||
constructor(message) { | ||
super(exports.StatusCodes.LOCKED_DEVICE, { canBeMappedToChildError: false }); | ||
if (message) { | ||
this.message = message; | ||
} | ||
this.name = "LockedDeviceError"; | ||
} | ||
} | ||
exports.LockedDeviceError = LockedDeviceError; | ||
(0, helpers_1.addCustomErrorDeserializer)("TransportStatusError", e => new TransportStatusError(e.statusCode)); | ||
//# sourceMappingURL=index.js.map |
@@ -72,7 +72,22 @@ "use strict"; | ||
}); | ||
test("transport status error contains message", () => { | ||
const error = new index_1.TransportStatusError(index_1.StatusCodes.UNKNOWN_APDU); | ||
expect(error.stack).toContain("Ledger device: UNKNOWN_APDU (0x6d02)"); | ||
describe("TransportStatusError", () => { | ||
test("TransportStatusError contains the expected name, message, stack, status code and status message (non-regression)", () => { | ||
const error = new index_1.TransportStatusError(index_1.StatusCodes.UNKNOWN_APDU); | ||
console.log(`${JSON.stringify(error)}`); | ||
expect(error.name).toEqual("TransportStatusError"); | ||
expect(error.message).toEqual("Ledger device: UNKNOWN_APDU (0x6d02)"); | ||
expect(error.stack).toContain("Ledger device: UNKNOWN_APDU (0x6d02)"); | ||
expect(error.statusText).toEqual("UNKNOWN_APDU"); | ||
expect(error.statusCode).toEqual(0x6d02); | ||
}); | ||
test.only("TransportStatusError should be mapped to a LockedDeviceError on status code 0x5515", () => { | ||
const error = new index_1.TransportStatusError(index_1.StatusCodes.LOCKED_DEVICE); | ||
expect(error.name).toEqual("LockedDeviceError"); | ||
expect(error.message).toEqual("Ledger device: Locked device (0x5515)"); | ||
expect(error.stack).toContain("Ledger device: Locked device (0x5515)"); | ||
expect(error.statusText).toEqual("LOCKED_DEVICE"); | ||
expect(error.statusCode).toEqual(0x5515); | ||
}); | ||
}); | ||
}); | ||
//# sourceMappingURL=index.test.js.map |
{ | ||
"name": "@ledgerhq/errors", | ||
"version": "6.16.0", | ||
"version": "6.16.1-nightly.0", | ||
"description": "Ledger common errors", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -54,2 +54,4 @@ <img src="https://user-images.githubusercontent.com/4631227/191834116-59cf590e-25cc-4956-ae5c-812ea464f324.png" height="100" /> | ||
**Extends Error** | ||
Error thrown when a device returned a non success status. | ||
@@ -60,4 +62,6 @@ the error.statusCode is one of the `StatusCodes` exported by this library. | ||
* `statusCode` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)**  | ||
* `statusCode` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** The error status code coming from a Transport implementation | ||
* `options` **{canBeMappedToChildError: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?}** containing:* canBeMappedToChildError: enable the mapping of TransportStatusError to an error extending/inheriting from it | ||
. Ex: LockedDeviceError. Default to true. (optional, default `{}`) | ||
Returns **void**  | ||
* `options.canBeMappedToChildError` (optional, default `true`) |
@@ -76,6 +76,25 @@ import { AmountRequired, CurrencyNotSupported, TransportStatusError, StatusCodes } from "./index"; | ||
test("transport status error contains message", () => { | ||
const error: Error = new TransportStatusError(StatusCodes.UNKNOWN_APDU); | ||
expect(error.stack).toContain("Ledger device: UNKNOWN_APDU (0x6d02)"); | ||
describe("TransportStatusError", () => { | ||
test("TransportStatusError contains the expected name, message, stack, status code and status message (non-regression)", () => { | ||
const error = new TransportStatusError(StatusCodes.UNKNOWN_APDU); | ||
console.log(`${JSON.stringify(error)}`); | ||
expect(error.name).toEqual("TransportStatusError"); | ||
expect(error.message).toEqual("Ledger device: UNKNOWN_APDU (0x6d02)"); | ||
expect(error.stack).toContain("Ledger device: UNKNOWN_APDU (0x6d02)"); | ||
expect(error.statusText).toEqual("UNKNOWN_APDU"); | ||
expect(error.statusCode).toEqual(0x6d02); | ||
}); | ||
test.only("TransportStatusError should be mapped to a LockedDeviceError on status code 0x5515", () => { | ||
const error = new TransportStatusError(StatusCodes.LOCKED_DEVICE); | ||
expect(error.name).toEqual("LockedDeviceError"); | ||
expect(error.message).toEqual("Ledger device: Locked device (0x5515)"); | ||
expect(error.stack).toContain("Ledger device: Locked device (0x5515)"); | ||
expect(error.statusText).toEqual("LOCKED_DEVICE"); | ||
expect(error.statusCode).toEqual(0x5515); | ||
}); | ||
}); | ||
}); |
@@ -35,3 +35,3 @@ import { | ||
export const DeviceSocketNoBulkStatus = createCustomErrorClass("DeviceSocketNoBulkStatus"); | ||
export const LockedDeviceError = createCustomErrorClass("LockedDeviceError"); | ||
export const DeviceNeedsRestart = createCustomErrorClass("DeviceSocketNoBulkStatus"); | ||
export const UnresponsiveDeviceError = createCustomErrorClass("UnresponsiveDeviceError"); | ||
@@ -135,2 +135,5 @@ export const DisconnectedDevice = createCustomErrorClass("DisconnectedDevice"); | ||
); | ||
export const TransportExchangeTimeoutError = createCustomErrorClass( | ||
"TransportExchangeTimeoutError", | ||
); | ||
export const DeviceShouldStayInApp = createCustomErrorClass("DeviceShouldStayInApp"); | ||
@@ -174,2 +177,5 @@ export const WebsocketConnectionError = createCustomErrorClass("WebsocketConnectionError"); | ||
// Represents the type of all the classes created with createCustomErrorClass | ||
export type CustomErrorClassType = ReturnType<typeof createCustomErrorClass>; | ||
/** | ||
@@ -292,22 +298,48 @@ * Type of a Transport error used to represent all equivalent errors coming from all possible implementation of Transport | ||
*/ | ||
export function TransportStatusError(statusCode: number): void { | ||
const statusText = | ||
Object.keys(StatusCodes).find(k => StatusCodes[k] === statusCode) || "UNKNOWN_ERROR"; | ||
const smsg = getAltStatusMessage(statusCode) || statusText; | ||
const statusCodeStr = statusCode.toString(16); | ||
const message = `Ledger device: ${smsg} (0x${statusCodeStr})`; | ||
export class TransportStatusError extends Error { | ||
statusCode: number; | ||
statusText: string; | ||
// Maps to a LockedDeviceError | ||
if (statusCode === StatusCodes.LOCKED_DEVICE) { | ||
throw new LockedDeviceError(message); | ||
/** | ||
* @param statusCode The error status code coming from a Transport implementation | ||
* @param options containing: | ||
* - canBeMappedToChildError: enable the mapping of TransportStatusError to an error extending/inheriting from it | ||
* . Ex: LockedDeviceError. Default to true. | ||
*/ | ||
constructor( | ||
statusCode: number, | ||
{ canBeMappedToChildError = true }: { canBeMappedToChildError?: boolean } = {}, | ||
) { | ||
const statusText = | ||
Object.keys(StatusCodes).find(k => StatusCodes[k] === statusCode) || "UNKNOWN_ERROR"; | ||
const smsg = getAltStatusMessage(statusCode) || statusText; | ||
const statusCodeStr = statusCode.toString(16); | ||
const message = `Ledger device: ${smsg} (0x${statusCodeStr})`; | ||
super(message); | ||
this.name = "TransportStatusError"; | ||
this.statusCode = statusCode; | ||
this.statusText = statusText; | ||
// Maps to a LockedDeviceError | ||
if (canBeMappedToChildError && statusCode === StatusCodes.LOCKED_DEVICE) { | ||
return new LockedDeviceError(message); | ||
} | ||
} | ||
} | ||
this.name = "TransportStatusError"; | ||
this.message = message; | ||
this.stack = new Error(message).stack; | ||
this.statusCode = statusCode; | ||
this.statusText = statusText; | ||
export class LockedDeviceError extends TransportStatusError { | ||
constructor(message?: string) { | ||
super(StatusCodes.LOCKED_DEVICE, { canBeMappedToChildError: false }); | ||
if (message) { | ||
this.message = message; | ||
} | ||
this.name = "LockedDeviceError"; | ||
} | ||
} | ||
TransportStatusError.prototype = new Error(); | ||
// Represents the type of the class TransportStatusError and its children | ||
export type TransportStatusErrorClassType = typeof TransportStatusError | typeof LockedDeviceError; | ||
addCustomErrorDeserializer("TransportStatusError", e => new TransportStatusError(e.statusCode)); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
SPDX disjunction
LicenseSPDX disjunction for an artifact's license information
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
SPDX disjunction
LicenseSPDX disjunction for an artifact's license information
Found 1 instance in 1 package
186312
44
2631
66
2
1