This PR adds [JSON-RPC 2.0](https://www.jsonrpc.org/specification)-compliant notification handling for `JsonRpcEngine`.
- JSON-RPC notifications are defined as JSON-RPC request objects without an `id` property.
- A new constructor parameter, `notificationHandler`, is introduced. This parameter is a function that accepts JSON-RPC notification objects and returns `void | Promise<void>`.
- When `JsonRpcEngine.handle` is called, if a `notificationHandler` exists, any request objects duck-typed as notifications will be handled as such. This means that:
- Validation errors that occur after duck-typing will be ignored. At the moment, this just means that no error will be thrown if the `method` field is not a string.
- If basic validation succeeds, the notification object will be passed to the handler function without touching the middleware stack.
- The response from `handle()` will be `undefined`.
- No error will be returned or thrown, unless the notification handler itself throws or rejects.
- Notification handlers should not throw or reject, and it is the implementer's responsibility to ensure that they do not.
- If `JsonRpcEngine.handle` is called and no `notificationHandler` exists, notifications will be treated just like requests. This is the current behavior.
Adds a new method `JsonRpcEngine.destroy()`, based on this hack in the MetaMask extension: 851fce9a3b/app/scripts/metamask-controller.js (L2785)
The `JsonRpcMiddleware` type is altered to permit a `destroy` property. Calling `JsonRpcEngine.destroy()` clears the internal middleware array, calls the `destroy()` method of every middleware with such an own or inherited property, and renders the engine instance unusable.
Kudos to @daoauth for the original implementation in #98.
Co-authored-by: daoauth <57783762+daoauth@users.noreply.github.com>
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.
Migrates all tests to Jest and TypeScript per the module template. Care was taken to modify the existing tests as little as possible. Therefore, the tests unfortunately make prodigious use of casts to `any`. Nevertheless, to minimize such casts, a pair of assertion type guards were added for successful and failed JSON-RPC responses. They use the existing boolean type guards under the hood, and are fully tested.
Assertion type guards are tremendously helpful in situations like this, where boolean type guards don't help since e.g. `expect(typeGuard(value)).toBe(true);` doesn't tell TypeScript anything, and we have lint rules preventing us from calling `expect` conditionally.
This PR updates various repository features for module template compliance. This repository should be fully compliant as of this PR, except for tests, which will be addressed in a follow-up. Notable changes include:
- Updates the ESLint config and related dependencies
- Adds `@lavamoat/allow-scripts` and the `setup` package script
- Migrates from CircleCI to GitHub Actions
- Bumps the minimum Node version to 14
Adds some type guard utilities in a new file, `utils.ts`, and accompanying unit tests.
In addition to fixing #89, adds a function for validating JSON-RPC ID values. As part of implementing that, this also fixes a long-standing bug where we returned `undefined` instead of `null` for the ID when returning an error for a request without an `id` value.
* Enforcing minimum node version 12 via .nvmrc, circleci, and the package file
* Adding a note about running tests to README.md
* Adding basic .gitattributes file
* Migrate to TypeScript
* Update CI config
* Update eth-rpc-errors, fix JsonRpcError stack type
* Add runtime typecheck for handle callback
* Use Maybe utility type for response.result
* 100% test coverage everywhere
* add nyc config, check coverage, use in CI
* add next handler test case
* add async handle tests
* add sinon; use stub