Skip to content
This repository was archived by the owner on Nov 9, 2023. It is now read-only.

Commit 61e159f

Browse files
authored
BREAKING: Use @metamask/utils (#105)
Replace various utility types and functions with implementations copied over to `@metamask/utils`. Functionality should be practically identical. The one possible deviation is that two `in` checks have been replaced with `hasProperty`, which does not walk the prototype chain. This should not be breaking for our purposes.
1 parent 07f7604 commit 61e159f

13 files changed

+72
-391
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
},
3333
"dependencies": {
3434
"@metamask/safe-event-emitter": "^2.0.0",
35+
"@metamask/utils": "^2.0.0",
3536
"eth-rpc-errors": "^4.0.2"
3637
},
3738
"devDependencies": {

src/JsonRpcEngine.ts

Lines changed: 30 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,19 @@
11
import SafeEventEmitter from '@metamask/safe-event-emitter';
2+
import {
3+
hasProperty,
4+
JsonRpcError,
5+
JsonRpcRequest,
6+
JsonRpcResponse,
7+
} from '@metamask/utils';
28
import { errorCodes, EthereumRpcError, serializeError } from 'eth-rpc-errors';
39

4-
type Maybe<T> = Partial<T> | null | undefined;
5-
6-
export type Json =
7-
| boolean
8-
| number
9-
| string
10-
| null
11-
| { [property: string]: Json }
12-
| Json[];
13-
14-
/**
15-
* A String specifying the version of the JSON-RPC protocol.
16-
* MUST be exactly "2.0".
17-
*/
18-
export type JsonRpcVersion = '2.0';
19-
20-
/**
21-
* An identifier established by the Client that MUST contain a String, Number,
22-
* or NULL value if included. If it is not included it is assumed to be a
23-
* notification. The value SHOULD normally not be Null and Numbers SHOULD
24-
* NOT contain fractional parts.
25-
*/
26-
export type JsonRpcId = number | string | null;
27-
28-
export interface JsonRpcError {
29-
code: number;
30-
message: string;
31-
data?: unknown;
32-
stack?: string;
33-
}
34-
35-
export interface JsonRpcRequest<T> {
36-
jsonrpc: JsonRpcVersion;
37-
method: string;
38-
id: JsonRpcId;
39-
params?: T;
40-
}
41-
42-
export interface JsonRpcNotification<T> {
43-
jsonrpc: JsonRpcVersion;
44-
method: string;
45-
params?: T;
46-
}
47-
48-
interface JsonRpcResponseBase {
49-
jsonrpc: JsonRpcVersion;
50-
id: JsonRpcId;
51-
}
52-
53-
export interface JsonRpcSuccess<T> extends JsonRpcResponseBase {
54-
result: Maybe<T>;
55-
}
56-
57-
export interface JsonRpcFailure extends JsonRpcResponseBase {
58-
error: JsonRpcError;
59-
}
60-
61-
export type JsonRpcResponse<T> = JsonRpcSuccess<T> | JsonRpcFailure;
62-
63-
export interface PendingJsonRpcResponse<T> extends JsonRpcResponseBase {
64-
result?: T;
65-
error?: Error | JsonRpcError;
66-
}
10+
export type PendingJsonRpcResponse<Result> = Omit<
11+
JsonRpcResponse<Result>,
12+
'error' | 'result'
13+
> & {
14+
result?: Result;
15+
error?: JsonRpcError;
16+
};
6717

6818
export type JsonRpcEngineCallbackError = Error | JsonRpcError | null;
6919

@@ -79,9 +29,9 @@ export type JsonRpcEngineEndCallback = (
7929
error?: JsonRpcEngineCallbackError,
8030
) => void;
8131

82-
export type JsonRpcMiddleware<T, U> = (
83-
req: JsonRpcRequest<T>,
84-
res: PendingJsonRpcResponse<U>,
32+
export type JsonRpcMiddleware<Params, Result> = (
33+
req: JsonRpcRequest<Params>,
34+
res: PendingJsonRpcResponse<Result>,
8535
next: JsonRpcEngineNextCallback,
8636
end: JsonRpcEngineEndCallback,
8737
) => void;
@@ -103,7 +53,7 @@ export class JsonRpcEngine extends SafeEventEmitter {
10353
*
10454
* @param middleware - The middleware function to add.
10555
*/
106-
push<T, U>(middleware: JsonRpcMiddleware<T, U>): void {
56+
push<Params, Result>(middleware: JsonRpcMiddleware<Params, Result>): void {
10757
this._middleware.push(middleware as JsonRpcMiddleware<unknown, unknown>);
10858
}
10959

@@ -113,9 +63,9 @@ export class JsonRpcEngine extends SafeEventEmitter {
11363
* @param request - The request to handle.
11464
* @param callback - An error-first callback that will receive the response.
11565
*/
116-
handle<T, U>(
117-
request: JsonRpcRequest<T>,
118-
callback: (error: unknown, response: JsonRpcResponse<U>) => void,
66+
handle<Params, Result>(
67+
request: JsonRpcRequest<Params>,
68+
callback: (error: unknown, response: JsonRpcResponse<Result>) => void,
11969
): void;
12070

12171
/**
@@ -125,9 +75,9 @@ export class JsonRpcEngine extends SafeEventEmitter {
12575
* @param callback - An error-first callback that will receive the array of
12676
* responses.
12777
*/
128-
handle<T, U>(
129-
requests: JsonRpcRequest<T>[],
130-
callback: (error: unknown, responses: JsonRpcResponse<U>[]) => void,
78+
handle<Params, Result>(
79+
requests: JsonRpcRequest<Params>[],
80+
callback: (error: unknown, responses: JsonRpcResponse<Result>[]) => void,
13181
): void;
13282

13383
/**
@@ -136,15 +86,19 @@ export class JsonRpcEngine extends SafeEventEmitter {
13686
* @param request - The JSON-RPC request to handle.
13787
* @returns The JSON-RPC response.
13888
*/
139-
handle<T, U>(request: JsonRpcRequest<T>): Promise<JsonRpcResponse<U>>;
89+
handle<Params, Result>(
90+
request: JsonRpcRequest<Params>,
91+
): Promise<JsonRpcResponse<Result>>;
14092

14193
/**
14294
* Handle an array of JSON-RPC requests, and return an array of responses.
14395
*
14496
* @param request - The JSON-RPC requests to handle.
14597
* @returns An array of JSON-RPC responses.
14698
*/
147-
handle<T, U>(requests: JsonRpcRequest<T>[]): Promise<JsonRpcResponse<U>[]>;
99+
handle<Params, Result>(
100+
requests: JsonRpcRequest<Params>[],
101+
): Promise<JsonRpcResponse<Result>[]>;
148102

149103
handle(req: unknown, callback?: any) {
150104
if (callback && typeof callback !== 'function') {
@@ -487,7 +441,7 @@ export class JsonRpcEngine extends SafeEventEmitter {
487441
res: PendingJsonRpcResponse<unknown>,
488442
isComplete: boolean,
489443
): void {
490-
if (!('result' in res) && !('error' in res)) {
444+
if (!hasProperty(res, 'result') && !hasProperty(res, 'error')) {
491445
throw new EthereumRpcError(
492446
errorCodes.rpc.internal,
493447
`JsonRpcEngine: Response has no error or result for request:\n${jsonify(

src/asMiddleware.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
22
assertIsJsonRpcSuccess,
33
isJsonRpcSuccess,
4-
JsonRpcEngine,
54
JsonRpcRequest,
6-
} from '.';
5+
} from '@metamask/utils';
6+
import { JsonRpcEngine } from '.';
77

88
const jsonrpc = '2.0' as const;
99

src/createAsyncMiddleware.test.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
import {
2-
JsonRpcEngine,
3-
createAsyncMiddleware,
4-
assertIsJsonRpcSuccess,
5-
} from '.';
1+
import { assertIsJsonRpcSuccess } from '@metamask/utils';
2+
import { JsonRpcEngine, createAsyncMiddleware } from '.';
63

74
const jsonrpc = '2.0' as const;
85

src/createAsyncMiddleware.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
import {
2-
JsonRpcMiddleware,
3-
JsonRpcRequest,
4-
PendingJsonRpcResponse,
5-
} from './JsonRpcEngine';
1+
import { JsonRpcRequest } from '@metamask/utils';
2+
import { JsonRpcMiddleware, PendingJsonRpcResponse } from './JsonRpcEngine';
63

74
export type AsyncJsonRpcEngineNextCallback = () => Promise<void>;
85

9-
export type AsyncJsonrpcMiddleware<T, U> = (
10-
req: JsonRpcRequest<T>,
11-
res: PendingJsonRpcResponse<U>,
6+
export type AsyncJsonrpcMiddleware<Params, Result> = (
7+
req: JsonRpcRequest<Params>,
8+
res: PendingJsonRpcResponse<Result>,
129
next: AsyncJsonRpcEngineNextCallback,
1310
) => Promise<void>;
1411

@@ -35,9 +32,9 @@ type ReturnHandlerCallback = (error: null | Error) => void;
3532
* @returns The wrapped asynchronous middleware function, ready to be consumed
3633
* by JsonRpcEngine.
3734
*/
38-
export function createAsyncMiddleware<T, U>(
39-
asyncMiddleware: AsyncJsonrpcMiddleware<T, U>,
40-
): JsonRpcMiddleware<T, U> {
35+
export function createAsyncMiddleware<Params, Result>(
36+
asyncMiddleware: AsyncJsonrpcMiddleware<Params, Result>,
37+
): JsonRpcMiddleware<Params, Result> {
4138
return async (req, res, next, end) => {
4239
// nextPromise is the key to the implementation
4340
// it is resolved by the return handler passed to the

src/createScaffoldMiddleware.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import {
2-
JsonRpcEngine,
3-
createScaffoldMiddleware,
4-
JsonRpcMiddleware,
52
assertIsJsonRpcSuccess,
63
assertIsJsonRpcFailure,
7-
} from '.';
4+
} from '@metamask/utils';
5+
import { ethErrors } from 'eth-rpc-errors';
6+
import { JsonRpcEngine, createScaffoldMiddleware, JsonRpcMiddleware } from '.';
87

98
describe('createScaffoldMiddleware', () => {
109
it('basic middleware test', async () => {
@@ -20,7 +19,7 @@ describe('createScaffoldMiddleware', () => {
2019
end();
2120
},
2221
method3: (_req, res, _next, end) => {
23-
res.error = new Error('method3');
22+
res.error = ethErrors.rpc.internal({ message: 'method3' });
2423
end();
2524
},
2625
};

src/createScaffoldMiddleware.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import { Json, JsonRpcMiddleware, JsonRpcSuccess } from './JsonRpcEngine';
1+
import { Json, JsonRpcSuccess } from '@metamask/utils';
2+
import { JsonRpcMiddleware } from './JsonRpcEngine';
23

3-
type ScaffoldMiddlewareHandler<T, U> = JsonRpcMiddleware<T, U> | Json;
4+
type ScaffoldMiddlewareHandler<Params, Result> =
5+
| JsonRpcMiddleware<Params, Result>
6+
| Json;
47

58
/**
69
* Creates a middleware function from an object of RPC method handler functions,

src/engine.test.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { isJsonRpcFailure, isJsonRpcSuccess } from './utils';
21
import {
3-
JsonRpcEngine,
42
assertIsJsonRpcSuccess,
53
assertIsJsonRpcFailure,
6-
} from '.';
4+
isJsonRpcFailure,
5+
isJsonRpcSuccess,
6+
} from '@metamask/utils';
7+
import { ethErrors } from 'eth-rpc-errors';
8+
import { JsonRpcEngine } from '.';
79

810
const jsonrpc = '2.0' as const;
911

@@ -187,7 +189,7 @@ describe('JsonRpcEngine', () => {
187189
const engine = new JsonRpcEngine();
188190

189191
engine.push(function (_req, res, next, _end) {
190-
res.error = new Error('no bueno');
192+
res.error = ethErrors.rpc.internal({ message: 'foobar' });
191193
next();
192194
});
193195

@@ -208,7 +210,7 @@ describe('JsonRpcEngine', () => {
208210
const engine = new JsonRpcEngine();
209211

210212
engine.push(function (_req, res, _next, end) {
211-
res.error = new Error('no bueno');
213+
res.error = ethErrors.rpc.internal({ message: 'foobar' });
212214
end();
213215
});
214216

@@ -270,7 +272,7 @@ describe('JsonRpcEngine', () => {
270272
engine.push(function (req, res, _next, end) {
271273
if (req.id === 4) {
272274
delete res.result;
273-
res.error = new Error('foobar');
275+
res.error = ethErrors.rpc.internal({ message: 'foobar' });
274276
return end(res.error);
275277
}
276278
res.result = req.id;
@@ -305,7 +307,7 @@ describe('JsonRpcEngine', () => {
305307
engine.push(function (req, res, _next, end) {
306308
if (req.id === 4) {
307309
delete res.result;
308-
res.error = new Error('foobar');
310+
res.error = ethErrors.rpc.internal({ message: 'foobar' });
309311
return end(res.error);
310312
}
311313
res.result = req.id;

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,3 @@ export * from './getUniqueId';
44
export * from './idRemapMiddleware';
55
export * from './JsonRpcEngine';
66
export * from './mergeMiddleware';
7-
export * from './utils';

src/mergeMiddleware.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
22
assertIsJsonRpcSuccess,
3-
JsonRpcEngine,
3+
hasProperty,
44
JsonRpcRequest,
5-
mergeMiddleware,
6-
} from '.';
5+
} from '@metamask/utils';
6+
import { JsonRpcEngine, mergeMiddleware } from '.';
77

88
const jsonrpc = '2.0' as const;
99

@@ -30,7 +30,7 @@ describe('mergeMiddleware', () => {
3030
expect(res).toBeDefined();
3131
expect(originalReq.id).toStrictEqual(res.id);
3232
expect(originalReq.jsonrpc).toStrictEqual(res.jsonrpc);
33-
expect('result' in res).toBe(true);
33+
expect(hasProperty(res, 'result')).toBe(true);
3434
resolve();
3535
});
3636
});

0 commit comments

Comments
 (0)