@metamask-previews/json-rpc-engine 10.1.1-preview-63ea58af → 10.1.1-preview-0458fe94
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 +11 -0
- package/README.md +647 -124
- package/dist/JsonRpcEngine.cjs +11 -13
- package/dist/JsonRpcEngine.cjs.map +1 -1
- package/dist/JsonRpcEngine.d.cts +18 -0
- package/dist/JsonRpcEngine.d.cts.map +1 -1
- package/dist/JsonRpcEngine.d.mts +18 -0
- package/dist/JsonRpcEngine.d.mts.map +1 -1
- package/dist/JsonRpcEngine.mjs +11 -13
- package/dist/JsonRpcEngine.mjs.map +1 -1
- package/dist/asV2Middleware.cjs +48 -0
- package/dist/asV2Middleware.cjs.map +1 -0
- package/dist/asV2Middleware.d.cts +11 -0
- package/dist/asV2Middleware.d.cts.map +1 -0
- package/dist/asV2Middleware.d.mts +11 -0
- package/dist/asV2Middleware.d.mts.map +1 -0
- package/dist/asV2Middleware.mjs +44 -0
- package/dist/asV2Middleware.mjs.map +1 -0
- package/dist/createAsyncMiddleware.cjs +1 -0
- package/dist/createAsyncMiddleware.cjs.map +1 -1
- package/dist/createAsyncMiddleware.d.cts +1 -0
- package/dist/createAsyncMiddleware.d.cts.map +1 -1
- package/dist/createAsyncMiddleware.d.mts +1 -0
- package/dist/createAsyncMiddleware.d.mts.map +1 -1
- package/dist/createAsyncMiddleware.mjs +1 -0
- package/dist/createAsyncMiddleware.mjs.map +1 -1
- package/dist/createScaffoldMiddleware.cjs +1 -0
- package/dist/createScaffoldMiddleware.cjs.map +1 -1
- package/dist/createScaffoldMiddleware.d.cts +1 -0
- package/dist/createScaffoldMiddleware.d.cts.map +1 -1
- package/dist/createScaffoldMiddleware.d.mts +1 -0
- package/dist/createScaffoldMiddleware.d.mts.map +1 -1
- package/dist/createScaffoldMiddleware.mjs +1 -0
- package/dist/createScaffoldMiddleware.mjs.map +1 -1
- package/dist/idRemapMiddleware.cjs +1 -0
- package/dist/idRemapMiddleware.cjs.map +1 -1
- package/dist/idRemapMiddleware.d.cts +1 -0
- package/dist/idRemapMiddleware.d.cts.map +1 -1
- package/dist/idRemapMiddleware.d.mts +1 -0
- package/dist/idRemapMiddleware.d.mts.map +1 -1
- package/dist/idRemapMiddleware.mjs +1 -0
- package/dist/idRemapMiddleware.mjs.map +1 -1
- package/dist/index.cjs +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/mergeMiddleware.cjs +1 -0
- package/dist/mergeMiddleware.cjs.map +1 -1
- package/dist/mergeMiddleware.d.cts +1 -0
- package/dist/mergeMiddleware.d.cts.map +1 -1
- package/dist/mergeMiddleware.d.mts +1 -0
- package/dist/mergeMiddleware.d.mts.map +1 -1
- package/dist/mergeMiddleware.mjs +1 -0
- package/dist/mergeMiddleware.mjs.map +1 -1
- package/dist/v2/JsonRpcEngineV2.cjs +213 -0
- package/dist/v2/JsonRpcEngineV2.cjs.map +1 -0
- package/dist/v2/JsonRpcEngineV2.d.cts +122 -0
- package/dist/v2/JsonRpcEngineV2.d.cts.map +1 -0
- package/dist/v2/JsonRpcEngineV2.d.mts +122 -0
- package/dist/v2/JsonRpcEngineV2.d.mts.map +1 -0
- package/dist/v2/JsonRpcEngineV2.mjs +213 -0
- package/dist/v2/JsonRpcEngineV2.mjs.map +1 -0
- package/dist/v2/JsonRpcServer.cjs +162 -0
- package/dist/v2/JsonRpcServer.cjs.map +1 -0
- package/dist/v2/JsonRpcServer.d.cts +85 -0
- package/dist/v2/JsonRpcServer.d.cts.map +1 -0
- package/dist/v2/JsonRpcServer.d.mts +85 -0
- package/dist/v2/JsonRpcServer.d.mts.map +1 -0
- package/dist/v2/JsonRpcServer.mjs +158 -0
- package/dist/v2/JsonRpcServer.mjs.map +1 -0
- package/dist/v2/MiddlewareContext.cjs +66 -0
- package/dist/v2/MiddlewareContext.cjs.map +1 -0
- package/dist/v2/MiddlewareContext.d.cts +95 -0
- package/dist/v2/MiddlewareContext.d.cts.map +1 -0
- package/dist/v2/MiddlewareContext.d.mts +95 -0
- package/dist/v2/MiddlewareContext.d.mts.map +1 -0
- package/dist/v2/MiddlewareContext.mjs +62 -0
- package/dist/v2/MiddlewareContext.mjs.map +1 -0
- package/dist/v2/asLegacyMiddleware.cjs +39 -0
- package/dist/v2/asLegacyMiddleware.cjs.map +1 -0
- package/dist/v2/asLegacyMiddleware.d.cts +11 -0
- package/dist/v2/asLegacyMiddleware.d.cts.map +1 -0
- package/dist/v2/asLegacyMiddleware.d.mts +11 -0
- package/dist/v2/asLegacyMiddleware.d.mts.map +1 -0
- package/dist/v2/asLegacyMiddleware.mjs +35 -0
- package/dist/v2/asLegacyMiddleware.mjs.map +1 -0
- package/dist/v2/compatibility-utils.cjs +151 -0
- package/dist/v2/compatibility-utils.cjs.map +1 -0
- package/dist/v2/compatibility-utils.d.cts +75 -0
- package/dist/v2/compatibility-utils.d.cts.map +1 -0
- package/dist/v2/compatibility-utils.d.mts +75 -0
- package/dist/v2/compatibility-utils.d.mts.map +1 -0
- package/dist/v2/compatibility-utils.mjs +142 -0
- package/dist/v2/compatibility-utils.mjs.map +1 -0
- package/dist/v2/index.cjs +29 -0
- package/dist/v2/index.cjs.map +1 -0
- package/dist/v2/index.d.cts +8 -0
- package/dist/v2/index.d.cts.map +1 -0
- package/dist/v2/index.d.mts +8 -0
- package/dist/v2/index.d.mts.map +1 -0
- package/dist/v2/index.mjs +6 -0
- package/dist/v2/index.mjs.map +1 -0
- package/dist/v2/utils.cjs +41 -0
- package/dist/v2/utils.cjs.map +1 -0
- package/dist/v2/utils.d.cts +35 -0
- package/dist/v2/utils.d.cts.map +1 -0
- package/dist/v2/utils.d.mts +35 -0
- package/dist/v2/utils.d.mts.map +1 -0
- package/dist/v2/utils.mjs +34 -0
- package/dist/v2/utils.mjs.map +1 -0
- package/package.json +17 -3
- package/v2.js +3 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _JsonRpcEngineV2_instances, _JsonRpcEngineV2_middleware, _JsonRpcEngineV2_isDestroyed, _JsonRpcEngineV2_handle, _JsonRpcEngineV2_makeNextFactory, _JsonRpcEngineV2_makeMiddlewareIterator, _JsonRpcEngineV2_updateResult, _JsonRpcEngineV2_assertValidNextRequest, _JsonRpcEngineV2_assertIsNotDestroyed;
|
|
13
|
+
function $importDefault(module) {
|
|
14
|
+
if (module?.__esModule) {
|
|
15
|
+
return module.default;
|
|
16
|
+
}
|
|
17
|
+
return module;
|
|
18
|
+
}
|
|
19
|
+
import { hasProperty } from "@metamask/utils";
|
|
20
|
+
import $deepFreeze from "deep-freeze-strict";
|
|
21
|
+
const deepFreeze = $importDefault($deepFreeze);
|
|
22
|
+
import { MiddlewareContext } from "./MiddlewareContext.mjs";
|
|
23
|
+
import { isNotification, isRequest, JsonRpcEngineError, stringify } from "./utils.mjs";
|
|
24
|
+
const INVALID_ENGINE = Symbol('Invalid engine');
|
|
25
|
+
/**
|
|
26
|
+
* A JSON-RPC request and response processor.
|
|
27
|
+
*
|
|
28
|
+
* Give it a stack of middleware, pass it requests, and get back responses.
|
|
29
|
+
*
|
|
30
|
+
* #### Requests vs. notifications
|
|
31
|
+
*
|
|
32
|
+
* JSON-RPC requests come in two flavors:
|
|
33
|
+
*
|
|
34
|
+
* - [Requests](https://www.jsonrpc.org/specification#request_object), i.e. request objects _with_ an `id`
|
|
35
|
+
* - [Notifications](https://www.jsonrpc.org/specification#notification), i.e. request objects _without_ an `id`
|
|
36
|
+
*
|
|
37
|
+
* For requests, one of the engine's middleware must "end" the request by returning a non-`undefined` result,
|
|
38
|
+
* or {@link handle} will throw an error:
|
|
39
|
+
*
|
|
40
|
+
* For notifications, on the other hand, one of the engine's middleware must return `undefined` to end the request,
|
|
41
|
+
* and any non-`undefined` return values will cause an error:
|
|
42
|
+
*
|
|
43
|
+
* @template Request - The type of request to handle.
|
|
44
|
+
* @template Result - The type of result to return.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const engine = JsonRpcEngineV2.create({
|
|
49
|
+
* middleware,
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* try {
|
|
53
|
+
* const result = await engine.handle(request);
|
|
54
|
+
* // Handle result
|
|
55
|
+
* } catch (error) {
|
|
56
|
+
* // Handle error
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export class JsonRpcEngineV2 {
|
|
61
|
+
// See .create() for why this is private.
|
|
62
|
+
constructor({ middleware }) {
|
|
63
|
+
_JsonRpcEngineV2_instances.add(this);
|
|
64
|
+
_JsonRpcEngineV2_middleware.set(this, void 0);
|
|
65
|
+
_JsonRpcEngineV2_isDestroyed.set(this, false);
|
|
66
|
+
__classPrivateFieldSet(this, _JsonRpcEngineV2_middleware, [...middleware], "f");
|
|
67
|
+
}
|
|
68
|
+
// We use a static factory method in order to construct a supertype of all middleware contexts,
|
|
69
|
+
// which enables us to instantiate an engine despite different middleware expecting different
|
|
70
|
+
// context types.
|
|
71
|
+
/**
|
|
72
|
+
* Create a new JSON-RPC engine.
|
|
73
|
+
*
|
|
74
|
+
* @throws If the middleware array is empty.
|
|
75
|
+
* @param options - The options for the engine.
|
|
76
|
+
* @param options.middleware - The middleware to use.
|
|
77
|
+
* @returns The JSON-RPC engine.
|
|
78
|
+
*/
|
|
79
|
+
static create({ middleware }) {
|
|
80
|
+
// We can't use NonEmptyArray for the params because it ruins type inference.
|
|
81
|
+
if (middleware.length === 0) {
|
|
82
|
+
throw new JsonRpcEngineError('Middleware array cannot be empty');
|
|
83
|
+
}
|
|
84
|
+
const mw = middleware;
|
|
85
|
+
return new JsonRpcEngineV2({
|
|
86
|
+
middleware: mw,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async handle(request, { context } = {}) {
|
|
90
|
+
const isReq = isRequest(request);
|
|
91
|
+
const { result } = await __classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_handle).call(this, request, context);
|
|
92
|
+
if (isReq && result === undefined) {
|
|
93
|
+
throw new JsonRpcEngineError(`Nothing ended request: ${stringify(request)}`);
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Convert the engine into a JSON-RPC middleware.
|
|
99
|
+
*
|
|
100
|
+
* @returns The JSON-RPC middleware.
|
|
101
|
+
*/
|
|
102
|
+
asMiddleware() {
|
|
103
|
+
__classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_assertIsNotDestroyed).call(this);
|
|
104
|
+
return async ({ request, context, next }) => {
|
|
105
|
+
const { result, request: finalRequest } = await __classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_handle).call(this, request, context);
|
|
106
|
+
return result === undefined ? await next(finalRequest) : result;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Destroy the engine. Calls the `destroy()` method of any middleware that has
|
|
111
|
+
* one. Attempting to use the engine after destroying it will throw an error.
|
|
112
|
+
*/
|
|
113
|
+
async destroy() {
|
|
114
|
+
if (__classPrivateFieldGet(this, _JsonRpcEngineV2_isDestroyed, "f")) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
__classPrivateFieldSet(this, _JsonRpcEngineV2_isDestroyed, true, "f");
|
|
118
|
+
const destructionPromise = Promise.all(__classPrivateFieldGet(this, _JsonRpcEngineV2_middleware, "f").map(async (middleware) => {
|
|
119
|
+
if (
|
|
120
|
+
// Intentionally using `in` to walk the prototype chain.
|
|
121
|
+
'destroy' in middleware &&
|
|
122
|
+
typeof middleware.destroy === 'function') {
|
|
123
|
+
return middleware.destroy();
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
}));
|
|
127
|
+
__classPrivateFieldSet(this, _JsonRpcEngineV2_middleware, [], "f");
|
|
128
|
+
await destructionPromise;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
_JsonRpcEngineV2_middleware = new WeakMap(), _JsonRpcEngineV2_isDestroyed = new WeakMap(), _JsonRpcEngineV2_instances = new WeakSet(), _JsonRpcEngineV2_handle =
|
|
132
|
+
/**
|
|
133
|
+
* Handle a JSON-RPC request. Throws if a middleware performs an invalid
|
|
134
|
+
* operation. Permits returning an `undefined` result.
|
|
135
|
+
*
|
|
136
|
+
* @param originalRequest - The JSON-RPC request to handle.
|
|
137
|
+
* @param context - The context to pass to the middleware.
|
|
138
|
+
* @returns The result from the middleware.
|
|
139
|
+
*/
|
|
140
|
+
async function _JsonRpcEngineV2_handle(originalRequest, context = new MiddlewareContext()) {
|
|
141
|
+
__classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_assertIsNotDestroyed).call(this);
|
|
142
|
+
deepFreeze(originalRequest);
|
|
143
|
+
const state = {
|
|
144
|
+
request: originalRequest,
|
|
145
|
+
result: undefined,
|
|
146
|
+
};
|
|
147
|
+
const middlewareIterator = __classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_makeMiddlewareIterator).call(this);
|
|
148
|
+
const firstMiddleware = middlewareIterator.next().value;
|
|
149
|
+
const makeNext = __classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_makeNextFactory).call(this, middlewareIterator, state, context);
|
|
150
|
+
const result = await firstMiddleware({
|
|
151
|
+
request: originalRequest,
|
|
152
|
+
context,
|
|
153
|
+
next: makeNext(),
|
|
154
|
+
});
|
|
155
|
+
__classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_updateResult).call(this, result, state);
|
|
156
|
+
return state;
|
|
157
|
+
}, _JsonRpcEngineV2_makeNextFactory = function _JsonRpcEngineV2_makeNextFactory(middlewareIterator, state, context) {
|
|
158
|
+
const makeNext = () => {
|
|
159
|
+
let wasCalled = false;
|
|
160
|
+
const next = async (request = state.request) => {
|
|
161
|
+
if (wasCalled) {
|
|
162
|
+
throw new JsonRpcEngineError(`Middleware attempted to call next() multiple times for request: ${stringify(request)}`);
|
|
163
|
+
}
|
|
164
|
+
wasCalled = true;
|
|
165
|
+
if (request !== state.request) {
|
|
166
|
+
__classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_assertValidNextRequest).call(this, state.request, request);
|
|
167
|
+
state.request = deepFreeze(request);
|
|
168
|
+
}
|
|
169
|
+
const { value: nextMiddleware, done } = middlewareIterator.next();
|
|
170
|
+
if (done) {
|
|
171
|
+
// This will cause the last middleware to return `undefined`. See the class
|
|
172
|
+
// JSDoc or package README for more details.
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
const result = await nextMiddleware({
|
|
176
|
+
request,
|
|
177
|
+
context,
|
|
178
|
+
next: makeNext(),
|
|
179
|
+
});
|
|
180
|
+
__classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_updateResult).call(this, result, state);
|
|
181
|
+
return state.result;
|
|
182
|
+
};
|
|
183
|
+
return next;
|
|
184
|
+
};
|
|
185
|
+
return makeNext;
|
|
186
|
+
}, _JsonRpcEngineV2_makeMiddlewareIterator = function _JsonRpcEngineV2_makeMiddlewareIterator() {
|
|
187
|
+
return __classPrivateFieldGet(this, _JsonRpcEngineV2_middleware, "f")[Symbol.iterator]();
|
|
188
|
+
}, _JsonRpcEngineV2_updateResult = function _JsonRpcEngineV2_updateResult(result, state) {
|
|
189
|
+
if (isNotification(state.request) && result !== undefined) {
|
|
190
|
+
throw new JsonRpcEngineError(`Result returned for notification: ${stringify(state.request)}`);
|
|
191
|
+
}
|
|
192
|
+
if (result !== undefined && result !== state.result) {
|
|
193
|
+
if (typeof result === 'object' && result !== null) {
|
|
194
|
+
deepFreeze(result);
|
|
195
|
+
}
|
|
196
|
+
state.result = result;
|
|
197
|
+
}
|
|
198
|
+
}, _JsonRpcEngineV2_assertValidNextRequest = function _JsonRpcEngineV2_assertValidNextRequest(currentRequest, nextRequest) {
|
|
199
|
+
if (nextRequest.jsonrpc !== currentRequest.jsonrpc) {
|
|
200
|
+
throw new JsonRpcEngineError(`Middleware attempted to modify readonly property "jsonrpc" for request: ${stringify(currentRequest)}`);
|
|
201
|
+
}
|
|
202
|
+
if (hasProperty(nextRequest, 'id') !== hasProperty(currentRequest, 'id') ||
|
|
203
|
+
// @ts-expect-error - "id" does not exist on notifications, but we can still
|
|
204
|
+
// check the value of the property at runtime.
|
|
205
|
+
nextRequest.id !== currentRequest.id) {
|
|
206
|
+
throw new JsonRpcEngineError(`Middleware attempted to modify readonly property "id" for request: ${stringify(currentRequest)}`);
|
|
207
|
+
}
|
|
208
|
+
}, _JsonRpcEngineV2_assertIsNotDestroyed = function _JsonRpcEngineV2_assertIsNotDestroyed() {
|
|
209
|
+
if (__classPrivateFieldGet(this, _JsonRpcEngineV2_isDestroyed, "f")) {
|
|
210
|
+
throw new JsonRpcEngineError('Engine is destroyed');
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
//# sourceMappingURL=JsonRpcEngineV2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonRpcEngineV2.mjs","sourceRoot":"","sources":["../../src/v2/JsonRpcEngineV2.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Json,\n type JsonRpcRequest,\n type JsonRpcNotification,\n type NonEmptyArray,\n hasProperty,\n} from '@metamask/utils';\nimport deepFreeze from 'deep-freeze-strict';\n\nimport type { ContextConstraint, MergeContexts } from './MiddlewareContext';\nimport { MiddlewareContext } from './MiddlewareContext';\nimport {\n isNotification,\n isRequest,\n JsonRpcEngineError,\n stringify,\n} from './utils';\nimport type { JsonRpcCall } from './utils';\n\n// Helper to forbid `id` on notifications\ntype WithoutId<Request extends JsonRpcCall> = Request & { id?: never };\n\n// Helper to enable JsonRpcCall overload of handle()\ntype MixedParam<Request extends JsonRpcCall> = [\n Extract<Request, JsonRpcRequest>,\n] extends [never]\n ? never\n : [Extract<Request, JsonRpcNotification>] extends [never]\n ? never\n :\n | Extract<Request, JsonRpcRequest>\n | WithoutId<Extract<Request, JsonRpcNotification>>;\n\nexport type ResultConstraint<Request extends JsonRpcCall> =\n Request extends JsonRpcRequest ? Json : void;\n\nexport type Next<Request extends JsonRpcCall> = (\n request?: Readonly<Request>,\n) => Promise<Readonly<ResultConstraint<Request>> | undefined>;\n\nexport type MiddlewareParams<\n Request extends JsonRpcCall,\n Context extends MiddlewareContext,\n> = {\n request: Readonly<Request>;\n context: Context;\n next: Next<Request>;\n};\n\nexport type JsonRpcMiddleware<\n Request extends JsonRpcCall = JsonRpcCall,\n Result extends ResultConstraint<Request> = ResultConstraint<Request>,\n Context extends ContextConstraint = MiddlewareContext,\n> = (\n params: MiddlewareParams<Request, Context>,\n) => Readonly<Result> | undefined | Promise<Readonly<Result> | undefined>;\n\ntype RequestState<Request extends JsonRpcCall> = {\n request: Request;\n result: Readonly<ResultConstraint<Request>> | undefined;\n};\n\ntype HandleOptions<Context extends MiddlewareContext> = {\n context?: Context;\n};\n\ntype ConstructorOptions<\n Request extends JsonRpcCall,\n Context extends MiddlewareContext,\n> = {\n middleware: NonEmptyArray<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >;\n};\n\ntype RequestOf<Middleware> =\n Middleware extends JsonRpcMiddleware<\n infer Request,\n ResultConstraint<infer Request>,\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any\n >\n ? Request\n : never;\n\ntype ContextOf<Middleware> =\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Middleware extends JsonRpcMiddleware<any, ResultConstraint<any>, infer C>\n ? C\n : never;\n\ntype MergedContextOf<\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Middleware extends JsonRpcMiddleware<any, any, any>,\n> = MergeContexts<ContextOf<Middleware>>;\n\nconst INVALID_ENGINE = Symbol('Invalid engine');\n\n/**\n * An internal type for invalid engines that explains why the engine is invalid.\n *\n * @template Message - The message explaining why the engine is invalid.\n */\ntype InvalidEngine<Message extends string> = { [INVALID_ENGINE]: Message };\n\n/**\n * A JSON-RPC request and response processor.\n *\n * Give it a stack of middleware, pass it requests, and get back responses.\n *\n * #### Requests vs. notifications\n *\n * JSON-RPC requests come in two flavors:\n *\n * - [Requests](https://www.jsonrpc.org/specification#request_object), i.e. request objects _with_ an `id`\n * - [Notifications](https://www.jsonrpc.org/specification#notification), i.e. request objects _without_ an `id`\n *\n * For requests, one of the engine's middleware must \"end\" the request by returning a non-`undefined` result,\n * or {@link handle} will throw an error:\n *\n * For notifications, on the other hand, one of the engine's middleware must return `undefined` to end the request,\n * and any non-`undefined` return values will cause an error:\n *\n * @template Request - The type of request to handle.\n * @template Result - The type of result to return.\n *\n * @example\n * ```ts\n * const engine = JsonRpcEngineV2.create({\n * middleware,\n * });\n *\n * try {\n * const result = await engine.handle(request);\n * // Handle result\n * } catch (error) {\n * // Handle error\n * }\n * ```\n */\nexport class JsonRpcEngineV2<\n Request extends JsonRpcCall = JsonRpcCall,\n Context extends ContextConstraint = MiddlewareContext,\n> {\n #middleware: Readonly<\n NonEmptyArray<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >\n >;\n\n #isDestroyed = false;\n\n // See .create() for why this is private.\n private constructor({ middleware }: ConstructorOptions<Request, Context>) {\n this.#middleware = [...middleware];\n }\n\n // We use a static factory method in order to construct a supertype of all middleware contexts,\n // which enables us to instantiate an engine despite different middleware expecting different\n // context types.\n /**\n * Create a new JSON-RPC engine.\n *\n * @throws If the middleware array is empty.\n * @param options - The options for the engine.\n * @param options.middleware - The middleware to use.\n * @returns The JSON-RPC engine.\n */\n static create<\n Middleware extends JsonRpcMiddleware<\n // Non-polluting `any` constraint.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n any,\n ResultConstraint<any>,\n any\n /* eslint-enable @typescript-eslint/no-explicit-any */\n > = JsonRpcMiddleware,\n >({ middleware }: { middleware: Middleware[] }) {\n // We can't use NonEmptyArray for the params because it ruins type inference.\n if (middleware.length === 0) {\n throw new JsonRpcEngineError('Middleware array cannot be empty');\n }\n\n type MergedContext = MergedContextOf<Middleware>;\n type InputRequest = RequestOf<Middleware>;\n const mw = middleware as unknown as NonEmptyArray<\n JsonRpcMiddleware<\n InputRequest,\n ResultConstraint<InputRequest>,\n MergedContext\n >\n >;\n return new JsonRpcEngineV2<InputRequest, MergedContext>({\n middleware: mw,\n }) as MergedContext extends never\n ? InvalidEngine<'Some middleware have incompatible context types'>\n : JsonRpcEngineV2<InputRequest, MergedContext>;\n }\n\n /**\n * Handle a JSON-RPC request.\n *\n * @param request - The JSON-RPC request to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n * @returns The JSON-RPC response.\n */\n async handle(\n request: Extract<Request, JsonRpcRequest> extends never\n ? never\n : Extract<Request, JsonRpcRequest>,\n options?: HandleOptions<Context>,\n ): Promise<\n Extract<Request, JsonRpcRequest> extends never\n ? never\n : ResultConstraint<Request>\n >;\n\n /**\n * Handle a JSON-RPC notification. Notifications do not return a result.\n *\n * @param notification - The JSON-RPC notification to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n */\n async handle(\n notification: Extract<Request, JsonRpcNotification> extends never\n ? never\n : WithoutId<Extract<Request, JsonRpcNotification>>,\n options?: HandleOptions<Context>,\n ): Promise<\n Extract<Request, JsonRpcNotification> extends never\n ? never\n : ResultConstraint<Request>\n >;\n\n /**\n * Handle a JSON-RPC call, i.e. request or notification. Requests return a\n * result, notifications do not.\n *\n * @param call - The JSON-RPC call to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n * @returns The JSON-RPC response, or `undefined` if the call is a notification.\n */\n async handle(\n call: MixedParam<Request>,\n options?: HandleOptions<Context>,\n ): Promise<ResultConstraint<Request> | void>;\n\n async handle(\n request: Request,\n { context }: HandleOptions<Context> = {},\n ): Promise<Readonly<ResultConstraint<Request>> | void> {\n const isReq = isRequest(request);\n const { result } = await this.#handle(request, context);\n\n if (isReq && result === undefined) {\n throw new JsonRpcEngineError(\n `Nothing ended request: ${stringify(request)}`,\n );\n }\n return result;\n }\n\n /**\n * Handle a JSON-RPC request. Throws if a middleware performs an invalid\n * operation. Permits returning an `undefined` result.\n *\n * @param originalRequest - The JSON-RPC request to handle.\n * @param context - The context to pass to the middleware.\n * @returns The result from the middleware.\n */\n async #handle(\n originalRequest: Request,\n context: Context = new MiddlewareContext() as Context,\n ): Promise<RequestState<Request>> {\n this.#assertIsNotDestroyed();\n\n deepFreeze(originalRequest);\n\n const state: RequestState<Request> = {\n request: originalRequest,\n result: undefined,\n };\n const middlewareIterator = this.#makeMiddlewareIterator();\n const firstMiddleware = middlewareIterator.next().value;\n\n const makeNext = this.#makeNextFactory(middlewareIterator, state, context);\n\n const result = await firstMiddleware({\n request: originalRequest,\n context,\n next: makeNext(),\n });\n this.#updateResult(result, state);\n\n return state;\n }\n\n /**\n * Create a factory of `next()` functions for use with a particular request.\n * The factory is recursive, and a new `next()` is created for each middleware\n * invocation.\n *\n * @param middlewareIterator - The iterator of middleware for the current\n * request.\n * @param state - The current values of the request and result.\n * @param context - The context to pass to the middleware.\n * @returns The `next()` function factory.\n */\n #makeNextFactory(\n middlewareIterator: Iterator<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >,\n state: RequestState<Request>,\n context: Context,\n ): () => Next<Request> {\n const makeNext = (): Next<Request> => {\n let wasCalled = false;\n\n const next = async (\n request: Request = state.request,\n ): Promise<Readonly<ResultConstraint<Request>> | undefined> => {\n if (wasCalled) {\n throw new JsonRpcEngineError(\n `Middleware attempted to call next() multiple times for request: ${stringify(request)}`,\n );\n }\n wasCalled = true;\n\n if (request !== state.request) {\n this.#assertValidNextRequest(state.request, request);\n state.request = deepFreeze(request);\n }\n\n const { value: nextMiddleware, done } = middlewareIterator.next();\n if (done) {\n // This will cause the last middleware to return `undefined`. See the class\n // JSDoc or package README for more details.\n return undefined;\n }\n\n const result = await nextMiddleware({\n request,\n context,\n next: makeNext(),\n });\n this.#updateResult(result, state);\n\n return state.result;\n };\n return next;\n };\n\n return makeNext;\n }\n\n #makeMiddlewareIterator(): Iterator<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n > {\n return this.#middleware[Symbol.iterator]();\n }\n\n /**\n * Validate the result from a middleware and, if it's a new value, update the\n * current result.\n *\n * @param result - The result from the middleware.\n * @param state - The current values of the request and result.\n */\n #updateResult(\n result:\n | Readonly<ResultConstraint<Request>>\n | ResultConstraint<Request>\n | void,\n state: RequestState<Request>,\n ): void {\n if (isNotification(state.request) && result !== undefined) {\n throw new JsonRpcEngineError(\n `Result returned for notification: ${stringify(state.request)}`,\n );\n }\n\n if (result !== undefined && result !== state.result) {\n if (typeof result === 'object' && result !== null) {\n deepFreeze(result);\n }\n state.result = result;\n }\n }\n\n /**\n * Assert that a request modified by a middleware is valid.\n *\n * @param currentRequest - The current request.\n * @param nextRequest - The next request.\n */\n #assertValidNextRequest(currentRequest: Request, nextRequest: Request): void {\n if (nextRequest.jsonrpc !== currentRequest.jsonrpc) {\n throw new JsonRpcEngineError(\n `Middleware attempted to modify readonly property \"jsonrpc\" for request: ${stringify(currentRequest)}`,\n );\n }\n if (\n hasProperty(nextRequest, 'id') !== hasProperty(currentRequest, 'id') ||\n // @ts-expect-error - \"id\" does not exist on notifications, but we can still\n // check the value of the property at runtime.\n nextRequest.id !== currentRequest.id\n ) {\n throw new JsonRpcEngineError(\n `Middleware attempted to modify readonly property \"id\" for request: ${stringify(currentRequest)}`,\n );\n }\n }\n\n /**\n * Convert the engine into a JSON-RPC middleware.\n *\n * @returns The JSON-RPC middleware.\n */\n asMiddleware(): JsonRpcMiddleware<\n Request,\n ResultConstraint<Request>,\n Context\n > {\n this.#assertIsNotDestroyed();\n\n return async ({ request, context, next }) => {\n const { result, request: finalRequest } = await this.#handle(\n request,\n context,\n );\n return result === undefined ? await next(finalRequest) : result;\n };\n }\n\n /**\n * Destroy the engine. Calls the `destroy()` method of any middleware that has\n * one. Attempting to use the engine after destroying it will throw an error.\n */\n async destroy(): Promise<void> {\n if (this.#isDestroyed) {\n return;\n }\n this.#isDestroyed = true;\n\n const destructionPromise = Promise.all(\n this.#middleware.map(async (middleware) => {\n if (\n // Intentionally using `in` to walk the prototype chain.\n 'destroy' in middleware &&\n typeof middleware.destroy === 'function'\n ) {\n return middleware.destroy();\n }\n return undefined;\n }),\n );\n this.#middleware = [] as never;\n await destructionPromise;\n }\n\n #assertIsNotDestroyed(): void {\n if (this.#isDestroyed) {\n throw new JsonRpcEngineError('Engine is destroyed');\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _JsonRpcServer_instances, _JsonRpcServer_engine, _JsonRpcServer_onError, _JsonRpcServer_coerceRequest;
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.JsonRpcServer = void 0;
|
|
16
|
+
const rpc_errors_1 = require("@metamask/rpc-errors");
|
|
17
|
+
const utils_1 = require("@metamask/utils");
|
|
18
|
+
const JsonRpcEngineV2_1 = require("./JsonRpcEngineV2.cjs");
|
|
19
|
+
const getUniqueId_1 = require("../getUniqueId.cjs");
|
|
20
|
+
const jsonrpc = '2.0';
|
|
21
|
+
/**
|
|
22
|
+
* A JSON-RPC server that handles requests and notifications.
|
|
23
|
+
*
|
|
24
|
+
* Essentially wraps a {@link JsonRpcEngineV2} in order to create a conformant
|
|
25
|
+
* yet permissive JSON-RPC 2.0 server.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const server = new JsonRpcServer({
|
|
30
|
+
* engine,
|
|
31
|
+
* onError,
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* const response = await server.handle(request);
|
|
35
|
+
* if ('result' in response) {
|
|
36
|
+
* // Handle result
|
|
37
|
+
* } else {
|
|
38
|
+
* // Handle error
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
class JsonRpcServer {
|
|
43
|
+
/**
|
|
44
|
+
* Construct a new JSON-RPC server.
|
|
45
|
+
*
|
|
46
|
+
* @param options - The options for the server.
|
|
47
|
+
* @param options.onError - The callback to handle errors thrown by the
|
|
48
|
+
* engine. Errors always result in a failed response object, containing a
|
|
49
|
+
* JSON-RPC 2.0 serialized version of the original error. If you need to
|
|
50
|
+
* access the original error, use the `onError` callback.
|
|
51
|
+
* @param options.engine - The engine to use. Mutually exclusive with
|
|
52
|
+
* `middleware`.
|
|
53
|
+
* @param options.middleware - The middleware to use. Mutually exclusive with
|
|
54
|
+
* `engine`.
|
|
55
|
+
*/
|
|
56
|
+
constructor(options) {
|
|
57
|
+
_JsonRpcServer_instances.add(this);
|
|
58
|
+
_JsonRpcServer_engine.set(this, void 0);
|
|
59
|
+
_JsonRpcServer_onError.set(this, void 0);
|
|
60
|
+
__classPrivateFieldSet(this, _JsonRpcServer_onError, options.onError, "f");
|
|
61
|
+
if ((0, utils_1.hasProperty)(options, 'engine')) {
|
|
62
|
+
// @ts-expect-error - hasProperty fails to narrow the type.
|
|
63
|
+
__classPrivateFieldSet(this, _JsonRpcServer_engine, options.engine, "f");
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
__classPrivateFieldSet(this, _JsonRpcServer_engine, JsonRpcEngineV2_1.JsonRpcEngineV2.create({ middleware: options.middleware }), "f");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async handle(rawRequest) {
|
|
70
|
+
// If rawRequest is not a notification, the originalId will be attached
|
|
71
|
+
// to the response. We attach our own, trusted id in #coerceRequest()
|
|
72
|
+
// while the request is being handled.
|
|
73
|
+
const [originalId, isRequest] = getOriginalId(rawRequest);
|
|
74
|
+
try {
|
|
75
|
+
const request = __classPrivateFieldGet(this, _JsonRpcServer_instances, "m", _JsonRpcServer_coerceRequest).call(this, rawRequest, isRequest);
|
|
76
|
+
const result = await __classPrivateFieldGet(this, _JsonRpcServer_engine, "f").handle(request);
|
|
77
|
+
if (result !== undefined) {
|
|
78
|
+
return {
|
|
79
|
+
jsonrpc,
|
|
80
|
+
// @ts-expect-error - Reassign the original id, regardless of its type.
|
|
81
|
+
id: originalId,
|
|
82
|
+
result,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
__classPrivateFieldGet(this, _JsonRpcServer_onError, "f")?.call(this, error);
|
|
88
|
+
if (isRequest) {
|
|
89
|
+
return {
|
|
90
|
+
jsonrpc,
|
|
91
|
+
// @ts-expect-error - Reassign the original id, regardless of its type.
|
|
92
|
+
id: originalId,
|
|
93
|
+
error: (0, rpc_errors_1.serializeError)(error, {
|
|
94
|
+
shouldIncludeStack: false,
|
|
95
|
+
shouldPreserveMessage: true,
|
|
96
|
+
}),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.JsonRpcServer = JsonRpcServer;
|
|
104
|
+
_JsonRpcServer_engine = new WeakMap(), _JsonRpcServer_onError = new WeakMap(), _JsonRpcServer_instances = new WeakSet(), _JsonRpcServer_coerceRequest = function _JsonRpcServer_coerceRequest(rawRequest, isRequest) {
|
|
105
|
+
if (!isMinimalRequest(rawRequest)) {
|
|
106
|
+
throw rpc_errors_1.rpcErrors.invalidRequest({
|
|
107
|
+
data: {
|
|
108
|
+
request: rawRequest,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const request = {
|
|
113
|
+
jsonrpc,
|
|
114
|
+
method: rawRequest.method,
|
|
115
|
+
};
|
|
116
|
+
if ((0, utils_1.hasProperty)(rawRequest, 'params')) {
|
|
117
|
+
request.params = rawRequest.params;
|
|
118
|
+
}
|
|
119
|
+
if (isRequest) {
|
|
120
|
+
request.id = (0, getUniqueId_1.getUniqueId)();
|
|
121
|
+
}
|
|
122
|
+
return request;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Check if an unvalidated request is a minimal request.
|
|
126
|
+
*
|
|
127
|
+
* @param rawRequest - The raw request to check.
|
|
128
|
+
* @returns `true` if the request is a {@link MinimalRequest}, `false` otherwise.
|
|
129
|
+
*/
|
|
130
|
+
function isMinimalRequest(rawRequest) {
|
|
131
|
+
return ((0, utils_1.isObject)(rawRequest) &&
|
|
132
|
+
(0, utils_1.hasProperty)(rawRequest, 'method') &&
|
|
133
|
+
typeof rawRequest.method === 'string' &&
|
|
134
|
+
hasValidParams(rawRequest));
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check if a request has valid params, i.e. an array or object.
|
|
138
|
+
* The contents of the params are not inspected.
|
|
139
|
+
*
|
|
140
|
+
* @param rawRequest - The request to check.
|
|
141
|
+
* @returns `true` if the request has valid params, `false` otherwise.
|
|
142
|
+
*/
|
|
143
|
+
function hasValidParams(rawRequest) {
|
|
144
|
+
if ((0, utils_1.hasProperty)(rawRequest, 'params')) {
|
|
145
|
+
return Array.isArray(rawRequest.params) || (0, utils_1.isObject)(rawRequest.params);
|
|
146
|
+
}
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get the original id from a request.
|
|
151
|
+
*
|
|
152
|
+
* @param rawRequest - The request to get the original id from.
|
|
153
|
+
* @returns The original id and a boolean indicating if the request is a request
|
|
154
|
+
* (as opposed to a notification).
|
|
155
|
+
*/
|
|
156
|
+
function getOriginalId(rawRequest) {
|
|
157
|
+
if ((0, utils_1.isObject)(rawRequest) && (0, utils_1.hasProperty)(rawRequest, 'id')) {
|
|
158
|
+
return [rawRequest.id, true];
|
|
159
|
+
}
|
|
160
|
+
return [undefined, false];
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=JsonRpcServer.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonRpcServer.cjs","sourceRoot":"","sources":["../../src/v2/JsonRpcServer.ts"],"names":[],"mappings":"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","sourcesContent":["import { rpcErrors, serializeError } from '@metamask/rpc-errors';\nimport type {\n JsonRpcNotification,\n JsonRpcParams,\n JsonRpcRequest,\n JsonRpcResponse,\n NonEmptyArray,\n} from '@metamask/utils';\nimport { hasProperty, isObject } from '@metamask/utils';\n\nimport type { JsonRpcMiddleware } from './JsonRpcEngineV2';\nimport { JsonRpcEngineV2 } from './JsonRpcEngineV2';\nimport type { JsonRpcCall } from './utils';\nimport { getUniqueId } from '../getUniqueId';\n\ntype OnError = (error: unknown) => void;\n\ntype Options = {\n onError?: OnError;\n} & (\n | {\n engine: JsonRpcEngineV2;\n }\n | {\n middleware: NonEmptyArray<JsonRpcMiddleware>;\n }\n);\n\nconst jsonrpc = '2.0' as const;\n\n/**\n * A JSON-RPC server that handles requests and notifications.\n *\n * Essentially wraps a {@link JsonRpcEngineV2} in order to create a conformant\n * yet permissive JSON-RPC 2.0 server.\n *\n * @example\n * ```ts\n * const server = new JsonRpcServer({\n * engine,\n * onError,\n * });\n *\n * const response = await server.handle(request);\n * if ('result' in response) {\n * // Handle result\n * } else {\n * // Handle error\n * }\n * ```\n */\nexport class JsonRpcServer {\n readonly #engine: JsonRpcEngineV2;\n\n readonly #onError?: OnError | undefined;\n\n /**\n * Construct a new JSON-RPC server.\n *\n * @param options - The options for the server.\n * @param options.onError - The callback to handle errors thrown by the\n * engine. Errors always result in a failed response object, containing a\n * JSON-RPC 2.0 serialized version of the original error. If you need to\n * access the original error, use the `onError` callback.\n * @param options.engine - The engine to use. Mutually exclusive with\n * `middleware`.\n * @param options.middleware - The middleware to use. Mutually exclusive with\n * `engine`.\n */\n constructor(options: Options) {\n this.#onError = options.onError;\n\n if (hasProperty(options, 'engine')) {\n // @ts-expect-error - hasProperty fails to narrow the type.\n this.#engine = options.engine;\n } else {\n this.#engine = JsonRpcEngineV2.create({ middleware: options.middleware });\n }\n }\n\n /**\n * Handle a JSON-RPC request.\n *\n * This method never throws. For requests, a response is always returned.\n * All errors are passed to the engine's `onError` callback.\n *\n * @param request - The request to handle.\n * @returns The JSON-RPC response.\n */\n async handle(request: JsonRpcRequest): Promise<JsonRpcResponse>;\n\n /**\n * Handle a JSON-RPC notification.\n *\n * This method never throws. For notifications, `undefined` is always returned.\n * All errors are passed to the engine's `onError` callback.\n *\n * @param notification - The notification to handle.\n */\n async handle(notification: JsonRpcNotification): Promise<void>;\n\n /**\n * Handle an alleged JSON-RPC request or notification. Permits any plain\n * object with `{ method: string }`, so long as any present JSON-RPC 2.0\n * properties are valid. If the object has no `id`, it will be treated as\n * a notification and vice versa.\n *\n * This method never throws. All errors are passed to the engine's\n * `onError` callback. A JSON-RPC response is always returned for requests,\n * and `undefined` is returned for notifications.\n *\n * @param rawRequest - The raw request to handle.\n * @returns The JSON-RPC response, or `undefined` if the request is a\n * notification.\n */\n async handle(rawRequest: unknown): Promise<JsonRpcResponse | void>;\n\n async handle(rawRequest: unknown): Promise<JsonRpcResponse | void> {\n // If rawRequest is not a notification, the originalId will be attached\n // to the response. We attach our own, trusted id in #coerceRequest()\n // while the request is being handled.\n const [originalId, isRequest] = getOriginalId(rawRequest);\n\n try {\n const request = this.#coerceRequest(rawRequest, isRequest);\n const result = await this.#engine.handle(request);\n\n if (result !== undefined) {\n return {\n jsonrpc,\n // @ts-expect-error - Reassign the original id, regardless of its type.\n id: originalId,\n result,\n };\n }\n } catch (error) {\n this.#onError?.(error);\n\n if (isRequest) {\n return {\n jsonrpc,\n // @ts-expect-error - Reassign the original id, regardless of its type.\n id: originalId,\n error: serializeError(error, {\n shouldIncludeStack: false,\n shouldPreserveMessage: true,\n }),\n };\n }\n }\n return undefined;\n }\n\n #coerceRequest(rawRequest: unknown, isRequest: boolean): JsonRpcCall {\n if (!isMinimalRequest(rawRequest)) {\n throw rpcErrors.invalidRequest({\n data: {\n request: rawRequest,\n },\n });\n }\n\n const request: JsonRpcCall = {\n jsonrpc,\n method: rawRequest.method,\n };\n\n if (hasProperty(rawRequest, 'params')) {\n request.params = rawRequest.params as JsonRpcParams;\n }\n\n if (isRequest) {\n (request as JsonRpcRequest).id = getUniqueId();\n }\n\n return request;\n }\n}\n\n/**\n * The most minimally conformant request object that we will accept.\n */\ntype MinimalRequest = {\n method: string;\n params?: JsonRpcParams;\n} & Record<string, unknown>;\n\n/**\n * Check if an unvalidated request is a minimal request.\n *\n * @param rawRequest - The raw request to check.\n * @returns `true` if the request is a {@link MinimalRequest}, `false` otherwise.\n */\nfunction isMinimalRequest(rawRequest: unknown): rawRequest is MinimalRequest {\n return (\n isObject(rawRequest) &&\n hasProperty(rawRequest, 'method') &&\n typeof rawRequest.method === 'string' &&\n hasValidParams(rawRequest)\n );\n}\n\n/**\n * Check if a request has valid params, i.e. an array or object.\n * The contents of the params are not inspected.\n *\n * @param rawRequest - The request to check.\n * @returns `true` if the request has valid params, `false` otherwise.\n */\nfunction hasValidParams(\n rawRequest: Record<string, unknown>,\n): rawRequest is { params?: JsonRpcParams } {\n if (hasProperty(rawRequest, 'params')) {\n return Array.isArray(rawRequest.params) || isObject(rawRequest.params);\n }\n\n return true;\n}\n\n/**\n * Get the original id from a request.\n *\n * @param rawRequest - The request to get the original id from.\n * @returns The original id and a boolean indicating if the request is a request\n * (as opposed to a notification).\n */\nfunction getOriginalId(rawRequest: unknown): [unknown, boolean] {\n if (isObject(rawRequest) && hasProperty(rawRequest, 'id')) {\n return [rawRequest.id, true];\n }\n\n return [undefined, false];\n}\n"]}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, NonEmptyArray } from "@metamask/utils";
|
|
2
|
+
import type { JsonRpcMiddleware } from "./JsonRpcEngineV2.cjs";
|
|
3
|
+
import { JsonRpcEngineV2 } from "./JsonRpcEngineV2.cjs";
|
|
4
|
+
type OnError = (error: unknown) => void;
|
|
5
|
+
type Options = {
|
|
6
|
+
onError?: OnError;
|
|
7
|
+
} & ({
|
|
8
|
+
engine: JsonRpcEngineV2;
|
|
9
|
+
} | {
|
|
10
|
+
middleware: NonEmptyArray<JsonRpcMiddleware>;
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* A JSON-RPC server that handles requests and notifications.
|
|
14
|
+
*
|
|
15
|
+
* Essentially wraps a {@link JsonRpcEngineV2} in order to create a conformant
|
|
16
|
+
* yet permissive JSON-RPC 2.0 server.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const server = new JsonRpcServer({
|
|
21
|
+
* engine,
|
|
22
|
+
* onError,
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* const response = await server.handle(request);
|
|
26
|
+
* if ('result' in response) {
|
|
27
|
+
* // Handle result
|
|
28
|
+
* } else {
|
|
29
|
+
* // Handle error
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare class JsonRpcServer {
|
|
34
|
+
#private;
|
|
35
|
+
/**
|
|
36
|
+
* Construct a new JSON-RPC server.
|
|
37
|
+
*
|
|
38
|
+
* @param options - The options for the server.
|
|
39
|
+
* @param options.onError - The callback to handle errors thrown by the
|
|
40
|
+
* engine. Errors always result in a failed response object, containing a
|
|
41
|
+
* JSON-RPC 2.0 serialized version of the original error. If you need to
|
|
42
|
+
* access the original error, use the `onError` callback.
|
|
43
|
+
* @param options.engine - The engine to use. Mutually exclusive with
|
|
44
|
+
* `middleware`.
|
|
45
|
+
* @param options.middleware - The middleware to use. Mutually exclusive with
|
|
46
|
+
* `engine`.
|
|
47
|
+
*/
|
|
48
|
+
constructor(options: Options);
|
|
49
|
+
/**
|
|
50
|
+
* Handle a JSON-RPC request.
|
|
51
|
+
*
|
|
52
|
+
* This method never throws. For requests, a response is always returned.
|
|
53
|
+
* All errors are passed to the engine's `onError` callback.
|
|
54
|
+
*
|
|
55
|
+
* @param request - The request to handle.
|
|
56
|
+
* @returns The JSON-RPC response.
|
|
57
|
+
*/
|
|
58
|
+
handle(request: JsonRpcRequest): Promise<JsonRpcResponse>;
|
|
59
|
+
/**
|
|
60
|
+
* Handle a JSON-RPC notification.
|
|
61
|
+
*
|
|
62
|
+
* This method never throws. For notifications, `undefined` is always returned.
|
|
63
|
+
* All errors are passed to the engine's `onError` callback.
|
|
64
|
+
*
|
|
65
|
+
* @param notification - The notification to handle.
|
|
66
|
+
*/
|
|
67
|
+
handle(notification: JsonRpcNotification): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Handle an alleged JSON-RPC request or notification. Permits any plain
|
|
70
|
+
* object with `{ method: string }`, so long as any present JSON-RPC 2.0
|
|
71
|
+
* properties are valid. If the object has no `id`, it will be treated as
|
|
72
|
+
* a notification and vice versa.
|
|
73
|
+
*
|
|
74
|
+
* This method never throws. All errors are passed to the engine's
|
|
75
|
+
* `onError` callback. A JSON-RPC response is always returned for requests,
|
|
76
|
+
* and `undefined` is returned for notifications.
|
|
77
|
+
*
|
|
78
|
+
* @param rawRequest - The raw request to handle.
|
|
79
|
+
* @returns The JSON-RPC response, or `undefined` if the request is a
|
|
80
|
+
* notification.
|
|
81
|
+
*/
|
|
82
|
+
handle(rawRequest: unknown): Promise<JsonRpcResponse | void>;
|
|
83
|
+
}
|
|
84
|
+
export {};
|
|
85
|
+
//# sourceMappingURL=JsonRpcServer.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonRpcServer.d.cts","sourceRoot":"","sources":["../../src/v2/JsonRpcServer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EAEnB,cAAc,EACd,eAAe,EACf,aAAa,EACd,wBAAwB;AAGzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,8BAA0B;AAC3D,OAAO,EAAE,eAAe,EAAE,8BAA0B;AAIpD,KAAK,OAAO,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;AAExC,KAAK,OAAO,GAAG;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,CACA;IACE,MAAM,EAAE,eAAe,CAAC;CACzB,GACD;IACE,UAAU,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;CAC9C,CACJ,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,aAAa;;IAKxB;;;;;;;;;;;;OAYG;gBACS,OAAO,EAAE,OAAO;IAW5B;;;;;;;;OAQG;IACG,MAAM,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAE/D;;;;;;;OAOG;IACG,MAAM,CAAC,YAAY,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAE9D;;;;;;;;;;;;;OAaG;IACG,MAAM,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;CA8DnE"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, NonEmptyArray } from "@metamask/utils";
|
|
2
|
+
import type { JsonRpcMiddleware } from "./JsonRpcEngineV2.mjs";
|
|
3
|
+
import { JsonRpcEngineV2 } from "./JsonRpcEngineV2.mjs";
|
|
4
|
+
type OnError = (error: unknown) => void;
|
|
5
|
+
type Options = {
|
|
6
|
+
onError?: OnError;
|
|
7
|
+
} & ({
|
|
8
|
+
engine: JsonRpcEngineV2;
|
|
9
|
+
} | {
|
|
10
|
+
middleware: NonEmptyArray<JsonRpcMiddleware>;
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* A JSON-RPC server that handles requests and notifications.
|
|
14
|
+
*
|
|
15
|
+
* Essentially wraps a {@link JsonRpcEngineV2} in order to create a conformant
|
|
16
|
+
* yet permissive JSON-RPC 2.0 server.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const server = new JsonRpcServer({
|
|
21
|
+
* engine,
|
|
22
|
+
* onError,
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* const response = await server.handle(request);
|
|
26
|
+
* if ('result' in response) {
|
|
27
|
+
* // Handle result
|
|
28
|
+
* } else {
|
|
29
|
+
* // Handle error
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare class JsonRpcServer {
|
|
34
|
+
#private;
|
|
35
|
+
/**
|
|
36
|
+
* Construct a new JSON-RPC server.
|
|
37
|
+
*
|
|
38
|
+
* @param options - The options for the server.
|
|
39
|
+
* @param options.onError - The callback to handle errors thrown by the
|
|
40
|
+
* engine. Errors always result in a failed response object, containing a
|
|
41
|
+
* JSON-RPC 2.0 serialized version of the original error. If you need to
|
|
42
|
+
* access the original error, use the `onError` callback.
|
|
43
|
+
* @param options.engine - The engine to use. Mutually exclusive with
|
|
44
|
+
* `middleware`.
|
|
45
|
+
* @param options.middleware - The middleware to use. Mutually exclusive with
|
|
46
|
+
* `engine`.
|
|
47
|
+
*/
|
|
48
|
+
constructor(options: Options);
|
|
49
|
+
/**
|
|
50
|
+
* Handle a JSON-RPC request.
|
|
51
|
+
*
|
|
52
|
+
* This method never throws. For requests, a response is always returned.
|
|
53
|
+
* All errors are passed to the engine's `onError` callback.
|
|
54
|
+
*
|
|
55
|
+
* @param request - The request to handle.
|
|
56
|
+
* @returns The JSON-RPC response.
|
|
57
|
+
*/
|
|
58
|
+
handle(request: JsonRpcRequest): Promise<JsonRpcResponse>;
|
|
59
|
+
/**
|
|
60
|
+
* Handle a JSON-RPC notification.
|
|
61
|
+
*
|
|
62
|
+
* This method never throws. For notifications, `undefined` is always returned.
|
|
63
|
+
* All errors are passed to the engine's `onError` callback.
|
|
64
|
+
*
|
|
65
|
+
* @param notification - The notification to handle.
|
|
66
|
+
*/
|
|
67
|
+
handle(notification: JsonRpcNotification): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Handle an alleged JSON-RPC request or notification. Permits any plain
|
|
70
|
+
* object with `{ method: string }`, so long as any present JSON-RPC 2.0
|
|
71
|
+
* properties are valid. If the object has no `id`, it will be treated as
|
|
72
|
+
* a notification and vice versa.
|
|
73
|
+
*
|
|
74
|
+
* This method never throws. All errors are passed to the engine's
|
|
75
|
+
* `onError` callback. A JSON-RPC response is always returned for requests,
|
|
76
|
+
* and `undefined` is returned for notifications.
|
|
77
|
+
*
|
|
78
|
+
* @param rawRequest - The raw request to handle.
|
|
79
|
+
* @returns The JSON-RPC response, or `undefined` if the request is a
|
|
80
|
+
* notification.
|
|
81
|
+
*/
|
|
82
|
+
handle(rawRequest: unknown): Promise<JsonRpcResponse | void>;
|
|
83
|
+
}
|
|
84
|
+
export {};
|
|
85
|
+
//# sourceMappingURL=JsonRpcServer.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonRpcServer.d.mts","sourceRoot":"","sources":["../../src/v2/JsonRpcServer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EAEnB,cAAc,EACd,eAAe,EACf,aAAa,EACd,wBAAwB;AAGzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,8BAA0B;AAC3D,OAAO,EAAE,eAAe,EAAE,8BAA0B;AAIpD,KAAK,OAAO,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;AAExC,KAAK,OAAO,GAAG;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,CACA;IACE,MAAM,EAAE,eAAe,CAAC;CACzB,GACD;IACE,UAAU,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;CAC9C,CACJ,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,aAAa;;IAKxB;;;;;;;;;;;;OAYG;gBACS,OAAO,EAAE,OAAO;IAW5B;;;;;;;;OAQG;IACG,MAAM,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAE/D;;;;;;;OAOG;IACG,MAAM,CAAC,YAAY,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAE9D;;;;;;;;;;;;;OAaG;IACG,MAAM,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;CA8DnE"}
|