jsonrpc-client-websocket 1.3.0 → 1.5.1

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  [![Travis build status](https://travis-ci.com/fabriciobastian/jsonrpc-client-websocket.svg?branch=master)](https://travis-ci.com/fabriciobastian/jsonrpc-client-websocket) [![License](https://img.shields.io/github/license/fabriciobastian/jsonrpc-client-websocket)](https://choosealicense.com/licenses/mit/) [![NPM downloads](https://img.shields.io/npm/dt/jsonrpc-client-websocket.svg)](https://www.npmjs.com/package/jsonrpc-client-websocket)
2
2
 
3
- # jsonrpc-client-websocket
3
+ ![jsonrpc-client-websocket](https://github.com/fabriciobastian/jsonrpc-client-websocket/blob/master/assets/jsonrpc-client-websocket-banner-light-small.png?raw=true)
4
4
 
5
5
  A simple JSON RPC 2.0 client over websockets
6
6
 
@@ -70,3 +70,8 @@ websocket.on('sum', (a: number, b: number) => {
70
70
  });
71
71
  ```
72
72
  The defined RPC methods can also be called with both positional and named parameters.
73
+
74
+ ## Remove RPC method
75
+ ```typescript
76
+ websocket.off('sum');
77
+ ```
@@ -1,6 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- class DeferredPromise {
1
+ export class DeferredPromise {
4
2
  constructor() {
5
3
  this.promise = new Promise((resolve, reject) => {
6
4
  this.deferResolve = resolve;
@@ -17,4 +15,3 @@ class DeferredPromise {
17
15
  this.deferReject(error);
18
16
  }
19
17
  }
20
- exports.DeferredPromise = DeferredPromise;
package/lib/index.js CHANGED
@@ -1,7 +1,2 @@
1
- "use strict";
2
- function __export(m) {
3
- for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
4
- }
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- __export(require("./jsonrpc-websocket"));
7
- __export(require("./jsonrpc.model"));
1
+ export * from './jsonrpc-websocket';
2
+ export * from './jsonrpc.model';
@@ -21,8 +21,9 @@ export declare class JsonRpcWebsocket {
21
21
  open(): Promise<Event>;
22
22
  close(): Promise<CloseEvent>;
23
23
  on(methodName: string, callback: (...args: any[]) => any): void;
24
- call(method: string, params?: any): Promise<JsonRpcResponse>;
25
- notify(method: string, params?: any): void;
24
+ off(methodName: string): void;
25
+ call(method: string, params?: unknown): Promise<JsonRpcResponse>;
26
+ notify(method: string, params?: unknown): void;
26
27
  private createWebsocket;
27
28
  private respondOk;
28
29
  private respondError;
@@ -1,16 +1,14 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const getParameterNames = require("get-parameter-names");
4
- const deferred_promise_1 = require("./deferred-promise");
5
- const jsonrpc_model_1 = require("./jsonrpc.model");
6
- var WebsocketReadyStates;
1
+ import * as getParameterNames from 'get-parameter-names';
2
+ import { DeferredPromise } from './deferred-promise';
3
+ import { JsonRpcErrorCodes } from './jsonrpc.model';
4
+ export var WebsocketReadyStates;
7
5
  (function (WebsocketReadyStates) {
8
6
  WebsocketReadyStates[WebsocketReadyStates["CONNECTING"] = 0] = "CONNECTING";
9
7
  WebsocketReadyStates[WebsocketReadyStates["OPEN"] = 1] = "OPEN";
10
8
  WebsocketReadyStates[WebsocketReadyStates["CLOSING"] = 2] = "CLOSING";
11
9
  WebsocketReadyStates[WebsocketReadyStates["CLOSED"] = 3] = "CLOSED";
12
- })(WebsocketReadyStates = exports.WebsocketReadyStates || (exports.WebsocketReadyStates = {}));
13
- class JsonRpcWebsocket {
10
+ })(WebsocketReadyStates || (WebsocketReadyStates = {}));
11
+ export class JsonRpcWebsocket {
14
12
  constructor(url, requestTimeoutMs, onError) {
15
13
  this.url = url;
16
14
  this.requestTimeoutMs = requestTimeoutMs;
@@ -30,21 +28,23 @@ class JsonRpcWebsocket {
30
28
  return this.createWebsocket();
31
29
  }
32
30
  close() {
33
- if (this.websocket === void 0) {
31
+ if (this.websocket === undefined) {
34
32
  return Promise.resolve(new CloseEvent('No websocket was opened', { wasClean: false, code: 1005 }));
35
33
  }
36
34
  this.websocket.close(1000); // 1000 = normal closure
37
- this.websocket = void 0;
35
+ this.websocket = undefined;
38
36
  return this.closeDeferredPromise.asPromise();
39
37
  }
40
38
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
39
  on(methodName, callback) {
42
40
  this.rpcMethods[methodName.toLowerCase()] = callback; // case-insensitive!
43
41
  }
44
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
+ off(methodName) {
43
+ delete this.rpcMethods[methodName.toLowerCase()]; // case-insensitive!
44
+ }
45
45
  call(method, params) {
46
46
  if (!this.websocket || this.state !== WebsocketReadyStates.OPEN) {
47
- return Promise.reject({ code: jsonrpc_model_1.JsonRpcErrorCodes.INTERNAL_ERROR, message: 'The websocket is not opened' });
47
+ return Promise.reject({ code: JsonRpcErrorCodes.INTERNAL_ERROR, message: 'The websocket is not opened' });
48
48
  }
49
49
  const request = {
50
50
  id: this.getRequestId(),
@@ -57,11 +57,10 @@ class JsonRpcWebsocket {
57
57
  }
58
58
  catch (e) {
59
59
  // istanbul ignore next
60
- return Promise.reject({ code: jsonrpc_model_1.JsonRpcErrorCodes.INTERNAL_ERROR, message: `Internal error. ${e}` });
60
+ return Promise.reject({ code: JsonRpcErrorCodes.INTERNAL_ERROR, message: `Internal error. ${e}` });
61
61
  }
62
62
  return this.createPendingRequest(request);
63
63
  }
64
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
65
64
  notify(method, params) {
66
65
  if (!this.websocket || this.state !== WebsocketReadyStates.OPEN) {
67
66
  throw new Error('The websocket is not opened');
@@ -83,8 +82,8 @@ class JsonRpcWebsocket {
83
82
  // See https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent for close event codes
84
83
  // this.websocket = new WebSocket(this.url, ['jsonrpc-2.0']);
85
84
  this.websocket = new WebSocket(this.url);
86
- const openDeferredPromise = new deferred_promise_1.DeferredPromise();
87
- this.closeDeferredPromise = new deferred_promise_1.DeferredPromise();
85
+ const openDeferredPromise = new DeferredPromise();
86
+ this.closeDeferredPromise = new DeferredPromise();
88
87
  this.websocket.onopen = (event) => {
89
88
  openDeferredPromise.resolve(event);
90
89
  };
@@ -92,7 +91,7 @@ class JsonRpcWebsocket {
92
91
  openDeferredPromise.reject(err);
93
92
  };
94
93
  this.websocket.onclose = (event) => {
95
- this.websocket = void 0;
94
+ this.websocket = undefined;
96
95
  if (event.code !== 1000) {
97
96
  // 1000 = normal closure
98
97
  const error = {
@@ -107,14 +106,12 @@ class JsonRpcWebsocket {
107
106
  this.websocket.onmessage = (message) => this.handleMessage(message.data);
108
107
  return openDeferredPromise.asPromise();
109
108
  }
110
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
111
109
  respondOk(id, result) {
112
110
  this.respond(id, result);
113
111
  }
114
112
  respondError(id, error) {
115
- this.respond(id, void 0, error);
113
+ this.respond(id, undefined, error);
116
114
  }
117
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
115
  respond(id, result, error) {
119
116
  // istanbul ignore if
120
117
  if (!this.websocket || this.state !== WebsocketReadyStates.OPEN) {
@@ -128,7 +125,7 @@ class JsonRpcWebsocket {
128
125
  jsonrpc: this.jsonRpcVersion,
129
126
  error: error,
130
127
  id: id,
131
- result: result
128
+ result: result,
132
129
  };
133
130
  try {
134
131
  this.websocket.send(JSON.stringify(response));
@@ -144,14 +141,14 @@ class JsonRpcWebsocket {
144
141
  data = JSON.parse(msg);
145
142
  }
146
143
  catch (e) /* istanbul ignore next */ {
147
- this.handleError(jsonrpc_model_1.JsonRpcErrorCodes.PARSE_ERROR, `Invalid JSON was received. ${e}`);
144
+ this.handleError(JsonRpcErrorCodes.PARSE_ERROR, `Invalid JSON was received. ${e}`);
148
145
  return;
149
146
  }
150
147
  const isResponse = !!data && this.hasProperty(data, 'id') && (this.hasProperty(data, 'result') || this.hasProperty(data, 'error'));
151
148
  const isRequest = !!data && this.hasProperty(data, 'method');
152
- const requestId = isRequest && data.id ? data.id : void 0;
149
+ const requestId = isRequest && data.id ? data.id : undefined;
153
150
  if (!data.jsonrpc || data.jsonrpc !== this.jsonRpcVersion) {
154
- this.handleError(jsonrpc_model_1.JsonRpcErrorCodes.INVALID_REQUEST, `Invalid JSON RPC protocol version. Expecting ${this.jsonRpcVersion}, but got ${data.jsonrpc}`, requestId);
151
+ this.handleError(JsonRpcErrorCodes.INVALID_REQUEST, `Invalid JSON RPC protocol version. Expecting ${this.jsonRpcVersion}, but got ${data.jsonrpc}`, requestId);
155
152
  return;
156
153
  }
157
154
  if (isResponse) {
@@ -161,13 +158,13 @@ class JsonRpcWebsocket {
161
158
  this.handleRequest(data);
162
159
  }
163
160
  else {
164
- this.handleError(jsonrpc_model_1.JsonRpcErrorCodes.INVALID_REQUEST, `Received unknown data: ${JSON.stringify(data)}`, requestId);
161
+ this.handleError(JsonRpcErrorCodes.INVALID_REQUEST, `Received unknown data: ${JSON.stringify(data)}`, requestId);
165
162
  }
166
163
  }
167
164
  handleRequest(request) {
168
165
  const method = this.rpcMethods[request.method.toLowerCase()]; // case-insensitive!
169
166
  if (!method) {
170
- this.handleError(jsonrpc_model_1.JsonRpcErrorCodes.METHOD_NOT_FOUND, `Method '${request.method}' was not found`, request.id);
167
+ this.handleError(JsonRpcErrorCodes.METHOD_NOT_FOUND, `Method '${request.method}' was not found`, request.id);
171
168
  return;
172
169
  }
173
170
  let requestParams = [];
@@ -175,12 +172,17 @@ class JsonRpcWebsocket {
175
172
  requestParams = this.getRequestParams(method, request);
176
173
  }
177
174
  catch (error) {
178
- this.handleError(jsonrpc_model_1.JsonRpcErrorCodes.INVALID_PARAMS, error.message, request.id);
175
+ this.handleError(JsonRpcErrorCodes.INVALID_PARAMS, error.message, request.id);
179
176
  return;
180
177
  }
181
- const result = method(...requestParams);
182
- if (request.id) {
183
- this.respondOk(request.id, result);
178
+ try {
179
+ const result = method(...requestParams);
180
+ if (request.id) {
181
+ this.respondOk(request.id, result);
182
+ }
183
+ }
184
+ catch (error) {
185
+ this.handleError(JsonRpcErrorCodes.REQUEST_FAILED, `Method '${request.method}' has thrown: '${error.message}'`, request.id);
184
186
  }
185
187
  }
186
188
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -198,9 +200,9 @@ class JsonRpcWebsocket {
198
200
  if (method.length !== Object.keys(request.params).length) {
199
201
  throw new Error(`Invalid parameters. Method '${request.method}' expects parameters [${parameterNames}], but got [${Object.keys(request.params)}]`);
200
202
  }
201
- parameterNames.forEach(paramName => {
203
+ parameterNames.forEach((paramName) => {
202
204
  const paramValue = request.params[paramName];
203
- if (!paramValue) {
205
+ if (paramValue === undefined) {
204
206
  throw new Error(`Invalid parameters. Method '${request.method}' expects parameters [${parameterNames}], but got [${Object.keys(request.params)}]`);
205
207
  }
206
208
  requestParams.push(paramValue);
@@ -214,9 +216,9 @@ class JsonRpcWebsocket {
214
216
  }
215
217
  handleResponse(response) {
216
218
  const activeRequest = this.pendingRequests[response.id];
217
- if (activeRequest === void 0) {
219
+ if (activeRequest === undefined) {
218
220
  this.callOnError({
219
- code: jsonrpc_model_1.JsonRpcErrorCodes.INTERNAL_ERROR,
221
+ code: JsonRpcErrorCodes.INTERNAL_ERROR,
220
222
  message: `Received a response with id ${response.id}, which does not match any requests made by this client`,
221
223
  });
222
224
  return;
@@ -225,7 +227,7 @@ class JsonRpcWebsocket {
225
227
  if (this.hasProperty(response, 'result') && this.hasProperty(response, 'error')) {
226
228
  const errorResponse = {
227
229
  error: {
228
- code: jsonrpc_model_1.JsonRpcErrorCodes.INVALID_RESPONSE,
230
+ code: JsonRpcErrorCodes.INVALID_RESPONSE,
229
231
  message: `Invalid response. Either result or error must be set, but not both. ${JSON.stringify(response)}`,
230
232
  },
231
233
  id: activeRequest.request.id,
@@ -249,7 +251,7 @@ class JsonRpcWebsocket {
249
251
  }
250
252
  }
251
253
  createPendingRequest(request) {
252
- const response = new deferred_promise_1.DeferredPromise();
254
+ const response = new DeferredPromise();
253
255
  this.pendingRequests[request.id] = {
254
256
  request,
255
257
  response,
@@ -261,12 +263,12 @@ class JsonRpcWebsocket {
261
263
  return self.setTimeout(() => {
262
264
  const activeRequest = this.pendingRequests[requestId];
263
265
  // istanbul ignore if
264
- if (activeRequest === void 0) {
266
+ if (activeRequest === undefined) {
265
267
  return;
266
268
  }
267
269
  const response = {
268
270
  error: {
269
- code: jsonrpc_model_1.JsonRpcErrorCodes.REQUEST_TIMEOUT,
271
+ code: JsonRpcErrorCodes.REQUEST_TIMEOUT,
270
272
  message: `Request ${activeRequest.request.id} exceeded the maximum time of ${this.requestTimeoutMs}ms and was aborted`,
271
273
  },
272
274
  id: activeRequest.request.id,
@@ -277,16 +279,14 @@ class JsonRpcWebsocket {
277
279
  }, this.requestTimeoutMs);
278
280
  }
279
281
  callOnError(error) {
280
- if (this.onError !== void 0) {
282
+ if (this.onError !== undefined) {
281
283
  this.onError(error);
282
284
  }
283
285
  }
284
286
  getRequestId() {
285
287
  return ++this.requestId;
286
288
  }
287
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
288
289
  hasProperty(object, propertyName) {
289
290
  return !!Object.prototype.hasOwnProperty.call(object, propertyName);
290
291
  }
291
292
  }
292
- exports.JsonRpcWebsocket = JsonRpcWebsocket;
@@ -5,7 +5,8 @@ export declare enum JsonRpcErrorCodes {
5
5
  INVALID_PARAMS = -32602,
6
6
  INTERNAL_ERROR = -32603,
7
7
  INVALID_RESPONSE = -32001,
8
- REQUEST_TIMEOUT = -32002
8
+ REQUEST_TIMEOUT = -32002,
9
+ REQUEST_FAILED = -32003
9
10
  }
10
11
  export declare class JsonRpcError {
11
12
  code: number;
@@ -1,8 +1,6 @@
1
- "use strict";
2
1
  /* tslint:disable:max-classes-per-file */
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
2
  // See https://www.jsonrpc.org/specification for the protocol details
5
- var JsonRpcErrorCodes;
3
+ export var JsonRpcErrorCodes;
6
4
  (function (JsonRpcErrorCodes) {
7
5
  JsonRpcErrorCodes[JsonRpcErrorCodes["PARSE_ERROR"] = -32700] = "PARSE_ERROR";
8
6
  JsonRpcErrorCodes[JsonRpcErrorCodes["INVALID_REQUEST"] = -32600] = "INVALID_REQUEST";
@@ -12,13 +10,11 @@ var JsonRpcErrorCodes;
12
10
  // App specific
13
11
  JsonRpcErrorCodes[JsonRpcErrorCodes["INVALID_RESPONSE"] = -32001] = "INVALID_RESPONSE";
14
12
  JsonRpcErrorCodes[JsonRpcErrorCodes["REQUEST_TIMEOUT"] = -32002] = "REQUEST_TIMEOUT";
15
- })(JsonRpcErrorCodes = exports.JsonRpcErrorCodes || (exports.JsonRpcErrorCodes = {}));
16
- class JsonRpcError {
13
+ JsonRpcErrorCodes[JsonRpcErrorCodes["REQUEST_FAILED"] = -32003] = "REQUEST_FAILED";
14
+ })(JsonRpcErrorCodes || (JsonRpcErrorCodes = {}));
15
+ export class JsonRpcError {
17
16
  }
18
- exports.JsonRpcError = JsonRpcError;
19
- class JsonRpcResponse {
17
+ export class JsonRpcResponse {
20
18
  }
21
- exports.JsonRpcResponse = JsonRpcResponse;
22
- class JsonRpcRequest {
19
+ export class JsonRpcRequest {
23
20
  }
24
- exports.JsonRpcRequest = JsonRpcRequest;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsonrpc-client-websocket",
3
- "version": "1.3.0",
3
+ "version": "1.5.1",
4
4
  "description": "A simple JSON RPC 2.0 websocket client",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -8,16 +8,17 @@
8
8
  "lib/**/*"
9
9
  ],
10
10
  "scripts": {
11
- "test": "jest --config jestconfig.json",
11
+ "test": "jest",
12
12
  "coverage": "jest --config jestconfig.json --coverage",
13
13
  "build": "tsc",
14
- "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
14
+ "format": "prettier --write \"src/**/*.ts\"",
15
15
  "lint": "tsc --noEmit && eslint . --ext .js,.jsx,.ts,.tsx --fix",
16
16
  "prepublishOnly": "npm test && npm run lint",
17
17
  "prepare": "npm run build",
18
18
  "preversion": "npm run lint",
19
19
  "version": "npm run format && git add -A src",
20
- "postversion": "git push && git push --tags"
20
+ "postversion": "git push && git push --tags",
21
+ "updateAll": "npm-check-updates --upgrade"
21
22
  },
22
23
  "repository": {
23
24
  "type": "git",
@@ -37,18 +38,20 @@
37
38
  "author": "Fabricio Bastian",
38
39
  "license": "MIT",
39
40
  "devDependencies": {
40
- "@types/jest": "^24.9.1",
41
- "@typescript-eslint/eslint-plugin": "^2.27.0",
42
- "@typescript-eslint/parser": "^2.27.0",
43
- "eslint": "^6.8.0",
44
- "eslint-config-prettier": "^6.10.1",
45
- "eslint-plugin-jest": "^23.8.2",
46
- "jest": "^24.9.0",
47
- "jest-websocket-mock": "^1.5.1",
48
- "mock-socket": "^8.1.1",
49
- "prettier": "^1.19.1",
50
- "ts-jest": "^24.3.0",
51
- "typescript": "^3.8.3"
41
+ "@types/jest": "^27.0.3",
42
+ "@typescript-eslint/eslint-plugin": "^5.4.0",
43
+ "@typescript-eslint/parser": "^5.4.0",
44
+ "eslint": "^8.3.0",
45
+ "eslint-config-prettier": "^8.3.0",
46
+ "eslint-plugin-jest": "^25.3.0",
47
+ "jest": "^27.3.1",
48
+ "jest-websocket-mock": "^2.2.1",
49
+ "mock-socket": "^9.0.8",
50
+ "npm-check-updates": "^12.0.2",
51
+ "prettier": "^2.5.0",
52
+ "ts-jest": "^27.0.7",
53
+ "ts-node": "^10.4.0",
54
+ "typescript": "^4.5.2"
52
55
  },
53
56
  "dependencies": {
54
57
  "get-parameter-names": "^0.3.0"