Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `serializeError`
- If the object passed to the function has a `.message` property, it will preferred over the `.message` property of the fallback error when creating the returned serialized error object

[Unreleased]: https://github.com/MetaMask/eth-rpc-errors/compare/v4.0.3...HEAD
[4.0.3]: https://github.com/MetaMask/eth-rpc-errors/compare/v4.0.2...v4.0.3
[4.0.2]: https://github.com/MetaMask/eth-rpc-errors/compare/v4.0.1...v4.0.2
[4.0.1]: https://github.com/MetaMask/eth-rpc-errors/compare/v4.0.0...v4.0.1
[4.0.0]: https://github.com/MetaMask/eth-rpc-errors/compare/v3.0.0...v4.0.0
[3.0.0]: https://github.com/MetaMask/eth-rpc-errors/compare/v2.1.1...v3.0.0
[2.1.1]: https://github.com/MetaMask/eth-rpc-errors/compare/v2.1.0...v2.1.1
[2.1.0]: https://github.com/MetaMask/eth-rpc-errors/compare/v2.0.2...v2.1.0
[2.0.2]: https://github.com/MetaMask/eth-rpc-errors/compare/v2.0.1...v2.0.2
[2.0.1]: https://github.com/MetaMask/eth-rpc-errors/compare/v2.0.0...v2.0.1
[2.0.0]: https://github.com/MetaMask/eth-rpc-errors/compare/v1.1.0...v2.0.0
[1.1.0]: https://github.com/MetaMask/eth-rpc-errors/releases/tag/v1.1.0
[Unreleased]: https://github.com/MetaMask/rpc-errors/compare/v4.0.3...HEAD
[4.0.3]: https://github.com/MetaMask/rpc-errors/compare/v4.0.2...v4.0.3
[4.0.2]: https://github.com/MetaMask/rpc-errors/compare/v4.0.1...v4.0.2
[4.0.1]: https://github.com/MetaMask/rpc-errors/compare/v4.0.0...v4.0.1
[4.0.0]: https://github.com/MetaMask/rpc-errors/compare/v3.0.0...v4.0.0
[3.0.0]: https://github.com/MetaMask/rpc-errors/compare/v2.1.1...v3.0.0
[2.1.1]: https://github.com/MetaMask/rpc-errors/compare/v2.1.0...v2.1.1
[2.1.0]: https://github.com/MetaMask/rpc-errors/compare/v2.0.2...v2.1.0
[2.0.2]: https://github.com/MetaMask/rpc-errors/compare/v2.0.1...v2.0.2
[2.0.1]: https://github.com/MetaMask/rpc-errors/compare/v2.0.0...v2.0.1
[2.0.0]: https://github.com/MetaMask/rpc-errors/compare/v1.1.0...v2.0.0
[1.1.0]: https://github.com/MetaMask/rpc-errors/releases/tag/v1.1.0
40 changes: 20 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,48 +17,48 @@ or
## Usage

```js
import { ethErrors } from '@metamask/rpc-errors';
import { rpcErrors, providerErrors } from '@metamask/rpc-errors';

throw ethErrors.provider.unauthorized();
throw rpcErrors.invalidRequest();
// or
throw ethErrors.provider.unauthorized('my custom message');
throw providerErrors.unauthorized('my custom message');
```

## Supported Errors

