diff --git a/.gitignore b/.gitignore index ef3aa3b..2db1904 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules/ coverage/ ~$* docs/logo.psd +dist diff --git a/index.js b/index.ts similarity index 67% rename from index.js rename to index.ts index 847b5a4..c60c651 100644 --- a/index.js +++ b/index.ts @@ -1,15 +1,18 @@ -const RPCClient = require('./lib/client'); -const RPCServer = require('./lib/server'); +//@ts-ignore +import RPCClient from './lib/client'; +import RPCServer from './lib/server'; const errors = require('./lib/errors'); const symbols = require('./lib/symbols'); const { createRPCError } = require('./lib/util'); const { createValidator } = require('./lib/validator'); -module.exports = { +export { RPCClient, RPCServer }; + +export default { RPCServer, RPCClient, createRPCError, createValidator, ...errors, ...symbols, -}; \ No newline at end of file +}; diff --git a/lib/server.js b/lib/server.ts similarity index 77% rename from lib/server.js rename to lib/server.ts index 936ed2d..9c9fbf0 100644 --- a/lib/server.js +++ b/lib/server.ts @@ -1,16 +1,57 @@ -const {EventEmitter, once} = require('events'); -const {WebSocketServer, OPEN, CLOSING, CLOSED} = require('ws'); -const {createServer} = require('http'); +import { EventEmitter, once } from 'events'; +const { WebSocketServer, OPEN, CLOSING, CLOSED } = require('ws'); +const { createServer } = require('http'); const RPCServerClient = require('./server-client'); const { abortHandshake, parseSubprotocols } = require('./ws-util'); const standardValidators = require('./standard-validators'); const { getPackageIdent } = require('./util'); const { WebsocketUpgradeError } = require('./errors'); +interface Options { + wssOptions: Object, + protocols: string[], + callTimeoutMs: number, + pingIntervalMs: number, + deferPingsOnActivity: boolean, + respondWithDetailedErrors: boolean, + callConcurrency: number, + maxBadMessages: number, + strictMode: boolean, + strictModeValidators: any[], +} + + +interface ListenOptions { + signal?: AbortSignal, +} + +interface CloseOptions { + code?: number, + reason?: string, + awaitPending?: boolean, + force?: boolean, +} + +type AuthCallback = ( + accept: (session?: any, protocol?: string | false) => void, + reject: (code?: number, message?: string) => void, + handshake: any, + signal: AbortSignal +) => void; + class RPCServer extends EventEmitter { - constructor(options) { + _state: number; + _clients: Set; + _pendingUpgrades: WeakMap; + _options: Options; + _wss: any; + _httpServerAbortControllers: Set; + _strictValidators?: Map; + authCallback?: AuthCallback; + + constructor(options: Partial) { super(); - + this._httpServerAbortControllers = new Set(); this._state = OPEN; this._clients = new Set(); @@ -20,8 +61,8 @@ class RPCServer extends EventEmitter { // defaults wssOptions: {}, protocols: [], - callTimeoutMs: 1000*30, - pingIntervalMs: 1000*30, + callTimeoutMs: 1000 * 30, + pingIntervalMs: 1000 * 30, deferPingsOnActivity: false, respondWithDetailedErrors: false, callConcurrency: 1, @@ -35,18 +76,18 @@ class RPCServer extends EventEmitter { this._wss = new WebSocketServer({ ...this._options.wssOptions, noServer: true, - handleProtocols: (protocols, request) => { - const {protocol} = this._pendingUpgrades.get(request); + handleProtocols: (protocols: any, request: any) => { + const { protocol } = this._pendingUpgrades.get(request); return protocol; }, }); - this._wss.on('headers', h => h.push(`Server: ${getPackageIdent()}`)); - this._wss.on('error', err => this.emit('error', err)); + this._wss.on('headers', (h: any) => h.push(`Server: ${getPackageIdent()}`)); + this._wss.on('error', (err: any) => this.emit('error', err)); this._wss.on('connection', this._onConnection.bind(this)); } - - reconfigure(options) { + + reconfigure(options: Partial) { const newOpts = Object.assign({}, this._options, options); if (newOpts.strictMode && !newOpts.protocols?.length) { @@ -62,15 +103,15 @@ class RPCServer extends EventEmitter { svs.set(v.subprotocol, v); return svs; }, new Map()); - - let strictProtocols = []; + + let strictProtocols: any[] = []; if (Array.isArray(newOpts.strictMode)) { strictProtocols = newOpts.strictMode; } else if (newOpts.strictMode) { strictProtocols = newOpts.protocols; } - const missingValidator = strictProtocols.find(protocol => !this._strictValidators.has(protocol)); + const missingValidator = strictProtocols.find(protocol => !this._strictValidators?.has(protocol)); if (missingValidator) { throw Error(`Missing strictMode validator for subprotocol '${missingValidator}'`); } @@ -79,18 +120,18 @@ class RPCServer extends EventEmitter { } get handleUpgrade() { - return async (request, socket, head) => { + return async (request: any, socket: any, head: any) => { let resolved = false; const ac = new AbortController(); - const {signal} = ac; + const { signal } = ac; const url = new URL('http://localhost' + (request.url || '/')); const pathParts = url.pathname.split('/'); - const identity = decodeURIComponent(pathParts.pop()); + const identity = decodeURIComponent(pathParts.pop() || ''); - const abortUpgrade = (error) => { + const abortUpgrade = (error: any) => { resolved = true; if (error && error instanceof WebsocketUpgradeError) { @@ -110,7 +151,7 @@ class RPCServer extends EventEmitter { } }; - socket.on('error', (err) => { + socket.on('error', (err: any) => { abortUpgrade(err); }); @@ -118,17 +159,17 @@ class RPCServer extends EventEmitter { if (this._state !== OPEN) { throw new WebsocketUpgradeError(500, "Server not open"); } - + if (socket.readyState !== 'open') { throw new WebsocketUpgradeError(400, `Client readyState = '${socket.readyState}'`); } - + const headers = request.headers; if (headers.upgrade.toLowerCase() !== 'websocket') { throw new WebsocketUpgradeError(400, "Can only upgrade websocket upgrade requests"); } - + const endpoint = pathParts.join('/') || '/'; const remoteAddress = request.socket.remoteAddress; const protocols = ('sec-websocket-protocol' in request.headers) @@ -174,10 +215,10 @@ class RPCServer extends EventEmitter { password, }; - const accept = (session, protocol) => { + const accept = (session: any, protocol: any) => { if (resolved) return; resolved = true; - + try { if (socket.readyState !== 'open') { throw new WebsocketUpgradeError(400, `Client readyState = '${socket.readyState}'`); @@ -197,7 +238,7 @@ class RPCServer extends EventEmitter { handshake }); - this._wss.handleUpgrade(request, socket, head, ws => { + this._wss.handleUpgrade(request, socket, head, (ws: any) => { this._wss.emit('connection', ws, request); }); } catch (err) { @@ -227,7 +268,7 @@ class RPCServer extends EventEmitter { signal ); } else { - accept(); + (accept as any)(); } } catch (err) { @@ -236,13 +277,13 @@ class RPCServer extends EventEmitter { }; } - async _onConnection(websocket, request) { + async _onConnection(websocket: any, request: any) { try { if (this._state !== OPEN) { throw Error("Server is no longer open"); } - const {handshake, session} = this._pendingUpgrades.get(request); + const { handshake, session } = this._pendingUpgrades.get(request); const client = new RPCServerClient({ identity: handshake.identity, @@ -266,50 +307,51 @@ class RPCServer extends EventEmitter { client.once('close', () => this._clients.delete(client)); this.emit('client', client); - } catch (err) { + } catch (error) { + const err = error as { statusCode: number, message: string }; websocket.close(err.statusCode || 1000, err.message); } } - auth(cb) { + auth(cb: AuthCallback) { this.authCallback = cb; } - async listen(port, host, options = {}) { + async listen(port: number, host?: string, options: ListenOptions = {}) { const ac = new AbortController(); this._httpServerAbortControllers.add(ac); if (options.signal) { once(options.signal, 'abort').then(() => { - ac.abort(options.signal.reason); + ac.abort(options.signal!.reason); }); } const httpServer = createServer({ noDelay: true, - }, (req, res) => { + }, (req: any, res: any) => { res.setHeader('Server', getPackageIdent()); res.statusCode = 404; res.end(); }); httpServer.on('upgrade', this.handleUpgrade); httpServer.once('close', () => this._httpServerAbortControllers.delete(ac)); - await new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { httpServer.listen({ port, host, signal: ac.signal, - }, err => err ? reject(err) : resolve()); + }, (err: any) => err ? reject(err) : resolve()); }); return httpServer; } - async close({code, reason, awaitPending, force} = {}) { + async close({ code, reason, awaitPending, force }: CloseOptions = {}) { if (this._state === OPEN) { this._state = CLOSING; this.emit('closing'); code = code ?? 1001; - await Array.from(this._clients).map(cli => cli.close({code, reason, awaitPending, force})); - await new Promise((resolve, reject) => { - this._wss.close(err => err ? reject(err) : resolve()); + await Array.from(this._clients).map((client: any) => client.close({ code, reason, awaitPending, force })); + await new Promise((resolve, reject) => { + this._wss.close((err: any) => err ? reject(err) : resolve()); this._httpServerAbortControllers.forEach(ac => ac.abort("Closing")); }); this._state = CLOSED; @@ -318,4 +360,4 @@ class RPCServer extends EventEmitter { } } -module.exports = RPCServer; \ No newline at end of file +export default RPCServer; diff --git a/lib/util.js b/lib/util.js index f628417..4a9a9c2 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,25 +1,25 @@ const errors = require('./errors'); -const package = require('../package.json'); +const packageJson = require('../package.json'); const rpcErrorLUT = { - 'GenericError' : errors.RPCGenericError, - 'NotImplemented' : errors.RPCNotImplementedError, - 'NotSupported' : errors.RPCNotSupportedError, - 'InternalError' : errors.RPCInternalError, - 'ProtocolError' : errors.RPCProtocolError, - 'SecurityError' : errors.RPCSecurityError, - 'FormationViolation' : errors.RPCFormationViolationError, - 'FormatViolation' : errors.RPCFormatViolationError, - 'PropertyConstraintViolation' : errors.RPCPropertyConstraintViolationError, - 'OccurenceConstraintViolation' : errors.RPCOccurenceConstraintViolationError, - 'OccurrenceConstraintViolation' : errors.RPCOccurrenceConstraintViolationError, - 'TypeConstraintViolation' : errors.RPCTypeConstraintViolationError, - 'MessageTypeNotSupported' : errors.RPCMessageTypeNotSupportedError, - 'RpcFrameworkError' : errors.RPCFrameworkError, + 'GenericError': errors.RPCGenericError, + 'NotImplemented': errors.RPCNotImplementedError, + 'NotSupported': errors.RPCNotSupportedError, + 'InternalError': errors.RPCInternalError, + 'ProtocolError': errors.RPCProtocolError, + 'SecurityError': errors.RPCSecurityError, + 'FormationViolation': errors.RPCFormationViolationError, + 'FormatViolation': errors.RPCFormatViolationError, + 'PropertyConstraintViolation': errors.RPCPropertyConstraintViolationError, + 'OccurenceConstraintViolation': errors.RPCOccurenceConstraintViolationError, + 'OccurrenceConstraintViolation': errors.RPCOccurrenceConstraintViolationError, + 'TypeConstraintViolation': errors.RPCTypeConstraintViolationError, + 'MessageTypeNotSupported': errors.RPCMessageTypeNotSupportedError, + 'RpcFrameworkError': errors.RPCFrameworkError, }; function getPackageIdent() { - return `${package.name}/${package.version} (${process.platform})`; + return `${packageJson.name}/${packageJson.version} (${process.platform})`; } function getErrorPlainObject(err) { diff --git a/package-lock.json b/package-lock.json index 23ac94b..1d70f7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,10 +16,12 @@ }, "devDependencies": { "mocha": "^10.0.0", - "nyc": "^15.1.0" + "nyc": "^15.1.0", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" }, "engines": { - "node": ">=17.2.0" + "node": ">=17.3.0" } }, "node_modules/@ampproject/remapping": { @@ -401,6 +403,28 @@ "node": ">=6.9.0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -547,12 +571,67 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", + "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "dev": true, + "peer": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -661,6 +740,12 @@ "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -904,6 +989,12 @@ "safe-buffer": "~5.1.1" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1606,6 +1697,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/minimatch": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", @@ -2362,6 +2459,58 @@ "node": ">=8.0" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -2380,6 +2529,26 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "peer": true + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -2398,6 +2567,12 @@ "uuid": "bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2555,6 +2730,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -2861,6 +3045,27 @@ "to-fast-properties": "^2.0.0" } }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -2976,12 +3181,58 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "@types/node": { + "version": "20.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", + "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "dev": true, + "peer": true, + "requires": { + "undici-types": "~5.26.4" + } + }, "@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, + "acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true + }, + "acorn-walk": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "dev": true + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -3057,6 +3308,12 @@ "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3235,6 +3492,12 @@ "safe-buffer": "~5.1.1" } }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3733,6 +3996,12 @@ "semver": "^6.0.0" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "minimatch": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", @@ -4309,6 +4578,35 @@ "is-number": "^7.0.0" } }, + "ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -4324,6 +4622,19 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true + }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "peer": true + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -4338,6 +4649,12 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4447,6 +4764,12 @@ } } }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index ad83fc2..705d0fe 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "A client & server implementation of the WAMP-like RPC-over-websocket system defined in the OCPP protocols (e.g. OCPP1.6-J and OCPP2.0.1).", "main": "index.js", "scripts": { - "test": "mocha", + "test": "mocha -r ts-node/register 'test/**/*.{js,ts}'", "coverage": "nyc --reporter=lcov --reporter=text mocha" }, "engines": { @@ -44,6 +44,8 @@ }, "devDependencies": { "mocha": "^10.0.0", - "nyc": "^15.1.0" + "nyc": "^15.1.0", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" } -} +} \ No newline at end of file diff --git a/test/client.js b/test/client.ts similarity index 79% rename from test/client.js rename to test/client.ts index 177e0fd..fb9fd89 100644 --- a/test/client.js +++ b/test/client.ts @@ -1,16 +1,17 @@ +// @ts-nocheck const assert = require('assert/strict'); const http = require('http'); const { once } = require('events'); const RPCClient = require("../lib/client"); const { TimeoutError, RPCFrameworkError, RPCError, RPCProtocolError, RPCTypeConstraintViolationError, RPCOccurenceConstraintViolationError, RPCPropertyConstraintViolationError, RPCOccurrenceConstraintViolationError, RPCFormationViolationError } = require('../lib/errors'); -const RPCServer = require("../lib/server"); +import RPCServer from "../lib/server"; const { setTimeout } = require('timers/promises'); const { createValidator } = require('../lib/validator'); const { createRPCError } = require('../lib/util'); const { NOREPLY } = require('../lib/symbols'); -const {CLOSING, CLOSED, CONNECTING} = RPCClient; +const { CLOSING, CLOSED, CONNECTING } = RPCClient; -describe('RPCClient', function(){ +describe('RPCClient', function () { this.timeout(500); async function createServer(options = {}, extra = {}) { @@ -20,29 +21,29 @@ describe('RPCClient', function(){ const endpoint = `ws://localhost:${port}`; const close = (...args) => server.close(...args); server.on('client', client => { - client.handle('Echo', async ({params}) => { + client.handle('Echo', async ({ params }) => { return params; }); - client.handle('Sleep', async ({params, signal}) => { - await setTimeout(params.ms, null, {signal}); + client.handle('Sleep', async ({ params, signal }) => { + await setTimeout(params.ms, null, { signal }); return `Waited ${params.ms}ms`; }); - client.handle('Reject', async ({params}) => { + client.handle('Reject', async ({ params }) => { const err = Error("Rejecting"); Object.assign(err, params); throw err; }); client.handle('Heartbeat', () => { - return {currentTime: new Date().toISOString()}; + return { currentTime: new Date().toISOString() }; }); - client.handle('TestTenth', ({params}) => { - return {val: params.val / 10}; + client.handle('TestTenth', ({ params }) => { + return { val: params.val / 10 }; }); if (extra.withClient) { extra.withClient(client); } }); - return {server, httpServer, port, endpoint, close}; + return { server, httpServer, port, endpoint, close }; } function getEchoValidator() { @@ -105,7 +106,7 @@ describe('RPCClient', function(){ ]); } - describe('#constructor', function(){ + describe('#constructor', function () { it('should throw on missing identity', async () => { @@ -180,13 +181,13 @@ describe('RPCClient', function(){ }); - describe('events', function(){ + describe('events', function () { it('should emit call and response events', async () => { - const {endpoint, close} = await createServer({}, { + const { endpoint, close } = await createServer({}, { withClient: cli => { - cli.call('Test').catch(()=>{}); + cli.call('Test').catch(() => { }); } }); const cli = new RPCClient({ @@ -200,14 +201,14 @@ describe('RPCClient', function(){ }; cli.on('call', call => { - test[call.outbound?'out':'in'].call = call; + test[call.outbound ? 'out' : 'in'].call = call; }); cli.on('response', response => { - test[response.outbound?'out':'in'].response = response; + test[response.outbound ? 'out' : 'in'].response = response; }); await cli.connect(); - await cli.call('Sleep', {ms: 25}); + await cli.call('Sleep', { ms: 25 }); await cli.close(); await close(); @@ -222,7 +223,7 @@ describe('RPCClient', function(){ it('should emit callResult and callError events for outbound calls', async () => { - const {endpoint, close} = await createServer({}, {}); + const { endpoint, close } = await createServer({}, {}); const cli = new RPCClient({ endpoint, identity: 'X', @@ -240,8 +241,8 @@ describe('RPCClient', function(){ }); await cli.connect(); - await cli.call('Echo', {txt: 'Test'}); - await cli.call('Reject', {details:{code: 'Test'}}).catch(()=>{}); + await cli.call('Echo', { txt: 'Test' }); + await cli.call('Reject', { details: { code: 'Test' } }).catch(() => { }); await cli.close(); await close(); @@ -249,7 +250,7 @@ describe('RPCClient', function(){ assert.equal(result.outbound, true); assert.equal(result.params.txt, 'Test'); assert.equal(result.result.txt, 'Test'); - + assert.equal(error.method, 'Reject'); assert.equal(error.outbound, true); assert.equal(error.params.details.code, 'Test'); @@ -260,12 +261,12 @@ describe('RPCClient', function(){ it('should emit callResult and callError events for inbound calls', async () => { let resolveReceived; - let received = new Promise(r => {resolveReceived = r}); + let received = new Promise(r => { resolveReceived = r }); - const {endpoint, close} = await createServer({}, { + const { endpoint, close } = await createServer({}, { withClient: async (cli) => { - await cli.call('Echo', {txt: 'Test'}); - await cli.call('Reject', {details:{code: 'Test'}}).catch(()=>{}); + await cli.call('Echo', { txt: 'Test' }); + await cli.call('Reject', { details: { code: 'Test' } }).catch(() => { }); } }); const cli = new RPCClient({ @@ -273,11 +274,11 @@ describe('RPCClient', function(){ identity: 'X', }); - cli.handle('Echo', async ({params}) => { + cli.handle('Echo', async ({ params }) => { return params; }); - - cli.handle('Reject', async ({params}) => { + + cli.handle('Reject', async ({ params }) => { const err = Error("Rejecting"); Object.assign(err, params); throw err; @@ -304,7 +305,7 @@ describe('RPCClient', function(){ assert.equal(result.outbound, false); assert.equal(result.params.txt, 'Test'); assert.equal(result.result.txt, 'Test'); - + assert.equal(error.method, 'Reject'); assert.equal(error.outbound, false); assert.equal(error.params.details.code, 'Test'); @@ -313,8 +314,8 @@ describe('RPCClient', function(){ }); it('should emit 2 message events after call', async () => { - - const {endpoint, close} = await createServer(); + + const { endpoint, close } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', @@ -326,7 +327,7 @@ describe('RPCClient', function(){ payload: JSON.parse(m.message.toString('utf8')), outbound: m.outbound, })); - await cli.call('Echo', {val: 123}); + await cli.call('Echo', { val: 123 }); await cli.close(); await close(); @@ -341,12 +342,12 @@ describe('RPCClient', function(){ }); it('should emit 2 message events after handle', async () => { - + let complete; - let done = new Promise(r=>{complete = r;}); - const {endpoint, close} = await createServer({}, { + let done = new Promise(r => { complete = r; }); + const { endpoint, close } = await createServer({}, { withClient: async (cli) => { - await cli.call('Echo', {val: 123}); + await cli.call('Echo', { val: 123 }); cli.close(); complete(); } @@ -357,7 +358,7 @@ describe('RPCClient', function(){ reconnect: false, }); - cli.handle('Echo', ({params}) => params); + cli.handle('Echo', ({ params }) => params); const messages = []; await cli.connect(); @@ -380,7 +381,7 @@ describe('RPCClient', function(){ }); it("should emit 'badMessage' with 'RpcFrameworkError' when message is not a JSON structure", async () => { - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: cli => { cli.sendRaw('{]'); } @@ -401,7 +402,7 @@ describe('RPCClient', function(){ }); it("should emit 'badMessage' with 'RpcFrameworkError' when message is not an array", async () => { - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: cli => { cli.sendRaw('{}'); } @@ -422,7 +423,7 @@ describe('RPCClient', function(){ }); it("should emit 'badMessage' with 'RpcFrameworkError' when message type is not a number", async () => { - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: cli => { cli.sendRaw('["a", "123", "Echo", {}]'); } @@ -443,7 +444,7 @@ describe('RPCClient', function(){ }); it("should emit 'badMessage' with 'MessageTypeNotSupported' when message type unrecognised", async () => { - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: cli => { cli.sendRaw('[0, "123", "Echo", {}]'); } @@ -464,7 +465,7 @@ describe('RPCClient', function(){ }); it("should emit 'badMessage' with 'RpcFrameworkError' when message ID is not a string", async () => { - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: cli => { cli.sendRaw('[2, 123, "Echo", {}]'); } @@ -485,7 +486,7 @@ describe('RPCClient', function(){ }); it("should emit 'badMessage' with 'RpcFrameworkError' when method is not a string", async () => { - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: cli => { cli.sendRaw('[2, "123", 123, {}]'); } @@ -506,7 +507,7 @@ describe('RPCClient', function(){ }); it("should emit 'badMessage' with 'RpcFrameworkError' when message ID is repeated", async () => { - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: cli => { } @@ -518,7 +519,7 @@ describe('RPCClient', function(){ try { await cli.connect(); - + cli.sendRaw('[2, "123", "Sleep", {"ms":20}]'); cli.sendRaw('[2, "123", "Sleep", {"ms":20}]'); @@ -534,11 +535,11 @@ describe('RPCClient', function(){ }); }); - describe('#connect', function(){ + describe('#connect', function () { it('should connect to an RPCServer', async () => { - const {endpoint, close} = await createServer(); + const { endpoint, close } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', @@ -564,9 +565,9 @@ describe('RPCClient', function(){ }, err => err ? reject(err) : resolve()); }); const port = httpServer.address().port; - + const endpoint = `ws://localhost:${port}`; - const cli = new RPCClient({endpoint, identity: 'X'}); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { await assert.rejects(cli.connect()); @@ -579,7 +580,7 @@ describe('RPCClient', function(){ it('should reject on non-ws endpoint URL', async () => { - const {close, port} = await createServer(); + const { close, port } = await createServer(); const cli = new RPCClient({ endpoint: `http://localhost:${port}`, identity: 'X', @@ -596,7 +597,7 @@ describe('RPCClient', function(){ it('should reject on malformed endpoint URL', async () => { - const {close} = await createServer(); + const { close } = await createServer(); const cli = new RPCClient({ endpoint: 'x', identity: 'X', @@ -613,7 +614,7 @@ describe('RPCClient', function(){ it('should reject on unreachable address', async () => { - const {close} = await createServer(); + const { close } = await createServer(); const cli = new RPCClient({ endpoint: 'ws://0.0.0.0:0', identity: 'X', @@ -630,7 +631,7 @@ describe('RPCClient', function(){ it('should reject when no subprotocols match', async () => { - const {endpoint, close} = await createServer({protocols: ['one', 'two']}); + const { endpoint, close } = await createServer({ protocols: ['one', 'two'] }); const cli = new RPCClient({ endpoint, identity: 'X', @@ -648,7 +649,7 @@ describe('RPCClient', function(){ it('should select first matching subprotocol', async () => { - const {endpoint, close} = await createServer({protocols: ['one', 'two', 'three', 'four', 'x']}); + const { endpoint, close } = await createServer({ protocols: ['one', 'two', 'three', 'four', 'x'] }); const cli = new RPCClient({ endpoint, identity: 'X', @@ -666,9 +667,9 @@ describe('RPCClient', function(){ }); it('should pass query string to server (as object)', async () => { - + let shake; - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: client => { client.handle('GetQuery', () => client.handshake.query.toString()); } @@ -681,7 +682,7 @@ describe('RPCClient', function(){ const cli = new RPCClient({ endpoint, identity: 'X', - query: {'x-test': 'abc', '?=': '123'}, + query: { 'x-test': 'abc', '?=': '123' }, }); try { @@ -697,9 +698,9 @@ describe('RPCClient', function(){ }); it('should pass query string to server (as string)', async () => { - + let shake; - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); server.auth((accept, reject, handshake) => { shake = handshake; accept(); @@ -722,9 +723,9 @@ describe('RPCClient', function(){ }); it('should pass headers to server', async () => { - + let shake; - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: client => { client.handle('GetHeaders', () => client.handshake.headers); } @@ -756,9 +757,9 @@ describe('RPCClient', function(){ }); it('should also pass headers to server via wsOpts (but can be overridden by headers option)', async () => { - + let shake; - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: client => { client.handle('GetHeaders', () => client.handshake.headers); } @@ -800,8 +801,8 @@ describe('RPCClient', function(){ }); it('should reject while closing', async () => { - - const {endpoint, close, server} = await createServer(); + + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, @@ -812,8 +813,8 @@ describe('RPCClient', function(){ await cli.connect(); const [call, closed, connected] = await Promise.allSettled([ - cli.call('Sleep', {ms: 30}), - cli.close({awaitPending: true}), + cli.call('Sleep', { ms: 30 }), + cli.close({ awaitPending: true }), cli.connect(), ]); @@ -828,8 +829,8 @@ describe('RPCClient', function(){ }); it('should do nothing if already connected', async () => { - - const {endpoint, close, server} = await createServer(); + + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, @@ -846,8 +847,8 @@ describe('RPCClient', function(){ }); it('should resolve to the same result when called simultaneously', async () => { - - const {endpoint, close, server} = await createServer(); + + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, @@ -870,11 +871,11 @@ describe('RPCClient', function(){ }); it('should authenticate with string passwords', async () => { - + const password = 'hunter2'; let recPass; - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); server.auth((accept, reject, handshake) => { recPass = handshake.password; accept(); @@ -897,15 +898,15 @@ describe('RPCClient', function(){ }); it('should authenticate with binary passwords', async () => { - + const password = Buffer.from([ - 0,1,2,3,4,5,6,7,8,9, - 65,66,67,68,69, - 251,252,253,254,255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 65, 66, 67, 68, 69, + 251, 252, 253, 254, 255, ]); let recPass; - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); server.auth((accept, reject, handshake) => { recPass = handshake.password; accept(); @@ -931,19 +932,19 @@ describe('RPCClient', function(){ }); - describe('#close', function() { + describe('#close', function () { it('should pass code and reason to server', async () => { - const {server, endpoint, close} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { server, endpoint, close } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { const serverClientPromise = once(server, 'client'); await cli.connect(); const [serverClient] = await serverClientPromise; const serverClosePromise = once(serverClient, 'close'); - await cli.close({code: 4001, reason: 'TEST'}); + await cli.close({ code: 4001, reason: 'TEST' }); const [serverClose] = await serverClosePromise; assert.equal(serverClose.code, 4001); assert.equal(serverClose.reason, 'TEST'); @@ -956,18 +957,18 @@ describe('RPCClient', function(){ it('should treat invalid/reserved close codes as 1000', async () => { - const {server, endpoint, close} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { server, endpoint, close } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { - const testCodes = [-1000,0,1,1005,10000]; + const testCodes = [-1000, 0, 1, 1005, 10000]; for (const testCode of testCodes) { const serverClientPromise = once(server, 'client'); await cli.connect(); const [serverClient] = await serverClientPromise; const serverClosePromise = once(serverClient, 'close'); - await cli.close({code: testCode}); + await cli.close({ code: testCode }); const [serverClose] = await serverClosePromise; assert.equal(serverClose.code, 1000); } @@ -980,19 +981,19 @@ describe('RPCClient', function(){ it('should return the close code of the first close() call', async () => { - const {endpoint, close} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { endpoint, close } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { await cli.connect(); - const p1 = cli.close({code: 4001, reason: 'FIRST'}); - const p2 = cli.close({code: 4002, reason: 'SECOND'}); + const p1 = cli.close({ code: 4001, reason: 'FIRST' }); + const p2 = cli.close({ code: 4002, reason: 'SECOND' }); const [v1, v2] = await Promise.all([p1, p2]); assert.equal(v1.code, 4001); assert.equal(v1.reason, 'FIRST'); assert.equal(v2.code, 4001); assert.equal(v2.reason, 'FIRST'); - const v3 = await cli.close({code: 4003, reason: 'THIRD'}); + const v3 = await cli.close({ code: 4003, reason: 'THIRD' }); assert.equal(v3.code, 4001); assert.equal(v3.reason, 'FIRST'); @@ -1004,12 +1005,12 @@ describe('RPCClient', function(){ it('should abort #connect if connection in progress, with code 1001', async () => { - const {endpoint, close} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { endpoint, close } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { const connPromise = cli.connect(); - const closePromise = cli.close({code: 4001}); // 4001 should be ignored + const closePromise = cli.close({ code: 4001 }); // 4001 should be ignored const [connResult, closeResult] = await Promise.allSettled([connPromise, closePromise]); assert.equal(connResult.status, 'rejected'); assert.equal(connResult.reason.name, 'AbortError'); @@ -1023,8 +1024,8 @@ describe('RPCClient', function(){ it('should not throw if already closed', async () => { - const {endpoint, close} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { endpoint, close } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { await cli.connect(); @@ -1038,14 +1039,14 @@ describe('RPCClient', function(){ it('should abort all outbound calls when {awaitPending: false}', async () => { - const {endpoint, close, server} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { endpoint, close, server } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { await cli.connect(); const [callResult, closeResult] = await Promise.allSettled([ - cli.call('Sleep', {ms: 100}), - cli.close({awaitPending: false}) + cli.call('Sleep', { ms: 100 }), + cli.close({ awaitPending: false }) ]); assert.equal(callResult.status, 'rejected'); assert.equal(closeResult.status, 'fulfilled'); @@ -1057,25 +1058,25 @@ describe('RPCClient', function(){ }); it('should abort all inbound calls when {awaitPending: false}', async () => { - + let serverInitiatedCall = null; - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: client => { - serverInitiatedCall = client.call('Sleep', {ms: 50}); + serverInitiatedCall = client.call('Sleep', { ms: 50 }); } }); - const cli = new RPCClient({endpoint, identity: 'X'}); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { - cli.handle('Sleep', async ({params, signal}) => { - await setTimeout(params.ms, null, {signal}); + cli.handle('Sleep', async ({ params, signal }) => { + await setTimeout(params.ms, null, { signal }); }); await cli.connect(); - + const [callResult, closeResult] = await Promise.allSettled([ serverInitiatedCall, - cli.close({awaitPending: false}) + cli.close({ awaitPending: false }) ]); assert.equal(callResult.status, 'rejected'); assert.equal(closeResult.status, 'fulfilled'); @@ -1088,15 +1089,15 @@ describe('RPCClient', function(){ it('should wait for all outbound calls to settle when {awaitPending: true}', async () => { - const {endpoint, close, server} = await createServer({respondWithDetailedErrors: true}); - const cli = new RPCClient({endpoint, identity: 'X', callConcurrency: 2}); + const { endpoint, close, server } = await createServer({ respondWithDetailedErrors: true }); + const cli = new RPCClient({ endpoint, identity: 'X', callConcurrency: 2 }); try { await cli.connect(); const [rejectResult, sleepResult, closeResult] = await Promise.allSettled([ - cli.call('Reject', {code: 'TEST'}), - cli.call('Sleep', {ms: 50}), - cli.close({awaitPending: true}) + cli.call('Reject', { code: 'TEST' }), + cli.call('Sleep', { ms: 50 }), + cli.close({ awaitPending: true }) ]); assert.equal(rejectResult.status, 'rejected'); @@ -1111,29 +1112,29 @@ describe('RPCClient', function(){ }); it('should wait for all inbound calls to settle when {awaitPending: true}', async () => { - + const echoVal = 'TEST123'; let serverInitiatedCall = null; - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: client => { - serverInitiatedCall = client.call('SlowEcho', {ms: 50, val: echoVal}); + serverInitiatedCall = client.call('SlowEcho', { ms: 50, val: echoVal }); } }); - const cli = new RPCClient({endpoint, identity: 'X'}); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { - cli.handle('SlowEcho', async ({params}) => { + cli.handle('SlowEcho', async ({ params }) => { await setTimeout(params.ms); return params.val; }); await cli.connect(); - + const [callResult, closeResult] = await Promise.allSettled([ serverInitiatedCall, - setTimeout(1).then(() => cli.close({awaitPending: true})), + setTimeout(1).then(() => cli.close({ awaitPending: true })), ]); - + assert.equal(callResult.status, 'fulfilled'); assert.equal(callResult.value, echoVal); assert.equal(closeResult.status, 'fulfilled'); @@ -1145,13 +1146,13 @@ describe('RPCClient', function(){ }); it('should close immediately with code 1006 when {force: true}', async () => { - - const {endpoint, close, server} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + + const { endpoint, close, server } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { await cli.connect(); - cli.close({code: 4000, force: true}); + cli.close({ code: 4000, force: true }); const [dc] = await once(cli, 'close'); assert.equal(dc.code, 1006); @@ -1162,33 +1163,33 @@ describe('RPCClient', function(){ }); it('should immediately reject any in-flight calls when {force: true}', async () => { - + let serverInitiatedCall = null; - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: client => { - serverInitiatedCall = client.call('Sleep', {ms: 5000}); + serverInitiatedCall = client.call('Sleep', { ms: 5000 }); } }); - const cli = new RPCClient({endpoint, identity: 'X'}); - cli.handle('Sleep', async ({params, signal}) => { - await setTimeout(params.ms, null, {signal}); + const cli = new RPCClient({ endpoint, identity: 'X' }); + cli.handle('Sleep', async ({ params, signal }) => { + await setTimeout(params.ms, null, { signal }); return `Waited ${params.ms}ms`; }); try { await cli.connect(); - const clientInitiatedCall = cli.call('Sleep', {ms: 5000}); + const clientInitiatedCall = cli.call('Sleep', { ms: 5000 }); - cli.close({code: 4000, force: true}); + cli.close({ code: 4000, force: true }); const dcp = once(cli, 'close'); await assert.rejects(clientInitiatedCall); await assert.rejects(serverInitiatedCall); - + const [dc] = await dcp; assert.equal(dc.code, 1006); - + } finally { close(); @@ -1197,8 +1198,8 @@ describe('RPCClient', function(){ }); it('should not reconnect even when {reconnect: true}', async () => { - - const {endpoint, close, server} = await createServer({ + + const { endpoint, close, server } = await createServer({ protocols: ['a'], }); @@ -1217,7 +1218,7 @@ describe('RPCClient', function(){ try { await cli.connect(); - const dc = await cli.close({code: 4000}); + const dc = await cli.close({ code: 4000 }); assert.equal(dc.code, 4000); assert.equal(connectCount, 1); @@ -1230,11 +1231,11 @@ describe('RPCClient', function(){ }); - describe('#call', function() { + describe('#call', function () { it("should reject with 'RPCError' after invalid payload with client strictMode", async () => { - - const {endpoint, close, server} = await createServer({ + + const { endpoint, close, server } = await createServer({ protocols: ['echo1.0'] }); const cli = new RPCClient({ @@ -1249,8 +1250,8 @@ describe('RPCClient', function(){ await cli.connect(); const [c1, c2, c3] = await Promise.allSettled([ - cli.call('Echo', {val: '123'}), - cli.call('Echo', {val: 123}), + cli.call('Echo', { val: '123' }), + cli.call('Echo', { val: 123 }), cli.call('Unknown'), ]); @@ -1271,13 +1272,15 @@ describe('RPCClient', function(){ }); it("should reject with 'RPCError' after invalid payload with server strictMode", async () => { - - const {endpoint, close, server} = await createServer({ + + const { endpoint, close, server } = await createServer({ protocols: ['ocpp1.6'], strictMode: true, - }, {withClient: cli => { - cli.handle(() => {}); - }}); + }, { + withClient: cli => { + cli.handle(() => { }); + } + }); const cli = new RPCClient({ endpoint, identity: 'X', @@ -1289,8 +1292,8 @@ describe('RPCClient', function(){ const [c1, c2, c3] = await Promise.allSettled([ cli.call('UpdateFirmware', {}), - cli.call('Heartbeat', {a:123}), - cli.call('UpdateFirmware', {location: "a", retrieveDate: "a"}), + cli.call('Heartbeat', { a: 123 }), + cli.call('UpdateFirmware', { location: "a", retrieveDate: "a" }), ]); assert.equal(c1.status, 'rejected'); @@ -1310,21 +1313,23 @@ describe('RPCClient', function(){ }); - + it("should reject with 'RPCProtocolError' after invalid response with strictMode", async () => { - const {endpoint, close, server} = await createServer({ + const { endpoint, close, server } = await createServer({ protocols: ['echo1.0'] - }, {withClient: cli => { - cli.handle('Echo', async ({params}) => { - switch (params.val) { - case '1': return {bad: true}; - case '2': return 123; - case '3': return [1,2,3]; - case '4': return null; - case '5': return {val: params.val}; - } - }); - }}); + }, { + withClient: cli => { + cli.handle('Echo', async ({ params }) => { + switch (params.val) { + case '1': return { bad: true }; + case '2': return 123; + case '3': return [1, 2, 3]; + case '4': return null; + case '5': return { val: params.val }; + } + }); + } + }); const cli = new RPCClient({ endpoint, identity: 'X', @@ -1337,11 +1342,11 @@ describe('RPCClient', function(){ await cli.connect(); const [c1, c2, c3, c4, c5] = await Promise.allSettled([ - cli.call('Echo', {val: '1'}), - cli.call('Echo', {val: '2'}), - cli.call('Echo', {val: '3'}), - cli.call('Echo', {val: '4'}), - cli.call('Echo', {val: '5'}), + cli.call('Echo', { val: '1' }), + cli.call('Echo', { val: '2' }), + cli.call('Echo', { val: '3' }), + cli.call('Echo', { val: '4' }), + cli.call('Echo', { val: '5' }), ]); assert.equal(c1.status, 'rejected'); @@ -1361,16 +1366,18 @@ describe('RPCClient', function(){ } }); - + it("should emit 'strictValidationFailure' when incoming call is rejected by strictMode", async () => { - - const {endpoint, close, server} = await createServer({ + + const { endpoint, close, server } = await createServer({ protocols: ['echo1.0'] - }, {withClient: async (cli) => { - await cli.call('Echo', {bad: true}).catch(()=>{}); - await cli.call('Echo').catch(()=>{}); - await cli.call('Unknown').catch(()=>{}); - }}); + }, { + withClient: async (cli) => { + await cli.call('Echo', { bad: true }).catch(() => { }); + await cli.call('Echo').catch(() => { }); + await cli.call('Unknown').catch(() => { }); + } + }); const cli = new RPCClient({ endpoint, identity: 'X', @@ -1381,7 +1388,7 @@ describe('RPCClient', function(){ try { let uks = 0; - cli.handle('Echo', ({params}) => params); + cli.handle('Echo', ({ params }) => params); cli.handle('Unknown', () => ++uks); await cli.connect(); @@ -1411,21 +1418,23 @@ describe('RPCClient', function(){ }); - + it("should emit 'strictValidationFailure' when outgoing response is discarded by strictMode", async () => { - const {endpoint, close, server} = await createServer({ + const { endpoint, close, server } = await createServer({ protocols: ['echo1.0'] - }, {withClient: cli => { - cli.handle('Echo', async ({params}) => { - switch (params.val) { - case '1': return {bad: true}; - case '2': return 123; - case '3': return [1,2,3]; - case '4': return null; - case '5': return {val: params.val}; - } - }); - }}); + }, { + withClient: cli => { + cli.handle('Echo', async ({ params }) => { + switch (params.val) { + case '1': return { bad: true }; + case '2': return 123; + case '3': return [1, 2, 3]; + case '4': return null; + case '5': return { val: params.val }; + } + }); + } + }); const cli = new RPCClient({ endpoint, identity: 'X', @@ -1438,11 +1447,11 @@ describe('RPCClient', function(){ await cli.connect(); const [c1, c2, c3, c4, c5] = await Promise.allSettled([ - cli.call('Echo', {val: '1'}), - cli.call('Echo', {val: '2'}), - cli.call('Echo', {val: '3'}), - cli.call('Echo', {val: '4'}), - cli.call('Echo', {val: '5'}), + cli.call('Echo', { val: '1' }), + cli.call('Echo', { val: '2' }), + cli.call('Echo', { val: '3' }), + cli.call('Echo', { val: '4' }), + cli.call('Echo', { val: '5' }), ]); assert.equal(c1.status, 'rejected'); @@ -1488,16 +1497,16 @@ describe('RPCClient', function(){ ]); assert.equal(c1.status, 'fulfilled'); - assert.equal(c1.value.val, 1/10); + assert.equal(c1.value.val, 1 / 10); assert.equal(c2.status, 'fulfilled'); - assert.equal(c2.value.val, 0.1/10); + assert.equal(c2.value.val, 0.1 / 10); assert.equal(c3.status, 'fulfilled'); - assert.equal(c3.value.val, 9.1/10); + assert.equal(c3.value.val, 9.1 / 10); assert.equal(c4.status, 'rejected'); assert.ok(c4.reason instanceof RPCOccurenceConstraintViolationError); assert.equal(c4.reason.details.errors[0].keyword, 'multipleOf'); assert.equal(c5.status, 'fulfilled'); - assert.equal(c5.value.val, 57.3/3/10); + assert.equal(c5.value.val, 57.3 / 3 / 10); } finally { await cli.close(); @@ -1508,7 +1517,7 @@ describe('RPCClient', function(){ it("should validate calls using in-built validators", async () => { - const {endpoint, close, server} = await createServer({ + const { endpoint, close, server } = await createServer({ protocols: ['ocpp1.6'], strictMode: true, }); @@ -1524,10 +1533,10 @@ describe('RPCClient', function(){ const [c1, c2, c3] = await Promise.allSettled([ cli.call('Heartbeat', {}), - cli.call('Heartbeat', {a:1}), + cli.call('Heartbeat', { a: 1 }), cli.call('Heartbeat', 1), ]); - + assert.equal(c1.status, 'fulfilled'); assert.ok('currentTime' in c1.value); assert.equal(c2.status, 'rejected'); @@ -1543,15 +1552,17 @@ describe('RPCClient', function(){ }); it("should reject call validation failure with FormationViolation on ocpp1.6", async () => { - - const {endpoint, close, server} = await createServer({ + + const { endpoint, close, server } = await createServer({ protocols: ['ocpp1.6'], strictMode: true, - }, {withClient: cli => { - cli.handle('Heartbeat', () => { - throw createRPCError("FormatViolation"); - }); - }}); + }, { + withClient: cli => { + cli.handle('Heartbeat', () => { + throw createRPCError("FormatViolation"); + }); + } + }); const cli = new RPCClient({ endpoint, identity: 'X', @@ -1565,7 +1576,7 @@ describe('RPCClient', function(){ const [c1] = await Promise.allSettled([ cli.call('Heartbeat', {}), ]); - + assert.equal(c1.status, 'rejected'); assert.equal(c1.reason.rpcErrorCode, 'FormationViolation'); @@ -1578,7 +1589,7 @@ describe('RPCClient', function(){ it('should reject when method is not a string', async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', @@ -1591,7 +1602,7 @@ describe('RPCClient', function(){ await assert.rejects(cli.call([])); await assert.rejects(cli.call({})); - const err = await cli.call(1).catch(e=>e); + const err = await cli.call(1).catch(e => e); assert.ok(err instanceof RPCFrameworkError); } finally { @@ -1603,7 +1614,7 @@ describe('RPCClient', function(){ it('should timeout after client callTimeoutMs option', async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', @@ -1612,7 +1623,7 @@ describe('RPCClient', function(){ try { await cli.connect(); - await assert.rejects(cli.call('Sleep', {ms: 50}), TimeoutError); + await assert.rejects(cli.call('Sleep', { ms: 50 }), TimeoutError); } finally { await cli.close(); close(); @@ -1622,7 +1633,7 @@ describe('RPCClient', function(){ it('should not timeout after call callTimeoutMs option override', async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', @@ -1631,7 +1642,7 @@ describe('RPCClient', function(){ try { await cli.connect(); - await assert.doesNotReject(cli.call('Sleep', {ms: 50}, {callTimeoutMs: 100})); + await assert.doesNotReject(cli.call('Sleep', { ms: 50 }, { callTimeoutMs: 100 })); } finally { await cli.close(); close(); @@ -1641,14 +1652,14 @@ describe('RPCClient', function(){ it('should reject when state === CLOSING with {awaitPending: true}', async () => { - const {endpoint, close, server} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { endpoint, close, server } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { await cli.connect(); - const promSleep1 = cli.call('Sleep', {ms: 20}); - const promClose = cli.close({awaitPending: true}); - const promSleep2 = cli.call('Sleep', {ms: 1000}); + const promSleep1 = cli.call('Sleep', { ms: 20 }); + const promClose = cli.close({ awaitPending: true }); + const promSleep2 = cli.call('Sleep', { ms: 1000 }); assert.equal(cli.state, CLOSING); @@ -1666,13 +1677,13 @@ describe('RPCClient', function(){ it('should reject when state === CLOSING', async () => { - const {endpoint, close, server} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { endpoint, close, server } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { await cli.connect(); cli.close(); - const callPromise = cli.call('Sleep', {ms: 1000}); + const callPromise = cli.call('Sleep', { ms: 1000 }); await assert.rejects(callPromise); assert.equal(cli.state, CLOSING); @@ -1685,11 +1696,11 @@ describe('RPCClient', function(){ it('should reject when state === CLOSED', async () => { - const {endpoint, close, server} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { endpoint, close, server } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { - const callPromise = cli.call('Sleep', {ms: 1000}); + const callPromise = cli.call('Sleep', { ms: 1000 }); await assert.rejects(callPromise); assert.equal(cli.state, CLOSED); @@ -1702,8 +1713,8 @@ describe('RPCClient', function(){ it('should queue when state === CONNECTING', async () => { - const {endpoint, close, server} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { endpoint, close, server } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { cli.connect(); @@ -1723,14 +1734,14 @@ describe('RPCClient', function(){ it('should reject when options.signal aborts', async () => { const reason = "TEST123"; - const {endpoint, close} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { endpoint, close } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { await cli.connect(); const ac = new AbortController(); - - const callProm = cli.call('Sleep', {ms: 5000}, {signal: ac.signal}); + + const callProm = cli.call('Sleep', { ms: 5000 }, { signal: ac.signal }); ac.abort(reason); await assert.rejects(callProm); const abortedReason = await callProm.catch(err => err); @@ -1753,7 +1764,7 @@ describe('RPCClient', function(){ let totalCalls = 0; let mostConcurrent = 0; - const {endpoint, close} = await createServer({}, { + const { endpoint, close } = await createServer({}, { withClient: client => { client.handle('Conc', async () => { totalCalls++; @@ -1772,7 +1783,7 @@ describe('RPCClient', function(){ try { await cli.connect(); - + await Promise.all([ cli.call('Conc'), cli.call('Conc'), @@ -1794,7 +1805,7 @@ describe('RPCClient', function(){ let totalCalls = 0; let mostConcurrent = 0; - const {endpoint, close} = await createServer({}, { + const { endpoint, close } = await createServer({}, { withClient: client => { client.handle('Conc', async () => { totalCalls++; @@ -1813,7 +1824,7 @@ describe('RPCClient', function(){ try { await cli.connect(); - + await Promise.all([ cli.call('Conc'), cli.call('Conc'), @@ -1834,8 +1845,8 @@ describe('RPCClient', function(){ it('should emit badMessage upon a response to a noReply call', async () => { - const echoPayload = {abc: 123}; - const {endpoint, close} = await createServer(); + const echoPayload = { abc: 123 }; + const { endpoint, close } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', @@ -1843,10 +1854,10 @@ describe('RPCClient', function(){ try { await cli.connect(); - - const res = await cli.call('Echo', echoPayload, {noReply: true}); + + const res = await cli.call('Echo', echoPayload, { noReply: true }); const [bad] = await once(cli, 'badMessage'); - + const [mType, mId, mVal] = JSON.parse(bad.buffer.toString('utf8')); assert.equal(mType, 3); @@ -1862,7 +1873,7 @@ describe('RPCClient', function(){ it('should not reject when making unhandled noReply call', async () => { - const {endpoint, close} = await createServer(); + const { endpoint, close } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', @@ -1870,8 +1881,8 @@ describe('RPCClient', function(){ try { await cli.connect(); - - const res = await cli.call('UnrecognisedMethod', 1, {noReply: true}); + + const res = await cli.call('UnrecognisedMethod', 1, { noReply: true }); assert.equal(res, undefined); } finally { @@ -1883,16 +1894,16 @@ describe('RPCClient', function(){ }); - - describe('#_handleDisconnect', function() { + + describe('#_handleDisconnect', function () { it('client should disconnect when server closes', async () => { - const {endpoint, close, server} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X', reconnect: false}); + const { endpoint, close, server } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X', reconnect: false }); await cli.connect(); - close({code: 4050}); + close({ code: 4050 }); const [dc] = await once(cli, 'close'); assert.equal(dc.code, 4050); @@ -1900,20 +1911,20 @@ describe('RPCClient', function(){ it('should reject outbound call in-flight when connection drops', async () => { - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: async (client) => { - await client.close({code: 4001}); + await client.close({ code: 4001 }); } }); - const cli = new RPCClient({endpoint, identity: 'X', reconnect: false}); + const cli = new RPCClient({ endpoint, identity: 'X', reconnect: false }); try { const closePromise = once(cli, 'close'); await cli.connect(); - await assert.rejects(cli.call('Sleep', {ms: 1000})); + await assert.rejects(cli.call('Sleep', { ms: 1000 })); const [closeResult] = await closePromise; assert.equal(closeResult.code, 4001); - + } finally { await cli.close(); close(); @@ -1924,11 +1935,11 @@ describe('RPCClient', function(){ it('should reconnect if using option {reconnect: true} without subprotocols', async () => { let disconnectedOnce = false; - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: async (client) => { if (!disconnectedOnce) { disconnectedOnce = true; - await client.close({code: 4010, reason: "Please reconnect"}); + await client.close({ code: 4010, reason: "Please reconnect" }); } } }); @@ -1942,15 +1953,15 @@ describe('RPCClient', function(){ maxDelay: 2, } }); - + try { await cli.connect(); - const test1 = cli.call('Sleep', {ms: 1000}); + const test1 = cli.call('Sleep', { ms: 1000 }); const [dc1] = await once(cli, 'disconnect'); assert.equal(dc1.code, 4010); await assert.rejects(test1); - + const test2 = await cli.call('Echo', 'TEST2'); assert.equal(test2, 'TEST2'); @@ -1964,13 +1975,13 @@ describe('RPCClient', function(){ it('should reconnect if using option {reconnect: true} with subprotocols', async () => { let disconnectedOnce = false; - const {endpoint, close, server} = await createServer({ + const { endpoint, close, server } = await createServer({ protocols: ['a'], }, { withClient: async (client) => { if (!disconnectedOnce) { disconnectedOnce = true; - await client.close({code: 4010, reason: "Please reconnect"}); + await client.close({ code: 4010, reason: "Please reconnect" }); } } }); @@ -1985,15 +1996,15 @@ describe('RPCClient', function(){ maxDelay: 2, } }); - + try { await cli.connect(); - const test1 = cli.call('Sleep', {ms: 1000}); + const test1 = cli.call('Sleep', { ms: 1000 }); const [dc1] = await once(cli, 'disconnect'); assert.equal(dc1.code, 4010); await assert.rejects(test1); - + const test2 = await cli.call('Echo', 'TEST2'); assert.equal(test2, 'TEST2'); @@ -2007,7 +2018,7 @@ describe('RPCClient', function(){ it('should reconnect exactly {maxReconnects} times before giving up', async () => { const maxReconnects = 3; - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', @@ -2036,15 +2047,17 @@ describe('RPCClient', function(){ protocols: ['b', 'a'], }); - const {endpoint, close, server, port} = await createServer({ + const { endpoint, close, server, port } = await createServer({ protocols: ['a', 'b'], - }, {withClient: client => { - client.handle('Switcheroo', async () => { - await close(); - server2.listen(port); - }); - }}); - + }, { + withClient: client => { + client.handle('Switcheroo', async () => { + await close(); + server2.listen(port); + }); + } + }); + const cli = new RPCClient({ endpoint, @@ -2079,15 +2092,17 @@ describe('RPCClient', function(){ protocols: ['b'], }); - const {endpoint, close, server, port} = await createServer({ + const { endpoint, close, server, port } = await createServer({ protocols: ['a', 'b'], - }, {withClient: client => { - client.handle('Switcheroo', async () => { - await close(); - server2.listen(port); - }); - }}); - + }, { + withClient: client => { + client.handle('Switcheroo', async () => { + await close(); + server2.listen(port); + }); + } + }); + const cli = new RPCClient({ endpoint, @@ -2104,7 +2119,7 @@ describe('RPCClient', function(){ await cli.connect(); const call1Prom = cli.call('Switcheroo'); await assert.rejects(call1Prom); - + await once(cli, 'connecting'); const [dc] = await once(cli, 'close'); assert.equal(dc.code, 1001); @@ -2117,7 +2132,7 @@ describe('RPCClient', function(){ it('should close with code 1001 after failed reconnect', async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', @@ -2129,14 +2144,14 @@ describe('RPCClient', function(){ } }); - let timesOpened= 0; - let timesConnecting= 0; + let timesOpened = 0; + let timesConnecting = 0; cli.on('open', () => timesOpened++); cli.on('connecting', () => timesConnecting++); await cli.connect(); - close({code: 4060}); + close({ code: 4060 }); const [closed] = await once(cli, 'close'); assert.equal(closed.code, 1001); @@ -2148,11 +2163,11 @@ describe('RPCClient', function(){ }); - describe('#_onMessage', function() { + describe('#_onMessage', function () { it('should close connections with code 1002 when receiving too many malformed messages', async () => { - - const {endpoint, close, server} = await createServer({}, { + + const { endpoint, close, server } = await createServer({}, { withClient: async (client) => { client.sendRaw('x'); client.sendRaw('x'); @@ -2179,8 +2194,8 @@ describe('RPCClient', function(){ }); it('should tolerate bad messages within the configured limits', async () => { - - const {endpoint, close, server} = await createServer({}, { + + const { endpoint, close, server } = await createServer({}, { withClient: async (client) => { client.sendRaw('x'); client.sendRaw('x'); @@ -2199,13 +2214,13 @@ describe('RPCClient', function(){ try { let resolve; - let prom = new Promise(r => {resolve = r;}); + let prom = new Promise(r => { resolve = r; }); - cli.handle('Ok', () => {}); + cli.handle('Ok', () => { }); cli.handle('Done', resolve); await cli.connect(); await prom; - cli.close({code: 4060}); + cli.close({ code: 4060 }); const [closed] = await once(cli, 'close'); assert.equal(closed.code, 4060); @@ -2219,21 +2234,21 @@ describe('RPCClient', function(){ }); - describe('#handle', function() { + describe('#handle', function () { it('should only start handling one tick after connection opened', async () => { - - const {endpoint, close, server} = await createServer({protocols: ['b', 'c']}, { + + const { endpoint, close, server } = await createServer({ protocols: ['b', 'c'] }, { withClient: client => { - client.call('Test', {val: 123}); + client.call('Test', { val: 123 }); } }); - const cli = new RPCClient({endpoint, identity: 'X', protocols: ['a','b']}); + const cli = new RPCClient({ endpoint, identity: 'X', protocols: ['a', 'b'] }); try { const res = await new Promise(async (resolve, reject) => { - cli.handle(({method}) => { - reject(Error("Wildcard handler called for method: "+method)); + cli.handle(({ method }) => { + reject(Error("Wildcard handler called for method: " + method)); }); await cli.connect(); @@ -2253,22 +2268,22 @@ describe('RPCClient', function(){ it('should not invoke handler if client closes fast', async () => { - - const {endpoint, close, server} = await createServer({protocols: ['b', 'c']}, { + + const { endpoint, close, server } = await createServer({ protocols: ['b', 'c'] }, { withClient: client => { - client.call('Test', {val: 123}); + client.call('Test', { val: 123 }); } }); - const cli = new RPCClient({endpoint, identity: 'X', protocols: ['a','b']}); + const cli = new RPCClient({ endpoint, identity: 'X', protocols: ['a', 'b'] }); try { const [dc] = await new Promise(async (resolve, reject) => { - cli.handle(({method}) => { - reject(Error("Wildcard handler called for method: "+method)); + cli.handle(({ method }) => { + reject(Error("Wildcard handler called for method: " + method)); }); await cli.connect(); - cli.close({code: 4050}); + cli.close({ code: 4050 }); once(cli, 'close').then(resolve); }); @@ -2282,12 +2297,12 @@ describe('RPCClient', function(){ }); - + it('should not respond to a call that returns NOREPLY symbol', async () => { - const {endpoint, close} = await createServer({}, { + const { endpoint, close } = await createServer({}, { withClient: cli => { - cli.handle('NoReply', ({reply}) => { + cli.handle('NoReply', ({ reply }) => { reply(NOREPLY); }); } @@ -2299,8 +2314,8 @@ describe('RPCClient', function(){ try { await cli.connect(); - - await assert.rejects(cli.call('NoReply', 123, {callTimeoutMs: 50}), TimeoutError); + + await assert.rejects(cli.call('NoReply', 123, { callTimeoutMs: 50 }), TimeoutError); } finally { await cli.close(); @@ -2309,16 +2324,16 @@ describe('RPCClient', function(){ }); - + it('should report the message ID', async () => { - const {endpoint, close} = await createServer({}, { + const { endpoint, close } = await createServer({}, { withClient: cli => { - cli.handle('Manual', async ({messageId}) => { + cli.handle('Manual', async ({ messageId }) => { await cli.sendRaw(JSON.stringify([ 3, messageId, - {messageId} + { messageId } ])); return NOREPLY; }); @@ -2331,11 +2346,11 @@ describe('RPCClient', function(){ try { await cli.connect(); - + const callOutProm = once(cli, 'call'); - const {messageId} = await cli.call('Manual'); + const { messageId } = await cli.call('Manual'); const [callOut] = await callOutProm; - + assert.equal(callOut.outbound, true); assert.equal(callOut.payload[0], 2); assert.equal(callOut.payload[1], messageId); @@ -2348,24 +2363,24 @@ describe('RPCClient', function(){ }); - + it('can reply early before return/throw', async () => { - const {endpoint, close} = await createServer({}, { + const { endpoint, close } = await createServer({}, { withClient: cli => { - cli.handle('ResolveEarly', async ({reply}) => { + cli.handle('ResolveEarly', async ({ reply }) => { reply("early"); return "late"; }); - cli.handle('ResolveBeforeThrow', async ({reply}) => { + cli.handle('ResolveBeforeThrow', async ({ reply }) => { reply("early"); throw Error("late"); }); - cli.handle('RejectEarly', async ({reply}) => { + cli.handle('RejectEarly', async ({ reply }) => { reply(Error("early")); throw Error("late"); }); - cli.handle('RejectBeforeReturn', async ({reply}) => { + cli.handle('RejectBeforeReturn', async ({ reply }) => { reply(Error("early")); return "late"; }); @@ -2380,7 +2395,7 @@ describe('RPCClient', function(){ await cli.connect(); assert.equal(await cli.call('ResolveEarly'), "early"); - const err = await cli.call('RejectEarly').catch(e=>e); + const err = await cli.call('RejectEarly').catch(e => e); assert.equal(err.message, "early"); await assert.rejects(cli.call('RejectBeforeReturn')); assert.equal(await cli.call("ResolveBeforeThrow"), "early"); @@ -2395,20 +2410,22 @@ describe('RPCClient', function(){ }); - describe('#removeHandler', function() { + describe('#removeHandler', function () { it('should prevent wildcard handler from running again', async () => { - + let runs = 0; - const {endpoint, close, server} = await createServer({}, {withClient: cli => { - cli.handle(({method, params}) => { - runs++; - cli.removeHandler(); - return method; - }); - }}); + const { endpoint, close, server } = await createServer({}, { + withClient: cli => { + cli.handle(({ method, params }) => { + runs++; + cli.removeHandler(); + return method; + }); + } + }); - const cli = new RPCClient({endpoint, identity: 'X', reconnect: false}); + const cli = new RPCClient({ endpoint, identity: 'X', reconnect: false }); try { await cli.connect(); @@ -2423,7 +2440,7 @@ describe('RPCClient', function(){ assert.equal(res[0].value, 'Any1'); assert.equal(res[1].reason.rpcErrorCode, 'NotImplemented'); assert.equal(res[2].reason.rpcErrorCode, 'NotImplemented'); - + } finally { await cli.close(); close(); @@ -2434,15 +2451,17 @@ describe('RPCClient', function(){ it('should prevent handled methods from running again', async () => { let runs = 0; - const {endpoint, close, server} = await createServer({}, {withClient: cli => { - cli.handle('Test', ({method, params}) => { - runs++; - cli.removeHandler('Test'); - return runs; - }); - }}); + const { endpoint, close, server } = await createServer({}, { + withClient: cli => { + cli.handle('Test', ({ method, params }) => { + runs++; + cli.removeHandler('Test'); + return runs; + }); + } + }); - const cli = new RPCClient({endpoint, identity: 'X', reconnect: false}); + const cli = new RPCClient({ endpoint, identity: 'X', reconnect: false }); try { await cli.connect(); @@ -2457,7 +2476,7 @@ describe('RPCClient', function(){ assert.equal(res[0].value, 1); assert.equal(res[1].reason.rpcErrorCode, 'NotImplemented'); assert.equal(res[2].value, 'TEST'); - + } finally { await cli.close(); close(); @@ -2467,24 +2486,26 @@ describe('RPCClient', function(){ }); - describe('#removeAllHandlers', function() { + describe('#removeAllHandlers', function () { it('should prevent all handled methods from running again', async () => { let runs = 0; - const {endpoint, close, server} = await createServer({}, {withClient: cli => { - cli.handle('Test', ({method, params}) => { - runs++; - cli.removeAllHandlers(); - return runs; - }); + const { endpoint, close, server } = await createServer({}, { + withClient: cli => { + cli.handle('Test', ({ method, params }) => { + runs++; + cli.removeAllHandlers(); + return runs; + }); - cli.handle(({method, params}) => { - throw Error('GenericError'); - }); - }}); + cli.handle(({ method, params }) => { + throw Error('GenericError'); + }); + } + }); - const cli = new RPCClient({endpoint, identity: 'X', reconnect: false}); + const cli = new RPCClient({ endpoint, identity: 'X', reconnect: false }); try { await cli.connect(); @@ -2501,7 +2522,7 @@ describe('RPCClient', function(){ assert.equal(res[1].reason.rpcErrorCode, 'NotImplemented'); assert.equal(res[2].reason.rpcErrorCode, 'NotImplemented'); assert.equal(res[3].reason.rpcErrorCode, 'NotImplemented'); - + } finally { await cli.close(); close(); @@ -2511,13 +2532,13 @@ describe('RPCClient', function(){ }); - describe('#_keepAlive', function() { + describe('#_keepAlive', function () { it('should ping at the chosen interval', async () => { - + const pingIntervalMs = 40; - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', @@ -2529,7 +2550,7 @@ describe('RPCClient', function(){ const start = Date.now(); await once(cli, 'ping'); const fin = Date.now() - start; - const {code} = await cli.close({code: 4050}); + const { code } = await cli.close({ code: 4050 }); assert.ok(fin >= pingIntervalMs); assert.ok(fin <= pingIntervalMs * 2); assert.equal(code, 4050); @@ -2541,8 +2562,8 @@ describe('RPCClient', function(){ }); it('should force close client if no pong between pings', async () => { - - const {endpoint, close, server} = await createServer({}, { + + const { endpoint, close, server } = await createServer({}, { withClient: client => { // a hack to prevent WebSocket from responding to pings client._ws._receiver.removeAllListeners('ping'); @@ -2568,9 +2589,9 @@ describe('RPCClient', function(){ }); it('should process pings normally after keepAlive forces a reconnect', async () => { - + let doneOnce = false; - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: client => { if (!doneOnce) { doneOnce = true; @@ -2607,9 +2628,9 @@ describe('RPCClient', function(){ it('should not auto-ping server if other activity received with option deferPingsOnActivity', async () => { - + let pings = 0; - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: async (client) => { // send some rapid activity from the server for (let i = 0; i < 4; i++) { @@ -2626,12 +2647,12 @@ describe('RPCClient', function(){ deferPingsOnActivity: true, pingIntervalMs: 50 }); - cli.handle('Echo', async ({params}) => { + cli.handle('Echo', async ({ params }) => { return params; }); // count how many times we ping the server - cli.on('ping', () => {++pings;}); + cli.on('ping', () => { ++pings; }); try { await cli.connect(); @@ -2645,9 +2666,9 @@ describe('RPCClient', function(){ }); it('should auto-ping server even if other activity received without option deferPingsOnActivity', async () => { - + let pings = 0; - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: async (client) => { // send some rapid activity from the server for (let i = 0; i < 4; i++) { @@ -2664,12 +2685,12 @@ describe('RPCClient', function(){ deferPingsOnActivity: false, pingIntervalMs: 50 }); - cli.handle('Echo', async ({params}) => { + cli.handle('Echo', async ({ params }) => { return params; }); // count how many times we ping the server - cli.on('ping', () => {++pings;}); + cli.on('ping', () => { ++pings; }); try { await cli.connect(); @@ -2684,9 +2705,9 @@ describe('RPCClient', function(){ it('should not auto-ping server if ping received with option deferPingsOnActivity', async () => { - + let pings = 0; - const {endpoint, close, server} = await createServer({ + const { endpoint, close, server } = await createServer({ pingIntervalMs: 25, deferPingsOnActivity: false, }, { @@ -2705,7 +2726,7 @@ describe('RPCClient', function(){ }); // count how many times we ping the server - cli.on('ping', () => {++pings;}); + cli.on('ping', () => { ++pings; }); try { await cli.connect(); @@ -2719,9 +2740,9 @@ describe('RPCClient', function(){ }); it('should auto-ping server even if ping received without option deferPingsOnActivity', async () => { - + let pings = 0; - const {endpoint, close, server} = await createServer({ + const { endpoint, close, server } = await createServer({ pingIntervalMs: 25, deferPingsOnActivity: false, }, { @@ -2740,7 +2761,7 @@ describe('RPCClient', function(){ }); // count how many times we ping the server - cli.on('ping', () => {++pings;}); + cli.on('ping', () => { ++pings; }); try { await cli.connect(); @@ -2756,11 +2777,11 @@ describe('RPCClient', function(){ }); - describe('#sendRaw', function() { + describe('#sendRaw', function () { it("should cause a 'badMessage' event when used incorrectly", async () => { - - const {endpoint, close, server} = await createServer({}, { + + const { endpoint, close, server } = await createServer({}, { withClient: cli => { cli.sendRaw('x'); } @@ -2779,7 +2800,7 @@ describe('RPCClient', function(){ assert.equal(bad.response[0], 4); assert.equal(bad.response[1], '-1'); assert.equal(bad.response[2], 'RpcFrameworkError'); - + } finally { await cli.close(); close(); @@ -2789,11 +2810,11 @@ describe('RPCClient', function(){ }); - describe('#reconfigure', function() { + describe('#reconfigure', function () { it("should not change identity on reconnect", async () => { - - const {endpoint, close, server} = await createServer({}, { + + const { endpoint, close, server } = await createServer({}, { withClient: cli => { cli.handle('Drop', () => cli.close()); cli.handle('GetID', () => cli.identity); @@ -2812,9 +2833,9 @@ describe('RPCClient', function(){ await cli.connect(); assert.equal(await cli.call('GetID'), 'X'); - cli.reconfigure({identity: 'Y'}); - await cli.call('Drop').catch(()=>{}); - + cli.reconfigure({ identity: 'Y' }); + await cli.call('Drop').catch(() => { }); + assert.equal(await cli.call('GetID'), 'X'); } finally { @@ -2826,7 +2847,7 @@ describe('RPCClient', function(){ it("should change identity on explicit close and connect", async () => { - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: cli => { cli.handle('Drop', () => cli.close()); cli.handle('GetID', () => cli.identity); @@ -2841,10 +2862,10 @@ describe('RPCClient', function(){ await cli.connect(); assert.equal(await cli.call('GetID'), 'X'); - cli.reconfigure({identity: 'Y'}); + cli.reconfigure({ identity: 'Y' }); await cli.close(); await cli.connect(); - + assert.equal(await cli.call('GetID'), 'Y'); } finally { @@ -2855,8 +2876,8 @@ describe('RPCClient', function(){ }); it("should be able to adjust queue concurrency", async () => { - - const {endpoint, close, server} = await createServer({}, { + + const { endpoint, close, server } = await createServer({}, { withClient: cli => { let processing = 0; cli.handle('Max', async () => { @@ -2874,11 +2895,11 @@ describe('RPCClient', function(){ try { await cli.connect(); - - const arr = [1,2,3,4,5,6]; + + const arr = [1, 2, 3, 4, 5, 6]; const cc1 = await Promise.all(arr.map(x => cli.call('Max'))); - cli.reconfigure({callConcurrency: 3}); + cli.reconfigure({ callConcurrency: 3 }); const cc3 = await Promise.all(arr.map(x => cli.call('Max'))); assert.equal(Math.max(...cc1), 1); @@ -2892,8 +2913,8 @@ describe('RPCClient', function(){ }); it("should be able to adjust backoff configuration", async () => { - - const {endpoint, close, server} = await createServer({}, { + + const { endpoint, close, server } = await createServer({}, { withClient: cli => { cli.handle('Drop', () => cli.close()); } @@ -2910,7 +2931,7 @@ describe('RPCClient', function(){ try { await cli.connect(); - await cli.call('Drop').catch(() => {}); + await cli.call('Drop').catch(() => { }); const t1 = Date.now(); await once(cli, 'open'); const r1 = Date.now() - t1; @@ -2922,11 +2943,11 @@ describe('RPCClient', function(){ } }); - await cli.call('Drop').catch(() => {}); + await cli.call('Drop').catch(() => { }); const t2 = Date.now(); await once(cli, 'open'); const r2 = Date.now() - t2; - + assert.ok(r1 < 20); assert.ok(r2 > 20); @@ -2938,8 +2959,8 @@ describe('RPCClient', function(){ }); it("should be able to adjust ping interval", async () => { - - const {endpoint, close, server} = await createServer(); + + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', @@ -2947,14 +2968,14 @@ describe('RPCClient', function(){ }); try { - + await cli.connect(); const t1 = Date.now(); await once(cli, 'ping'); const r1 = Date.now() - t1; - - cli.reconfigure({pingIntervalMs: 10}); + + cli.reconfigure({ pingIntervalMs: 10 }); const t2 = Date.now(); await once(cli, 'ping'); diff --git a/test/server-client.js b/test/server-client.ts similarity index 82% rename from test/server-client.js rename to test/server-client.ts index 5d96322..c328b5e 100644 --- a/test/server-client.js +++ b/test/server-client.ts @@ -1,7 +1,8 @@ +// @ts-nocheck const assert = require('assert/strict'); const { once } = require('events'); const RPCClient = require("../lib/client"); -const RPCServer = require("../lib/server"); +import RPCServer from "../lib/server"; const { setTimeout } = require('timers/promises'); const { createValidator } = require('../lib/validator'); @@ -34,7 +35,7 @@ function getEchoValidator() { ]); } -describe('RPCServerClient', function(){ +describe('RPCServerClient', function () { this.timeout(500); async function createServer(options = {}, extra = {}) { @@ -44,14 +45,14 @@ describe('RPCServerClient', function(){ const endpoint = `ws://localhost:${port}`; const close = (...args) => server.close(...args); server.on('client', client => { - client.handle('Echo', async ({params}) => { + client.handle('Echo', async ({ params }) => { return params; }); - client.handle('Sleep', async ({params, signal}) => { - await setTimeout(params.ms, null, {signal}); + client.handle('Sleep', async ({ params, signal }) => { + await setTimeout(params.ms, null, { signal }); return `Waited ${params.ms}ms`; }); - client.handle('Reject', async ({params}) => { + client.handle('Reject', async ({ params }) => { const err = Error("Rejecting"); Object.assign(err, params); throw err; @@ -60,15 +61,15 @@ describe('RPCServerClient', function(){ extra.withClient(client); } }); - return {server, httpServer, port, endpoint, close}; + return { server, httpServer, port, endpoint, close }; } - describe('#connect', function(){ + describe('#connect', function () { it('should throw', async () => { let servCli; - const {endpoint, close} = await createServer({}, { + const { endpoint, close } = await createServer({}, { withClient: cli => { servCli = cli; } @@ -91,16 +92,16 @@ describe('RPCServerClient', function(){ it('should inherit server options', async () => { const inheritableOptions = { - callTimeoutMs: Math.floor(Math.random()*99999), - pingIntervalMs: Math.floor(Math.random()*99999), + callTimeoutMs: Math.floor(Math.random() * 99999), + pingIntervalMs: Math.floor(Math.random() * 99999), deferPingsOnActivity: true, respondWithDetailedErrors: true, - callConcurrency: Math.floor(Math.random()*99999), + callConcurrency: Math.floor(Math.random() * 99999), strictMode: true, strictModeValidators: [ getEchoValidator(), ], - maxBadMessages: Math.floor(Math.random()*99999), + maxBadMessages: Math.floor(Math.random() * 99999), }; const server = new RPCServer({ @@ -123,7 +124,7 @@ describe('RPCServerClient', function(){ resolve(); }); }); - + const cli = new RPCClient({ endpoint, identity: 'X', diff --git a/test/server.js b/test/server.ts similarity index 78% rename from test/server.js rename to test/server.ts index ce642fc..657c362 100644 --- a/test/server.js +++ b/test/server.ts @@ -1,14 +1,15 @@ +// @ts-nocheck const assert = require('assert/strict'); const http = require('http'); const { once } = require('events'); const RPCClient = require("../lib/client"); const { TimeoutError, UnexpectedHttpResponse, WebsocketUpgradeError } = require('../lib/errors'); -const RPCServer = require("../lib/server"); +import RPCServer from "../lib/server"; const { setTimeout } = require('timers/promises'); const { createValidator } = require('../lib/validator'); const { abortHandshake } = require('../lib/ws-util'); -describe('RPCServer', function(){ +describe('RPCServer', function () { this.timeout(500); async function createServer(options = {}, extra = {}) { @@ -18,14 +19,14 @@ describe('RPCServer', function(){ const endpoint = `ws://localhost:${port}`; const close = (...args) => server.close(...args); server.on('client', client => { - client.handle('Echo', async ({params}) => { + client.handle('Echo', async ({ params }) => { return params; }); - client.handle('Sleep', async ({params, signal}) => { - await setTimeout(params.ms, null, {signal}); + client.handle('Sleep', async ({ params, signal }) => { + await setTimeout(params.ms, null, { signal }); return `Waited ${params.ms}ms`; }); - client.handle('Reject', async ({params}) => { + client.handle('Reject', async ({ params }) => { const err = Error("Rejecting"); Object.assign(err, params); throw err; @@ -34,7 +35,7 @@ describe('RPCServer', function(){ extra.withClient(client); } }); - return {server, httpServer, port, endpoint, close}; + return { server, httpServer, port, endpoint, close }; } @@ -67,7 +68,7 @@ describe('RPCServer', function(){ ]); } - describe('#constructor', function(){ + describe('#constructor', function () { it('should throw if strictMode = true and not all protocol schemas found', async () => { @@ -120,15 +121,15 @@ describe('RPCServer', function(){ }); - describe('events', function(){ + describe('events', function () { it('should emit "client" when client connects', async () => { - const {endpoint, close, server} = await createServer(); - const cli = new RPCClient({endpoint, identity: 'X'}); + const { endpoint, close, server } = await createServer(); + const cli = new RPCClient({ endpoint, identity: 'X' }); try { - + const clientProm = once(server, 'client'); await cli.connect(); const [client] = await clientProm; @@ -144,11 +145,11 @@ describe('RPCServer', function(){ it('should correctly decode the client identity', async () => { const identity = 'RPC/ /123'; - const {endpoint, close, server} = await createServer(); - const cli = new RPCClient({endpoint, identity}); + const { endpoint, close, server } = await createServer(); + const cli = new RPCClient({ endpoint, identity }); try { - + const clientProm = once(server, 'client'); await cli.connect(); const [client] = await clientProm; @@ -163,12 +164,12 @@ describe('RPCServer', function(){ }); - - describe('#auth', function(){ + + describe('#auth', function () { it("should refuse client with error 400 when subprotocol incorrectly forced", async () => { - const {endpoint, close, server} = await createServer({protocols: ['a', 'b']}); + const { endpoint, close, server } = await createServer({ protocols: ['a', 'b'] }); server.auth((accept, reject, handshake) => { accept({}, 'b'); @@ -182,7 +183,7 @@ describe('RPCServer', function(){ try { - const err = await cli.connect().catch(e=>e); + const err = await cli.connect().catch(e => e); assert.equal(err.code, 400); } finally { @@ -193,10 +194,10 @@ describe('RPCServer', function(){ it("should not throw on double-accept", async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); let allOk; - let waitOk = new Promise(r => {allOk = r;}); + let waitOk = new Promise(r => { allOk = r; }); server.auth((accept, reject, handshake) => { accept(); @@ -221,10 +222,10 @@ describe('RPCServer', function(){ it("should not throw on double-reject", async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); let allOk; - let waitOk = new Promise(r => {allOk = r;}); + let waitOk = new Promise(r => { allOk = r; }); server.auth((accept, reject, handshake) => { reject(); @@ -238,7 +239,7 @@ describe('RPCServer', function(){ }); try { - await assert.rejects(cli.connect(), {code: 404}); + await assert.rejects(cli.connect(), { code: 404 }); await waitOk; } finally { await cli.close(); @@ -249,10 +250,10 @@ describe('RPCServer', function(){ it("should not throw on reject-after-accept", async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); let allOk; - let waitOk = new Promise(r => {allOk = r;}); + let waitOk = new Promise(r => { allOk = r; }); server.auth((accept, reject, handshake) => { accept(); @@ -277,10 +278,10 @@ describe('RPCServer', function(){ it("should not throw on accept-after-reject", async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); let allOk; - let waitOk = new Promise(r => {allOk = r;}); + let waitOk = new Promise(r => { allOk = r; }); server.auth((accept, reject, handshake) => { reject(); @@ -294,7 +295,7 @@ describe('RPCServer', function(){ }); try { - await assert.rejects(cli.connect(), {code: 404}); + await assert.rejects(cli.connect(), { code: 404 }); await waitOk; } finally { await cli.close(); @@ -307,7 +308,7 @@ describe('RPCServer', function(){ const identity = 'RPC/ /123'; const extraPath = '/extra/long/path'; - const {endpoint, close, server} = await createServer({protocols: ['a', 'b']}); + const { endpoint, close, server } = await createServer({ protocols: ['a', 'b'] }); const cli = new RPCClient({ endpoint: endpoint + extraPath, identity, @@ -315,7 +316,7 @@ describe('RPCServer', function(){ }); try { - + let hs; server.auth((accept, reject, handshake) => { hs = handshake; @@ -344,24 +345,24 @@ describe('RPCServer', function(){ it('should correctly parse endpoints with double slashes and dots', async () => { const identity = 'XX'; - const {endpoint, close, server} = await createServer({}); + const { endpoint, close, server } = await createServer({}); try { const endpointPaths = [ - {append: '/ocpp', expect: '/ocpp'}, - {append: '//', expect: '//'}, - {append: '//ocpp', expect: '//ocpp'}, - {append: '/ocpp/', expect: '/ocpp/'}, - {append: '/', expect: '/'}, - {append: '///', expect: '///'}, - {append: '/../', expect: '/'}, - {append: '//../', expect: '/'}, - {append: '/ocpp/..', expect: '/'}, - {append: '/ocpp/../', expect: '/'}, - {append: '//ocpp/../', expect: '//'}, - {append: '', expect: '/'}, + { append: '/ocpp', expect: '/ocpp' }, + { append: '//', expect: '//' }, + { append: '//ocpp', expect: '//ocpp' }, + { append: '/ocpp/', expect: '/ocpp/' }, + { append: '/', expect: '/' }, + { append: '///', expect: '///' }, + { append: '/../', expect: '/' }, + { append: '//../', expect: '/' }, + { append: '/ocpp/..', expect: '/' }, + { append: '/ocpp/../', expect: '/' }, + { append: '//ocpp/../', expect: '//' }, + { append: '', expect: '/' }, ]; - + for (const endpointPath of endpointPaths) { const fullEndpoint = endpoint + endpointPath.append; @@ -377,7 +378,7 @@ describe('RPCServer', function(){ }); await cli.connect(); - await cli.close({force: true}); + await cli.close({ force: true }); assert.equal(hs.endpoint, endpointPath.expect); assert.equal(hs.identity, identity); @@ -395,14 +396,14 @@ describe('RPCServer', function(){ const extraPath = '/extra/path'; const identity = 'X'; const proto = 'a'; - const sessionData = {a: 123, b: {c: 456}}; + const sessionData = { a: 123, b: { c: 456 } }; - const {endpoint, close, server} = await createServer({protocols: ['x', 'b', proto]}, { + const { endpoint, close, server } = await createServer({ protocols: ['x', 'b', proto] }, { withClient: client => { serverClient = client; } }); - + server.auth((accept, reject, handshake) => { accept(sessionData, proto); }); @@ -414,7 +415,7 @@ describe('RPCServer', function(){ }); try { - + await cli.connect(); assert.deepEqual(serverClient.session, sessionData); assert.equal(serverClient.protocol, proto); @@ -429,13 +430,13 @@ describe('RPCServer', function(){ it('should disconnect client if auth failed', async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); server.auth((accept, reject) => { reject(500); }); - const cli = new RPCClient({endpoint, identity: 'X'}); - - const err = await cli.connect().catch(e=>e); + const cli = new RPCClient({ endpoint, identity: 'X' }); + + const err = await cli.connect().catch(e => e); assert.ok(err instanceof UnexpectedHttpResponse); assert.equal(err.code, 500); @@ -445,13 +446,13 @@ describe('RPCServer', function(){ it("should disconnect client if server closes during auth", async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); server.auth((accept, reject) => { close(); accept(); }); - const cli = new RPCClient({endpoint, identity: 'X', reconnect: false}); - + const cli = new RPCClient({ endpoint, identity: 'X', reconnect: false }); + const closeProm = once(cli, 'close'); await cli.connect(); @@ -462,20 +463,22 @@ describe('RPCServer', function(){ }); - + it('should recognise passwords with colons', async () => { - + const password = 'hun:ter:2'; - const {endpoint, close, server} = await createServer({}, {withClient: cli => { - cli.handle('GetPassword', () => { - return cli.session.pwd; - }); - }}); + const { endpoint, close, server } = await createServer({}, { + withClient: cli => { + cli.handle('GetPassword', () => { + return cli.session.pwd; + }); + } + }); server.auth((accept, reject, handshake) => { - accept({pwd: handshake.password.toString('utf8')}); + accept({ pwd: handshake.password.toString('utf8') }); }); const cli = new RPCClient({ @@ -496,14 +499,14 @@ describe('RPCServer', function(){ }); it('should not get confused with identities and passwords containing colons', async () => { - + const identity = 'a:colonified:ident'; const password = 'a:colonified:p4ss'; - + let recIdent; let recPass; - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); server.auth((accept, reject, handshake) => { recIdent = handshake.identity; recPass = handshake.password; @@ -528,11 +531,11 @@ describe('RPCServer', function(){ }); it('should recognise empty passwords', async () => { - + const password = ''; let recPass; - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); server.auth((accept, reject, handshake) => { recPass = handshake.password; accept(); @@ -555,10 +558,10 @@ describe('RPCServer', function(){ }); it('should provide undefined password if no authorization header sent', async () => { - + let recPass; - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); server.auth((accept, reject, handshake) => { recPass = handshake.password; accept(); @@ -580,10 +583,10 @@ describe('RPCServer', function(){ }); it('should provide undefined password when identity mismatches username', async () => { - + let recPass; - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); server.auth((accept, reject, handshake) => { recPass = handshake.password; accept(); @@ -608,10 +611,10 @@ describe('RPCServer', function(){ }); it('should provide undefined password on bad authorization header', async () => { - + let recPass; - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); server.auth((accept, reject, handshake) => { recPass = handshake.password; accept(); @@ -634,23 +637,25 @@ describe('RPCServer', function(){ close(); } }); - + it('should recognise binary passwords', async () => { - + const password = Buffer.from([ - 0,1,2,3,4,5,6,7,8,9, - 65,66,67,68,69, - 251,252,253,254,255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 65, 66, 67, 68, 69, + 251, 252, 253, 254, 255, ]); - const {endpoint, close, server} = await createServer({}, {withClient: cli => { - cli.handle('GetPassword', () => { - return cli.session.pwd; - }); - }}); + const { endpoint, close, server } = await createServer({}, { + withClient: cli => { + cli.handle('GetPassword', () => { + return cli.session.pwd; + }); + } + }); server.auth((accept, reject, handshake) => { - accept({pwd: handshake.password.toString('hex')}); + accept({ pwd: handshake.password.toString('hex') }); }); const cli = new RPCClient({ @@ -672,15 +677,15 @@ describe('RPCServer', function(){ }); - - describe('#close', function(){ + + describe('#close', function () { it('should not allow new connections after close (before clients kicked)', async () => { let callReceived; - const callReceivedPromise = new Promise(r => {callReceived = r;}); + const callReceivedPromise = new Promise(r => { callReceived = r; }); - const {endpoint, close, server} = await createServer({}, { + const { endpoint, close, server } = await createServer({}, { withClient: client => { client.handle('Test', async () => { callReceived(); @@ -701,11 +706,11 @@ describe('RPCServer', function(){ }); try { - + await cli1.connect(); const callP = cli1.call('Test'); await callReceivedPromise; - close({awaitPending: true}); + close({ awaitPending: true }); const [callResult, connResult] = await Promise.allSettled([ callP, cli2.connect() @@ -723,8 +728,8 @@ describe('RPCServer', function(){ }); }); - - describe('#listen', function(){ + + describe('#listen', function () { it('should attach to an existing http server', async () => { @@ -738,10 +743,10 @@ describe('RPCServer', function(){ const httpServer = http.createServer({}, (req, res) => res.end()); httpServer.on('upgrade', server.handleUpgrade); await new Promise((resolve, reject) => { - httpServer.listen({port: 0}, err => err ? reject(err) : resolve()); + httpServer.listen({ port: 0 }, err => err ? reject(err) : resolve()); }); - const endpoint = 'ws://localhost:'+httpServer.address().port; + const endpoint = 'ws://localhost:' + httpServer.address().port; const cli1 = new RPCClient({ endpoint, @@ -759,7 +764,7 @@ describe('RPCServer', function(){ cli2.connect(), ]); await cli1.close(); // httpServer.close() won't kick clients - + assert.equal(callResult.status, 'fulfilled'); assert.equal(callResult.value, 123); assert.equal(connResult.status, 'rejected'); @@ -771,12 +776,12 @@ describe('RPCServer', function(){ const server = new RPCServer(); const s1 = await server.listen(); - const e1 = 'ws://localhost:'+s1.address().port; + const e1 = 'ws://localhost:' + s1.address().port; const s2 = await server.listen(); - const e2 = 'ws://localhost:'+s2.address().port; + const e2 = 'ws://localhost:' + s2.address().port; - const cli1 = new RPCClient({endpoint: e1, identity: '1', reconnect: false}); - const cli2 = new RPCClient({endpoint: e2, identity: '2', reconnect: false}); + const cli1 = new RPCClient({ endpoint: e1, identity: '1', reconnect: false }); + const cli2 = new RPCClient({ endpoint: e2, identity: '2', reconnect: false }); await cli1.connect(); await cli2.connect(); @@ -786,7 +791,7 @@ describe('RPCServer', function(){ once(cli2, 'close'), ]); - server.close({code: 4050}); + server.close({ code: 4050 }); await droppedProm; }); @@ -795,19 +800,19 @@ describe('RPCServer', function(){ const ac = new AbortController(); const server = new RPCServer(); - const httpServer = await server.listen(undefined, undefined, {signal: ac.signal}); + const httpServer = await server.listen(undefined, undefined, { signal: ac.signal }); const port = httpServer.address().port; - const endpoint = 'ws://localhost:'+port; + const endpoint = 'ws://localhost:' + port; + + const cli = new RPCClient({ endpoint, identity: 'X', reconnect: false }); - const cli = new RPCClient({endpoint, identity: 'X', reconnect: false}); - await cli.connect(); - const {code} = await cli.close({code: 4080}); + const { code } = await cli.close({ code: 4080 }); assert.equal(code, 4080); ac.abort(); - const err = await cli.connect().catch(e=>e); + const err = await cli.connect().catch(e => e); assert.equal(err.code, 'ECONNREFUSED'); @@ -816,12 +821,12 @@ describe('RPCServer', function(){ it('should automatically ping clients', async () => { - + const pingIntervalMs = 40; let pingResolve; - let pingPromise = new Promise(r => {pingResolve = r;}) + let pingPromise = new Promise(r => { pingResolve = r; }) - const {endpoint, close, server} = await createServer({ + const { endpoint, close, server } = await createServer({ pingIntervalMs, }, { withClient: async (client) => { @@ -839,11 +844,11 @@ describe('RPCServer', function(){ await cli.connect(); const ping = await pingPromise; const fin = Date.now() - start; - + assert.ok(fin >= pingIntervalMs); assert.ok(fin <= pingIntervalMs * 2); assert.ok(ping.rtt <= pingIntervalMs * 2); - + } finally { await cli.close(); close(); @@ -851,19 +856,19 @@ describe('RPCServer', function(){ }); it('should reject non-websocket requests with a 404', async () => { - - const {port, close, server} = await createServer(); + + const { port, close, server } = await createServer(); try { - - const req = http.request('http://localhost:'+port); + + const req = http.request('http://localhost:' + port); req.end(); const [res] = await once(req, 'response'); assert.equal(res.statusCode, 404); - + } catch (err) { - console.log({err}); + console.log({ err }); } finally { close(); } @@ -871,18 +876,18 @@ describe('RPCServer', function(){ }); - describe('#handleUpgrade', function() { + describe('#handleUpgrade', function () { it("should not throw if abortHandshake() called after socket already destroyed", async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', }); let completeAuth; - let authCompleted = new Promise(r => {completeAuth = r;}) + let authCompleted = new Promise(r => { completeAuth = r; }) server.auth(async (accept, reject, handshake) => { reject(400); @@ -892,9 +897,9 @@ describe('RPCServer', function(){ try { const conn = cli.connect(); - await assert.rejects(conn, {message: "Bad Request"}); + await assert.rejects(conn, { message: "Bad Request" }); await authCompleted; - + } finally { await cli.close(); close(); @@ -902,16 +907,16 @@ describe('RPCServer', function(){ }); - + it("should abort handshake if server not open", async () => { const server = new RPCServer(); - + let abortEvent; server.on('upgradeAborted', event => { abortEvent = event; }); - + let authed = false; server.auth((accept) => { // shouldn't get this far @@ -920,16 +925,16 @@ describe('RPCServer', function(){ }); let onUpgrade; - let upgradeProm = new Promise(r => {onUpgrade = r;}); + let upgradeProm = new Promise(r => { onUpgrade = r; }); const httpServer = http.createServer({}, (req, res) => res.end()); httpServer.on('upgrade', (...args) => onUpgrade(args)); await new Promise((resolve, reject) => { - httpServer.listen({port: 0}, err => err ? reject(err) : resolve()); + httpServer.listen({ port: 0 }, err => err ? reject(err) : resolve()); }); - const endpoint = 'ws://localhost:'+httpServer.address().port; + const endpoint = 'ws://localhost:' + httpServer.address().port; const cli = new RPCClient({ endpoint, @@ -943,13 +948,13 @@ describe('RPCServer', function(){ assert.equal(authed, false); assert.equal(abortEvent.error.code, 500); httpServer.close(); - + }); - + it("should abort handshake for non-websocket upgrades", async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); let abortEvent; server.on('upgradeAborted', event => { @@ -965,7 +970,7 @@ describe('RPCServer', function(){ try { - const req = http.request(endpoint.replace(/^ws/,'http') + '/X', { + const req = http.request(endpoint.replace(/^ws/, 'http') + '/X', { headers: { connection: 'Upgrade', upgrade: '_UNKNOWN_', @@ -980,17 +985,17 @@ describe('RPCServer', function(){ assert.equal(authed, false); assert.ok(abortEvent.error instanceof WebsocketUpgradeError); assert.equal(abortEvent.request.headers['user-agent'], 'test/0'); - + } finally { close(); } }); - + it("should emit upgradeAborted event on auth reject", async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); let abortEvent; server.on('upgradeAborted', event => { @@ -1009,10 +1014,10 @@ describe('RPCServer', function(){ }); await assert.rejects(cli.connect()); - + assert.ok(abortEvent.error instanceof WebsocketUpgradeError); assert.equal(abortEvent.error.code, 499); - + } finally { close(); } @@ -1021,24 +1026,24 @@ describe('RPCServer', function(){ it("should abort auth on upgrade error", async () => { - const {endpoint, close, server} = await createServer(); + const { endpoint, close, server } = await createServer(); const cli = new RPCClient({ endpoint, identity: 'X', }); let completeAuth; - let authCompleted = new Promise(r => {completeAuth = r;}) + let authCompleted = new Promise(r => { completeAuth = r; }) server.auth(async (accept, reject, handshake, signal) => { const abortProm = once(signal, 'abort'); - await cli.close({force: true, awaitPending: false}); + await cli.close({ force: true, awaitPending: false }); await abortProm; completeAuth(); }); try { - const connErr = await cli.connect().catch(e=>e); + const connErr = await cli.connect().catch(e => e); await authCompleted; assert.ok(connErr instanceof Error); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..41ce82f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,93 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "resolveJsonModule": true, /* Enable importing .json files */ + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + /* JavaScript Support */ + "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": false, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} \ No newline at end of file