- Generic JSON RPC 2.0 errors
- Per [JSON RPC 2.0 spec](https://www.jsonrpc.org/specification#error_object)
- Ethereum JSON RPC
- Per [EIP-1474](https://eips.ethereum.org/EIPS/eip-1474#error-codes)
- This includes all
[JSON RPC 2.0 errors](https://www.jsonrpc.org/specification#error_object)
- Ethereum Provider errors
- Per [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193#provider-errors)
- Does **not** yet support [`CloseEvent` errors or status codes](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes).

## API

```js
import { ethErrors } from '@metamask/rpc-errors';
import { rpcErrors, providerErrors } from '@metamask/rpc-errors';

// Ethereum RPC errors are namespaced under "ethErrors.rpc"
response.error = ethErrors.rpc.methodNotFound({
// JSON-RPC errors and Ethereum EIP-1474 errors are namespaced under "rpcErrors"
response.error = rpcErrors.methodNotFound({
message: optionalCustomMessage,
data: optionalData,
});

// Provider errors namespaced under ethErrors.provider
response.error = ethErrors.provider.unauthorized({
// Ethereum EIP-1193 Provider errors namespaced under "providerErrors"
response.error = providerErrors.unauthorized({
message: optionalCustomMessage,
data: optionalData,
});

// each error getter takes a single "opts" argument
// for most errors, this can be replaced with a single string, which becomes
// the error message
response.error = ethErrors.provider.unauthorized(customMessage);
response.error = providerErrors.unauthorized(customMessage);

// if an error getter accepts a single string, all arguments can be omitted
response.error = ethErrors.provider.unauthorized();
response.error = ethErrors.provider.unauthorized({});
response.error = providerErrors.unauthorized();
response.error = providerErrors.unauthorized({});

// omitting the message will produce an error with a default message per
// the relevant spec
Expand All @@ -67,13 +67,13 @@ response.error = ethErrors.provider.unauthorized({});
// "data" property

// the JSON RPC 2.0 server error requires a valid code
response.error = ethErrors.rpc.server({
response.error = rpcErrors.server({
code: -32031,
});

// custom Ethereum Provider errors require a valid code and message
// valid codes are integers i such that: 1000 <= i <= 4999
response.error = ethErrors.provider.custom({
response.error = providerErrors.custom({
code: 1001,
message: 'foo',
});
Expand Down Expand Up @@ -109,7 +109,7 @@ response.error = serializeError(maybeAnError, fallbackError)
/**
* Classes
*/
import { EthereumRpcError, EthereumProviderError } from '@metamask/rpc-errors';
import { JsonRpcError, EthereumProviderError } from '@metamask/rpc-errors';

/**
* getMessageFromCode and errorCodes
Expand All @@ -126,11 +126,11 @@ const message2 = getMessageFromCode(someCode, myFallback);
const message3 = getMessageFromCode(someCode, null);

// {
// rpc: { [errorName]: code, ... },
// provider: { [errorName]: code, ... },
// rpcErrors: { [errorName]: code, ... },
// providerErrors: { [errorName]: code, ... },
// }
const code1 = errorCodes.rpc.parse;
const code2 = errorCodes.provider.userRejectedRequest;
const code1 = rpcErrors.parse;
const code2 = providerErrors.userRejectedRequest;

// all codes in errorCodes have default messages
const message4 = getMessageFromCode(code1);
Expand Down
8 changes: 4 additions & 4 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ module.exports = {
// An object that configures minimum threshold enforcement for coverage results
coverageThreshold: {
global: {
branches: 94.44,
functions: 85,
lines: 96.87,
statements: 96.87,
branches: 94.5,
functions: 85.36,
lines: 96.88,
statements: 96.88,
},
},

Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"errors",
"utility"
],
"homepage": "https://github.com/MetaMask/eth-rpc-errors#readme",
"homepage": "https://github.com/MetaMask/rpc-errors#readme",
"bugs": {
"url": "https://github.com/MetaMask/eth-rpc-errors/issues"
"url": "https://github.com/MetaMask/rpc-errors/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/MetaMask/eth-rpc-errors.git"
"url": "https://github.com/MetaMask/rpc-errors.git"
},
"license": "MIT",
"author": "Erik Marks <[email protected]>",
Expand Down
8 changes: 4 additions & 4 deletions src/__fixtures__/errors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ethErrors } from '..';
import { rpcErrors } from '..';

export const dummyData = { foo: 'bar' };
export const dummyMessage = 'baz';
Expand Down Expand Up @@ -26,11 +26,11 @@ export const validError1 = {
message: dummyMessage,
data: Object.assign({}, dummyData),
};
export const validError2 = ethErrors.rpc.parse();
export const validError2 = rpcErrors.parse();
delete validError2.stack;
export const validError3 = ethErrors.rpc.parse(dummyMessage);
export const validError3 = rpcErrors.parse(dummyMessage);
delete validError3.stack;
export const validError4 = ethErrors.rpc.parse({
export const validError4 = rpcErrors.parse({
message: dummyMessage,
data: Object.assign({}, dummyData),
});
Expand Down
14 changes: 7 additions & 7 deletions src/classes.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import safeStringify from 'fast-safe-stringify';
import { Json, JsonRpcError } from '@metamask/utils';
import { Json, JsonRpcError as SerializedJsonRpcError } from '@metamask/utils';

export { JsonRpcError };
export { SerializedJsonRpcError };

/**
* Error subclass implementing JSON RPC 2.0 errors and Ethereum RPC errors
* per EIP-1474.
*
* Permits any integer error code.
*/
export class EthereumRpcError<T extends Json> extends Error {
export class JsonRpcError<T extends Json> extends Error {
public code: number;

public data?: T;
Expand All @@ -20,7 +20,7 @@ export class EthereumRpcError<T extends Json> extends Error {
}

if (!message || typeof message !== 'string') {
throw new Error('"message" must be a nonempty string.');
throw new Error('"message" must be a non-empty string.');
}

super(message);
Expand All @@ -35,8 +35,8 @@ export class EthereumRpcError<T extends Json> extends Error {
*
* @returns A plain object with all public class properties.
*/
serialize(): JsonRpcError {
const serialized: JsonRpcError = {
serialize(): SerializedJsonRpcError {
const serialized: SerializedJsonRpcError = {
code: this.code,
message: this.message,
};
Expand Down Expand Up @@ -65,7 +65,7 @@ export class EthereumRpcError<T extends Json> extends Error {
* Error subclass implementing Ethereum Provider errors per EIP-1193.
* Permits integer error codes in the [ 1000 <= 4999 ] range.
*/
export class EthereumProviderError<T extends Json> extends EthereumRpcError<T> {
export class EthereumProviderError<T extends Json> extends JsonRpcError<T> {
/**
* Create an Ethereum Provider JSON-RPC error.
*
Expand Down
61 changes: 31 additions & 30 deletions src/errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ import {
SERVER_ERROR_CODE,
CUSTOM_ERROR_CODE,
} from './__fixtures__';
import { ethErrors, errorCodes } from '.';
import { rpcErrors, providerErrors, errorCodes } from '.';

describe('ethErrors.rpc.invalidInput', () => {
describe('rpcErrors.invalidInput', () => {
it('accepts a single string argument where appropriate', () => {
const err = ethErrors.rpc.invalidInput(CUSTOM_ERROR_MESSAGE);
const err = rpcErrors.invalidInput(CUSTOM_ERROR_MESSAGE);
expect(err.code).toBe(errorCodes.rpc.invalidInput);
expect(err.message).toBe(CUSTOM_ERROR_MESSAGE);
});
});

describe('ethErrors.provider.unauthorized', () => {
describe('providerErrors.unauthorized', () => {
it('accepts a single string argument where appropriate', () => {
const err = ethErrors.provider.unauthorized(CUSTOM_ERROR_MESSAGE);
const err = providerErrors.unauthorized(CUSTOM_ERROR_MESSAGE);
expect(err.code).toBe(errorCodes.provider.unauthorized);
expect(err.message).toBe(CUSTOM_ERROR_MESSAGE);
});
Expand All @@ -27,7 +27,7 @@ describe('custom provider error options', () => {
it('throws if the value is not an options object', () => {
expect(() => {
// @ts-expect-error Invalid input
ethErrors.provider.custom('bar');
providerErrors.custom('bar');
}).toThrow(
'Ethereum Provider custom errors must provide single object argument.',
);
Expand All @@ -36,11 +36,11 @@ describe('custom provider error options', () => {
it('throws if the value is invalid', () => {
expect(() => {
// @ts-expect-error Invalid input
ethErrors.provider.custom({ code: 4009, message: 2 });
providerErrors.custom({ code: 4009, message: 2 });
}).toThrow('"message" must be a nonempty string');

expect(() => {
ethErrors.provider.custom({ code: 4009, message: '' });
providerErrors.custom({ code: 4009, message: '' });
}).toThrow('"message" must be a nonempty string');
});
});
Expand All @@ -49,24 +49,24 @@ describe('ethError.rpc.server', () => {
it('throws on invalid input', () => {
expect(() => {
// @ts-expect-error Invalid input
ethErrors.rpc.server('bar');
rpcErrors.server('bar');
}).toThrow(
'Ethereum RPC Server errors must provide single object argument.',
);

expect(() => {
// @ts-expect-error Invalid input
ethErrors.rpc.server({ code: 'bar' });
rpcErrors.server({ code: 'bar' });
}).toThrow('"code" must be an integer such that: -32099 <= code <= -32005');

expect(() => {
ethErrors.rpc.server({ code: 1 });
rpcErrors.server({ code: 1 });
}).toThrow('"code" must be an integer such that: -32099 <= code <= -32005');
});
});

describe('ethError.rpc', () => {
it.each(Object.entries(ethErrors.rpc).filter(([key]) => key !== 'server'))(
describe('rpcErrors', () => {
it.each(Object.entries(rpcErrors).filter(([key]) => key !== 'server'))(
'%s returns appropriate value',
(key, value) => {
const createError = value as any;
Expand All @@ -86,7 +86,7 @@ describe('ethError.rpc', () => {
);

it('server returns appropriate value', () => {
const error = ethErrors.rpc.server({
const error = rpcErrors.server({
code: SERVER_ERROR_CODE,
data: Object.assign({}, dummyData),
});
Expand All @@ -96,24 +96,25 @@ describe('ethError.rpc', () => {
});
});

describe('ethError.provider', () => {
it.each(
Object.entries(ethErrors.provider).filter(([key]) => key !== 'custom'),
)('%s returns appropriate value', (key, value) => {
const createError = value as any;
const error = createError({
message: null,
data: Object.assign({}, dummyData),
});
// @ts-expect-error TypeScript does not like indexing into this with the key
const providerCode = errorCodes.provider[key];
expect(error.code >= 1000 && error.code < 5000).toBe(true);
expect(error.code).toBe(providerCode);
expect(error.message).toBe(getMessageFromCode(providerCode));
});
describe('providerErrors', () => {
it.each(Object.entries(providerErrors).filter(([key]) => key !== 'custom'))(
'%s returns appropriate value',
(key, value) => {
const createError = value as any;
const error = createError({
message: null,
data: Object.assign({}, dummyData),
});
// @ts-expect-error TypeScript does not like indexing into this with the key
const providerCode = errorCodes.provider[key];
expect(error.code >= 1000 && error.code < 5000).toBe(true);
expect(error.code).toBe(providerCode);
expect(error.message).toBe(getMessageFromCode(providerCode));
},
);

it('custom returns appropriate value', () => {
const error = ethErrors.provider.custom({
const error = providerErrors.custom({
code: CUSTOM_ERROR_CODE,
message: CUSTOM_ERROR_MESSAGE,
data: Object.assign({}, dummyData),
Expand Down
Loading