From 51aa7ae1f5718bd27a12373074b72764d41f4c86 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 5 May 2022 21:25:28 +0100 Subject: [PATCH 01/24] - Returned type improvements. - Start migrating to base rest client. - Remove deprecated methods. - Run linter. - Deprecate shared endpoints for readibility. All methods are replicated within each client (there's not much duplication). - Expand test coverage for public inverse endpoints. --- package-lock.json | 7581 ++++++++++++++++++++++++++++++++- src/inverse-client.ts | 180 +- src/inverse-futures-client.ts | 211 +- src/linear-client.ts | 115 +- src/shared-endpoints.ts | 111 - src/spot-client.ts | 49 +- src/types/shared.ts | 14 +- src/util/BaseRestClient.ts | 75 +- src/util/requestUtils.ts | 24 +- src/websocket-client.ts | 360 +- test/inverse/public.test.ts | 100 +- 11 files changed, 8447 insertions(+), 373 deletions(-) delete mode 100644 src/shared-endpoints.ts diff --git a/package-lock.json b/package-lock.json index 073acc0..3249949 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,7567 @@ { "name": "bybit-api", - "version": "2.1.9", - "lockfileVersion": 1, + "version": "2.1.10", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "bybit-api", + "version": "2.1.10", + "license": "MIT", + "dependencies": { + "axios": "^0.21.0", + "isomorphic-ws": "^4.0.1", + "ws": "^7.4.0" + }, + "devDependencies": { + "@types/jest": "^26.0.23", + "@types/node": "^14.14.7", + "eslint": "^7.10.0", + "jest": "^27.0.4", + "source-map-loader": "^2.0.0", + "ts-jest": "^27.0.3", + "ts-loader": "^8.0.11", + "typescript": "^4.0.5", + "webpack": "^5.4.0", + "webpack-bundle-analyzer": "^4.1.0", + "webpack-cli": "^4.2.0" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/tiagosiebler" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz", + "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.6.tgz", + "integrity": "sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.5", + "@babel/helper-compilation-targets": "^7.14.5", + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helpers": "^7.14.6", + "@babel/parser": "^7.14.6", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/core/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz", + "integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.14.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", + "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", + "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", + "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", + "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz", + "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", + "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.5.tgz", + "integrity": "sha512-iXpX4KW8LVODuAieD7MzhNjmM6dzYY5tfRqT+R9HDXWl0jPn/djKmA+G9s/2C2T9zggw5tK1QNqZ70USfedOwA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-simple-access": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", + "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", + "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz", + "integrity": "sha512-nfBN9xvmCt6nrMZjfhkl7i0oTV3yxR4/FztsbOASyTvVcoYd0TRHh7eMLdlEcCqobydC0LAF3LtC92Iwxo0wyw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", + "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz", + "integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz", + "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", + "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.7.tgz", + "integrity": "sha512-9vDr5NzHu27wgwejuKL7kIOm4bwEtaPQ4Z6cpCmjSuaRqpH/7xc4qcGEscwMqlkwgcXl6MvqoAjZkQ24uSdIZQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.14.7", + "@babel/types": "^7.14.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", + "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types/node_modules/@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz", + "integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", + "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "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", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.0.2.tgz", + "integrity": "sha512-/zYigssuHLImGeMAACkjI4VLAiiJznHgAl3xnFT19iWyct2LhrH3KXOjHRmxBGTkiPLZKKAJAgaPpiU9EZ9K+w==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.0.2", + "jest-util": "^27.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/core": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.0.5.tgz", + "integrity": "sha512-g73//jF0VwsOIrWUC9Cqg03lU3QoAMFxVjsm6n6yNmwZcQPN/o8w+gLWODw5VfKNFZT38otXHWxc6b8eGDUpEA==", + "dev": true, + "dependencies": { + "@jest/console": "^27.0.2", + "@jest/reporters": "^27.0.5", + "@jest/test-result": "^27.0.2", + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^27.0.2", + "jest-config": "^27.0.5", + "jest-haste-map": "^27.0.5", + "jest-message-util": "^27.0.2", + "jest-regex-util": "^27.0.1", + "jest-resolve": "^27.0.5", + "jest-resolve-dependencies": "^27.0.5", + "jest-runner": "^27.0.5", + "jest-runtime": "^27.0.5", + "jest-snapshot": "^27.0.5", + "jest-util": "^27.0.2", + "jest-validate": "^27.0.2", + "jest-watcher": "^27.0.2", + "micromatch": "^4.0.4", + "p-each-series": "^2.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/core/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/core/node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/@jest/core/node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/environment": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.0.5.tgz", + "integrity": "sha512-IAkJPOT7bqn0GiX5LPio6/e1YpcmLbrd8O5EFYpAOZ6V+9xJDsXjdgN2vgv9WOKIs/uA1kf5WeD96HhlBYO+FA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/node": "*", + "jest-mock": "^27.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/environment/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/environment/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.0.5.tgz", + "integrity": "sha512-d6Tyf7iDoKqeUdwUKrOBV/GvEZRF67m7lpuWI0+SCD9D3aaejiOQZxAOxwH2EH/W18gnfYaBPLi0VeTGBHtQBg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "@sinonjs/fake-timers": "^7.0.2", + "@types/node": "*", + "jest-message-util": "^27.0.2", + "jest-mock": "^27.0.3", + "jest-util": "^27.0.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/globals": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.0.5.tgz", + "integrity": "sha512-qqKyjDXUaZwDuccpbMMKCCMBftvrbXzigtIsikAH/9ca+kaae8InP2MDf+Y/PdCSMuAsSpHS6q6M25irBBUh+Q==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.0.5", + "@jest/types": "^27.0.2", + "expect": "^27.0.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/reporters": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.0.5.tgz", + "integrity": "sha512-4uNg5+0eIfRafnpgu3jCZws3NNcFzhu5JdRd1mKQ4/53+vkIqwB6vfZ4gn5BdGqOaLtYhlOsPaL5ATkKzyBrJw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.0.2", + "@jest/test-result": "^27.0.2", + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^27.0.5", + "jest-resolve": "^27.0.5", + "jest-util": "^27.0.2", + "jest-worker": "^27.0.2", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/jest-worker": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.2.tgz", + "integrity": "sha512-EoBdilOTTyOgmHXtw/cPc+ZrCA0KJMrkXzkrPGNwLmnvvlN1nj7MPrxpT7m+otSv2e1TLaVffzDnE/LB14zJMg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@jest/source-map": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.1.tgz", + "integrity": "sha512-yMgkF0f+6WJtDMdDYNavmqvbHtiSpwRN2U/W+6uztgfqgkq/PXdKPqjBTUF1RD/feth4rH5N3NW0T5+wIuln1A==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.0.2.tgz", + "integrity": "sha512-gcdWwL3yP5VaIadzwQtbZyZMgpmes8ryBAJp70tuxghiA8qL4imJyZex+i+USQH2H4jeLVVszhwntgdQ97fccA==", + "dev": true, + "dependencies": { + "@jest/console": "^27.0.2", + "@jest/types": "^27.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-result/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-result/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.0.5.tgz", + "integrity": "sha512-opztnGs+cXzZ5txFG2+omBaV5ge/0yuJNKbhE3DREMiXE0YxBuzyEa6pNv3kk2JuucIlH2Xvgmn9kEEHSNt/SA==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.0.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.0.5", + "jest-runtime": "^27.0.5" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.0.5.tgz", + "integrity": "sha512-lBD6OwKXSc6JJECBNk4mVxtSVuJSBsQrJ9WCBisfJs7EZuYq4K6vM9HmoB7hmPiLIDGeyaerw3feBV/bC4z8tg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.0.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.0.5", + "jest-regex-util": "^27.0.1", + "jest-util": "^27.0.2", + "micromatch": "^4.0.4", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/transform/node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/@jest/transform/node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.11", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.11.tgz", + "integrity": "sha512-3NsZsJIA/22P3QUyrEDNA2D133H4j224twJrdipXN38dpnIOzAbUDtOwkcJ5pXmn75w7LSQDjA4tO9dm1XlqlA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/babel__core": { + "version": "7.1.14", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", + "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", + "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/eslint": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.6.tgz", + "integrity": "sha512-I+1sYH+NPQ3/tVqCeUSBwTE/0heyvtXqpIopUUArlBm0Kpocb8FbMa3AZ/ASKIFpN3rnEx932TTXDbt9OXsNDw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", + "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz", + "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==", + "dev": true + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "26.0.23", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz", + "integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==", + "dev": true, + "dependencies": { + "jest-diff": "^26.0.0", + "pretty-format": "^26.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "14.14.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz", + "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.0.tgz", + "integrity": "sha512-hkc1DATxFLQo4VxPDpMH1gCkPpBbpOoJ/4nhuXw4n63/0R6bCpQECj4+K226UJ4JO/eJQz+1mC2I7JsWanAdQw==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", + "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "15.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", + "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", + "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz", + "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz", + "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz", + "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz", + "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.0", + "@webassemblyjs/helper-api-error": "1.11.0", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz", + "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz", + "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz", + "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz", + "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz", + "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz", + "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/helper-wasm-section": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0", + "@webassemblyjs/wasm-opt": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0", + "@webassemblyjs/wast-printer": "1.11.0" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz", + "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/ieee754": "1.11.0", + "@webassemblyjs/leb128": "1.11.0", + "@webassemblyjs/utf8": "1.11.0" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz", + "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz", + "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-api-error": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/ieee754": "1.11.0", + "@webassemblyjs/leb128": "1.11.0", + "@webassemblyjs/utf8": "1.11.0" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz", + "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.0", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/info": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.1.tgz", + "integrity": "sha512-fLnDML5HZ5AEKzHul8xLAksoKN2cibu6MgonkUj8R9V7bbeVRkd1XbGEGWrAUNYHbX1jcqCsDEpBviE5StPMzQ==", + "dev": true, + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.1.tgz", + "integrity": "sha512-Zj1z6AyS+vqV6Hfi7ngCjFGdHV5EwZNIHo6QfFTNe9PyW+zBU1zJ9BiOW1pmUEq950RC4+Dym6flyA/61/vhyw==", + "dev": true, + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.0.tgz", + "integrity": "sha512-oZRad/3SMOI/pxbbmqyurIx7jHw1wZDcR9G44L8pUVFEomX/0dH89SrM1KaDXuv1NpzAXz6Op/Xu/Qd5XXzdEA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "node_modules/axios": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.2.tgz", + "integrity": "sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/babel-jest": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.0.5.tgz", + "integrity": "sha512-bTMAbpCX7ldtfbca2llYLeSFsDM257aspyAOpsdrdSrBqoLkWCy4HPYTXtXWaSLgFPjrJGACL65rzzr4RFGadw==", + "dev": true, + "dependencies": { + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^27.0.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-jest/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.1.tgz", + "integrity": "sha512-sqBF0owAcCDBVEDtxqfYr2F36eSHdx7lAVGyYuOBRnKdD6gzcy0I0XrAYCZgOA3CRrLhmR+Uae9nogPzmAtOfQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.0.1.tgz", + "integrity": "sha512-nIBIqCEpuiyhvjQs2mVNwTxQQa2xk70p9Dd/0obQGBf8FBzbnI8QhQKzLsWMN2i6q+5B0OcWDtrboBX5gmOLyA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^27.0.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/browserslist/node_modules/caniuse-lite": { + "version": "1.0.30001230", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz", + "integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/browserslist/node_modules/colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "node_modules/browserslist/node_modules/electron-to-chromium": { + "version": "1.3.742", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.742.tgz", + "integrity": "sha512-ihL14knI9FikJmH2XUIDdZFWJxvr14rPSdOhJ7PpS27xbz8qmaRwCwyg/bmFwjWKmWK9QyamiCZVCvXm5CH//Q==", + "dev": true + }, + "node_modules/browserslist/node_modules/node-releases": { + "version": "1.1.72", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", + "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", + "dev": true + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.1.tgz", + "integrity": "sha512-jVamGdJPDeuQilKhvVn1h3knuMOZzr8QDnpk+M9aMlCaMkTDd6fBWPhiDqFvFZ07pL0liqabAiuy8SY4jGHeaw==", + "dev": true + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/colorette": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", + "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/convert-source-map/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", + "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", + "dev": true + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", + "dev": true, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/enhanced-resolve": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", + "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/envinfo": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.7.3.tgz", + "integrity": "sha512-46+j5QxbPWza0PB1i15nZx0xQ4I/EfQxg9J8Had3b408SV63nEtor2e+oiY63amTo9KTuh2a3XLObNwduxYwwA==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.15.0.tgz", + "integrity": "sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.2.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.0.2.tgz", + "integrity": "sha512-YJFNJe2+P2DqH+ZrXy+ydRQYO87oxRUonZImpDodR1G7qo3NYd3pL+NQ9Keqpez3cehczYwZDBC3A7xk3n7M/w==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.0.1", + "jest-matcher-utils": "^27.0.2", + "jest-message-util": "^27.0.2", + "jest-regex-util": "^27.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/expect/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/expect/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/expect/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/expect/node_modules/jest-get-type": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.1.tgz", + "integrity": "sha512-9Tggo9zZbu0sHKebiAijyt1NM77Z0uO4tuWOxUCujAiSeXv30Vb5D4xVF4UR4YWNapcftj+PbByU54lKD7/xMg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", + "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", + "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.1.1" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.5.tgz", + "integrity": "sha512-4NlVMS29gE+JOZvgmSAsz3eOjkSsHqjTajlIsah/4MVSmKvf3zFP/TvgcLoWe2UVHiE9KF741sReqhF0p4mqbQ==", + "dev": true, + "dependencies": { + "@jest/core": "^27.0.5", + "import-local": "^3.0.2", + "jest-cli": "^27.0.5" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.0.2.tgz", + "integrity": "sha512-eMeb1Pn7w7x3wue5/vF73LPCJ7DKQuC9wQUR5ebP9hDPpk5hzcT/3Hmz3Q5BOFpR3tgbmaWhJcMTVgC8Z1NuMw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-circus": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.0.5.tgz", + "integrity": "sha512-p5rO90o1RTh8LPOG6l0Fc9qgp5YGv+8M5CFixhMh7gGHtGSobD1AxX9cjFZujILgY8t30QZ7WVvxlnuG31r8TA==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.0.5", + "@jest/test-result": "^27.0.2", + "@jest/types": "^27.0.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.0.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.0.2", + "jest-matcher-utils": "^27.0.2", + "jest-message-util": "^27.0.2", + "jest-runtime": "^27.0.5", + "jest-snapshot": "^27.0.5", + "jest-util": "^27.0.2", + "pretty-format": "^27.0.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-config": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.0.5.tgz", + "integrity": "sha512-zCUIXag7QIXKEVN4kUKbDBDi9Q53dV5o3eNhGqe+5zAbt1vLs4VE3ceWaYrOub0L4Y7E9pGfM84TX/0ARcE+Qw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.0.5", + "@jest/types": "^27.0.2", + "babel-jest": "^27.0.5", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "jest-circus": "^27.0.5", + "jest-environment-jsdom": "^27.0.5", + "jest-environment-node": "^27.0.5", + "jest-get-type": "^27.0.1", + "jest-jasmine2": "^27.0.5", + "jest-regex-util": "^27.0.1", + "jest-resolve": "^27.0.5", + "jest-runner": "^27.0.5", + "jest-util": "^27.0.2", + "jest-validate": "^27.0.2", + "micromatch": "^4.0.4", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-config/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/jest-get-type": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.1.tgz", + "integrity": "sha512-9Tggo9zZbu0sHKebiAijyt1NM77Z0uO4tuWOxUCujAiSeXv30Vb5D4xVF4UR4YWNapcftj+PbByU54lKD7/xMg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-config/node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/jest-config/node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-config/node_modules/pretty-format": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-docblock": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.1.tgz", + "integrity": "sha512-TA4+21s3oebURc7VgFV4r7ltdIJ5rtBH1E3Tbovcg7AV+oLfD5DcJ2V2vJ5zFA9sL5CFd/d2D6IpsAeSheEdrA==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.0.2.tgz", + "integrity": "sha512-OLMBZBZ6JkoXgUenDtseFRWA43wVl2BwmZYIWQws7eS7pqsIvePqj/jJmEnfq91ALk3LNphgwNK/PRFBYi7ITQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "chalk": "^4.0.0", + "jest-get-type": "^27.0.1", + "jest-util": "^27.0.2", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/jest-get-type": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.1.tgz", + "integrity": "sha512-9Tggo9zZbu0sHKebiAijyt1NM77Z0uO4tuWOxUCujAiSeXv30Vb5D4xVF4UR4YWNapcftj+PbByU54lKD7/xMg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/pretty-format": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.0.5.tgz", + "integrity": "sha512-ToWhViIoTl5738oRaajTMgYhdQL73UWPoV4GqHGk2DPhs+olv8OLq5KoQW8Yf+HtRao52XLqPWvl46dPI88PdA==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.0.5", + "@jest/fake-timers": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/node": "*", + "jest-mock": "^27.0.3", + "jest-util": "^27.0.2", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-environment-node": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.0.5.tgz", + "integrity": "sha512-47qqScV/WMVz5OKF5TWpAeQ1neZKqM3ySwNveEnLyd+yaE/KT6lSMx/0SOx60+ZUcVxPiESYS+Kt2JS9y4PpkQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.0.5", + "@jest/fake-timers": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/node": "*", + "jest-mock": "^27.0.3", + "jest-util": "^27.0.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-get-type": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "dev": true, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-haste-map": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.0.5.tgz", + "integrity": "sha512-3LFryGSHxwPFHzKIs6W0BGA2xr6g1MvzSjR3h3D8K8Uqy4vbRm/grpGHzbPtIbOPLC6wFoViRrNEmd116QWSkw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^27.0.1", + "jest-serializer": "^27.0.1", + "jest-util": "^27.0.2", + "jest-worker": "^27.0.2", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-haste-map/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-haste-map/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-haste-map/node_modules/jest-worker": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.2.tgz", + "integrity": "sha512-EoBdilOTTyOgmHXtw/cPc+ZrCA0KJMrkXzkrPGNwLmnvvlN1nj7MPrxpT7m+otSv2e1TLaVffzDnE/LB14zJMg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-haste-map/node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/jest-haste-map/node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-haste-map/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-jasmine2": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.0.5.tgz", + "integrity": "sha512-m3TojR19sFmTn79QoaGy1nOHBcLvtLso6Zh7u+gYxZWGcza4rRPVqwk1hciA5ZOWWZIJOukAcore8JRX992FaA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^27.0.5", + "@jest/source-map": "^27.0.1", + "@jest/test-result": "^27.0.2", + "@jest/types": "^27.0.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.0.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.0.2", + "jest-matcher-utils": "^27.0.2", + "jest-message-util": "^27.0.2", + "jest-runtime": "^27.0.5", + "jest-snapshot": "^27.0.5", + "jest-util": "^27.0.2", + "pretty-format": "^27.0.2", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-jasmine2/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/pretty-format": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.0.2.tgz", + "integrity": "sha512-TZA3DmCOfe8YZFIMD1GxFqXUkQnIoOGQyy4hFCA2mlHtnAaf+FeOMxi0fZmfB41ZL+QbFG6BVaZF5IeFIVy53Q==", + "dev": true, + "dependencies": { + "jest-get-type": "^27.0.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-leak-detector/node_modules/jest-get-type": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.1.tgz", + "integrity": "sha512-9Tggo9zZbu0sHKebiAijyt1NM77Z0uO4tuWOxUCujAiSeXv30Vb5D4xVF4UR4YWNapcftj+PbByU54lKD7/xMg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.0.2.tgz", + "integrity": "sha512-Qczi5xnTNjkhcIB0Yy75Txt+Ez51xdhOxsukN7awzq2auZQGPHcQrJ623PZj0ECDEMOk2soxWx05EXdXGd1CbA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.0.2", + "jest-get-type": "^27.0.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/diff-sequences": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.1.tgz", + "integrity": "sha512-XPLijkfJUh/PIBnfkcSHgvD6tlYixmcMAn3osTk6jt+H0v/mgURto1XUiD9DKuGX5NDoVS6dSlA23gd9FUaCFg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/jest-diff": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.2.tgz", + "integrity": "sha512-BFIdRb0LqfV1hBt8crQmw6gGQHVDhM87SpMIZ45FPYKReZYG5er1+5pIn2zKqvrJp6WNox0ylR8571Iwk2Dmgw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.0.1", + "jest-get-type": "^27.0.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/jest-get-type": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.1.tgz", + "integrity": "sha512-9Tggo9zZbu0sHKebiAijyt1NM77Z0uO4tuWOxUCujAiSeXv30Vb5D4xVF4UR4YWNapcftj+PbByU54lKD7/xMg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.0.2.tgz", + "integrity": "sha512-rTqWUX42ec2LdMkoUPOzrEd1Tcm+R1KfLOmFK+OVNo4MnLsEaxO5zPDb2BbdSmthdM/IfXxOZU60P/WbWF8BTw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.0.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "pretty-format": "^27.0.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/jest-message-util/node_modules/@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/jest-message-util/node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/jest-message-util/node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jest-message-util/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-message-util/node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/jest-message-util/node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-mock": { + "version": "27.0.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.0.3.tgz", + "integrity": "sha512-O5FZn5XDzEp+Xg28mUz4ovVcdwBBPfAhW9+zJLO0Efn2qNbYcDaJvSlRiQ6BCZUCVOJjALicuJQI9mRFjv1o9Q==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-mock/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-mock/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.1.tgz", + "integrity": "sha512-6nY6QVcpTgEKQy1L41P4pr3aOddneK17kn3HJw6SdwGiKfgCGTvH02hVXL0GU8GEKtPH83eD2DIDgxHXOxVohQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.0.5.tgz", + "integrity": "sha512-Md65pngRh8cRuWVdWznXBB5eDt391OJpdBaJMxfjfuXCvOhM3qQBtLMCMTykhuUKiBMmy5BhqCW7AVOKmPrW+Q==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "chalk": "^4.0.0", + "escalade": "^3.1.1", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.0.2", + "jest-validate": "^27.0.2", + "resolve": "^1.20.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.5.tgz", + "integrity": "sha512-xUj2dPoEEd59P+nuih4XwNa4nJ/zRd/g4rMvjHrZPEBWeWRq/aJnnM6mug+B+Nx+ILXGtfWHzQvh7TqNV/WbuA==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "jest-regex-util": "^27.0.1", + "jest-snapshot": "^27.0.5" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-resolve/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-resolve/node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jest-runner": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.0.5.tgz", + "integrity": "sha512-HNhOtrhfKPArcECgBTcWOc+8OSL8GoFoa7RsHGnfZR1C1dFohxy9eLtpYBS+koybAHlJLZzNCx2Y/Ic3iEtJpQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.0.2", + "@jest/environment": "^27.0.5", + "@jest/test-result": "^27.0.2", + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-docblock": "^27.0.1", + "jest-environment-jsdom": "^27.0.5", + "jest-environment-node": "^27.0.5", + "jest-haste-map": "^27.0.5", + "jest-leak-detector": "^27.0.2", + "jest-message-util": "^27.0.2", + "jest-resolve": "^27.0.5", + "jest-runtime": "^27.0.5", + "jest-util": "^27.0.2", + "jest-worker": "^27.0.2", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/jest-worker": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.2.tgz", + "integrity": "sha512-EoBdilOTTyOgmHXtw/cPc+ZrCA0KJMrkXzkrPGNwLmnvvlN1nj7MPrxpT7m+otSv2e1TLaVffzDnE/LB14zJMg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-runtime": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.0.5.tgz", + "integrity": "sha512-V/w/+VasowPESbmhXn5AsBGPfb35T7jZPGZybYTHxZdP7Gwaa+A0EXE6rx30DshHKA98lVCODbCO8KZpEW3hiQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.0.2", + "@jest/environment": "^27.0.5", + "@jest/fake-timers": "^27.0.5", + "@jest/globals": "^27.0.5", + "@jest/source-map": "^27.0.1", + "@jest/test-result": "^27.0.2", + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.0.5", + "jest-message-util": "^27.0.2", + "jest-mock": "^27.0.3", + "jest-regex-util": "^27.0.1", + "jest-resolve": "^27.0.5", + "jest-snapshot": "^27.0.5", + "jest-util": "^27.0.2", + "jest-validate": "^27.0.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^16.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-serializer": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.1.tgz", + "integrity": "sha512-svy//5IH6bfQvAbkAEg1s7xhhgHTtXu0li0I2fdKHDsLP2P2MOiscPQIENQep8oU2g2B3jqLyxKKzotZOz4CwQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.0.5.tgz", + "integrity": "sha512-H1yFYdgnL1vXvDqMrnDStH6yHFdMEuzYQYc71SnC/IJnuuhW6J16w8GWG1P+qGd3Ag3sQHjbRr0TcwEo/vGS+g==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.0.2", + "graceful-fs": "^4.2.4", + "jest-diff": "^27.0.2", + "jest-get-type": "^27.0.1", + "jest-haste-map": "^27.0.5", + "jest-matcher-utils": "^27.0.2", + "jest-message-util": "^27.0.2", + "jest-resolve": "^27.0.5", + "jest-util": "^27.0.2", + "natural-compare": "^1.4.0", + "pretty-format": "^27.0.2", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/diff-sequences": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.1.tgz", + "integrity": "sha512-XPLijkfJUh/PIBnfkcSHgvD6tlYixmcMAn3osTk6jt+H0v/mgURto1XUiD9DKuGX5NDoVS6dSlA23gd9FUaCFg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.2.tgz", + "integrity": "sha512-BFIdRb0LqfV1hBt8crQmw6gGQHVDhM87SpMIZ45FPYKReZYG5er1+5pIn2zKqvrJp6WNox0ylR8571Iwk2Dmgw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.0.1", + "jest-get-type": "^27.0.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-get-type": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.1.tgz", + "integrity": "sha512-9Tggo9zZbu0sHKebiAijyt1NM77Z0uO4tuWOxUCujAiSeXv30Vb5D4xVF4UR4YWNapcftj+PbByU54lKD7/xMg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.2.tgz", + "integrity": "sha512-1d9uH3a00OFGGWSibpNYr+jojZ6AckOMCXV2Z4K3YXDnzpkAaXQyIpY14FOJPiUmil7CD+A6Qs+lnnh6ctRbIA==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.0.2.tgz", + "integrity": "sha512-UgBF6/oVu1ofd1XbaSotXKihi8nZhg0Prm8twQ9uCuAfo59vlxCXMPI/RKmrZEVgi3Nd9dS0I8A0wzWU48pOvg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.0.1", + "leven": "^3.1.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/jest-get-type": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.1.tgz", + "integrity": "sha512-9Tggo9zZbu0sHKebiAijyt1NM77Z0uO4tuWOxUCujAiSeXv30Vb5D4xVF4UR4YWNapcftj+PbByU54lKD7/xMg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "dev": true, + "dependencies": { + "@jest/types": "^27.0.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.0.2.tgz", + "integrity": "sha512-8nuf0PGuTxWj/Ytfw5fyvNn/R80iXY8QhIT0ofyImUvdnoaBdT6kob0GmhXR+wO+ALYVnh8bQxN4Tjfez0JgkA==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.0.2", + "@jest/types": "^27.0.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.0.2", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest/node_modules/@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest/node_modules/jest-cli": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.0.5.tgz", + "integrity": "sha512-kZqY020QFOFQKVE2knFHirTBElw3/Q0kUbDc3nMfy/x+RQ7zUY89SUuzpHHJoSX1kX7Lq569ncvjNqU3Td/FCA==", + "dev": true, + "dependencies": { + "@jest/core": "^27.0.5", + "@jest/test-result": "^27.0.2", + "@jest/types": "^27.0.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "jest-config": "^27.0.5", + "jest-util": "^27.0.2", + "jest-validate": "^27.0.2", + "prompts": "^2.0.1", + "yargs": "^16.0.3" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.6.0.tgz", + "integrity": "sha512-Ty1vmF4NHJkolaEmdjtxTfSfkdb8Ywarwf63f+F8/mDD1uLSSWDxDuMiZxiPhwunLrn9LOSVItWj4bLYsLN3Dg==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.5", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/acorn": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.0.tgz", + "integrity": "sha512-ULr0LDaEqQrMFGyQ3bhJkLsbtrQ8QibAseGZeaSUiT/6zb9IvIkomWHJIvgvwad+hinRAgsI51JcWk2yvwyL+w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "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/makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "dependencies": { + "tmpl": "1.0.x" + } + }, + "node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/memory-fs/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/memory-fs/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/memory-fs/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mime": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.7.tgz", + "integrity": "sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", + "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", + "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", + "dev": true, + "dependencies": { + "mime-db": "1.45.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node_modules/node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-each-series": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "dependencies": { + "node-modules-regexp": "^1.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pretty-format/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prompts": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", + "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/rechoir": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "node_modules/sirv": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.10.tgz", + "integrity": "sha512-H5EZCoZaggEUQy8ocKsF7WAToGuZhjJlLvM3XOef46CbdIgbNeQ1p32N1PCuCjkVYwrAVOSMacN6CXXgIzuspg==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.9", + "mime": "^2.3.1", + "totalist": "^1.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-2.0.0.tgz", + "integrity": "sha512-DJLK+gR9hlx+58yGU54EDAQZzR/TksgrtvRtyEBWnd5DR7O4n0RgdyO/KBwJ76zF+wDiFRT/1vdV3SdLUR68Lg==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.2", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz", + "integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==", + "dev": true, + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz", + "integrity": "sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q==", + "dev": true, + "dependencies": { + "jest-worker": "^26.6.2", + "p-limit": "^3.1.0", + "schema-utils": "^3.0.0", + "serialize-javascript": "^5.0.1", + "source-map": "^0.6.1", + "terser": "^5.5.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/terser/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-jest": { + "version": "27.0.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.3.tgz", + "integrity": "sha512-U5rdMjnYam9Ucw+h0QvtNDbc5+88nxt7tbIvqaZUhFrfG4+SkWhMXjejCLVGcpILTPuV+H3W/GZDZrnZFpPeXw==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "buffer-from": "1.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash": "4.x", + "make-error": "1.x", + "mkdirp": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "jest": "^27.0.0", + "typescript": ">=3.8 <5.0" + } + }, + "node_modules/ts-loader": { + "version": "8.0.14", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.14.tgz", + "integrity": "sha512-Jt/hHlUnApOZjnSjTmZ+AbD5BGlQFx3f1D0nYuNKwz0JJnuDGHJas6az+FlWKwwRTu+26GXpv249A8UAnYUpqA==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^4.0.0", + "loader-utils": "^2.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "*" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/v8-compile-cache": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz", + "integrity": "sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "dependencies": { + "makeerror": "1.0.x" + } + }, + "node_modules/watchpack": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.0.tgz", + "integrity": "sha512-UjgD1mqjkG99+3lgG36at4wPnUXNvis2v1utwTgQ43C22c4LD71LsYMExdWXh4HZ+RmW+B0t1Vrg2GpXAkTOQw==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/webpack": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.13.0.tgz", + "integrity": "sha512-NPhMEtfhSVegp1FNPkCM1MPygDm0GHwpreG10dh//0Gr0epfB0br9nlgEfxSghxJqrQ7j9XzgO91CGGLWZiHeA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.0", + "@types/estree": "^0.0.45", + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/wasm-edit": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0", + "acorn": "^8.0.4", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.6.0", + "eslint-scope": "^5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.4", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "pkg-dir": "^5.0.0", + "schema-utils": "^3.0.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.1", + "watchpack": "^2.0.0", + "webpack-sources": "^2.1.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.3.0.tgz", + "integrity": "sha512-J3TPm54bPARx6QG8z4cKBszahnUglcv70+N+8gUqv2I5KOFHJbzBiLx+pAp606so0X004fxM7hqRu10MLjJifA==", + "dev": true, + "dependencies": { + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "chalk": "^4.1.0", + "commander": "^6.2.0", + "gzip-size": "^6.0.0", + "lodash": "^4.17.20", + "opener": "^1.5.2", + "sirv": "^1.0.7", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/acorn": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.4.tgz", + "integrity": "sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/webpack-cli": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.1.tgz", + "integrity": "sha512-/F4+9QNZM/qKzzL9/06Am8NXIkGV+/NqQ62Dx7DSqudxxpAgBqYn6V7+zp+0Y7JuWksKUbczRY3wMTd+7Uj6OA==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/info": "^1.2.1", + "@webpack-cli/serve": "^1.2.1", + "colorette": "^1.2.1", + "commander": "^6.2.0", + "enquirer": "^2.3.6", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "v8-compile-cache": "^2.2.0", + "webpack-merge": "^4.2.2" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/init": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/webpack-merge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", + "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/webpack-sources": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz", + "integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==", + "dev": true, + "dependencies": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/acorn": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.4.tgz", + "integrity": "sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack/node_modules/enhanced-resolve": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.6.0.tgz", + "integrity": "sha512-C3GGDfFZmqUa21o10YRKbZN60DPl0HyXKXxoEnQMWso9u7KMU23L7CBHfr/rVxORddY/8YQZaU2MZ1ewTS8Pcw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/tapable": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", + "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.6.0.tgz", + "integrity": "sha512-os0KkeeqUOl7ccdDT1qqUcS4KH4tcBTSKK5Nl5WKb2lyxInIZ/CpjkqKa1Ss12mjfdcRX9mHmPPs7/SxG1Hbdw==", + "dev": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.10.4", @@ -1421,7 +8980,8 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.1.tgz", "integrity": "sha512-Zj1z6AyS+vqV6Hfi7ngCjFGdHV5EwZNIHo6QfFTNe9PyW+zBU1zJ9BiOW1pmUEq950RC4+Dym6flyA/61/vhyw==", - "dev": true + "dev": true, + "requires": {} }, "@xtuc/ieee754": { "version": "1.2.0", @@ -1469,7 +9029,8 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true + "dev": true, + "requires": {} }, "acorn-walk": { "version": "8.0.0", @@ -1502,7 +9063,8 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true + "dev": true, + "requires": {} }, "ansi-colors": { "version": "4.1.1", @@ -2907,7 +10469,8 @@ "isomorphic-ws": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", - "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==" + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "requires": {} }, "istanbul-lib-coverage": { "version": "3.0.0", @@ -3846,7 +11409,8 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true + "dev": true, + "requires": {} }, "jest-regex-util": { "version": "27.0.1", @@ -5830,7 +13394,8 @@ "ws": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "requires": {} }, "xml-name-validator": { "version": "3.0.0", diff --git a/src/inverse-client.ts b/src/inverse-client.ts index 32dfe97..340e596 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -1,10 +1,29 @@ import { AxiosRequestConfig } from 'axios'; -import { GenericAPIResponse, getRestBaseUrl, RestClientOptions } from './util/requestUtils'; +import { + GenericAPIResponse, + getRestBaseUrl, + RestClientOptions, +} from './util/requestUtils'; import RequestWrapper from './util/requestWrapper'; -import SharedEndpoints from './shared-endpoints'; -import { SymbolFromLimitParam, SymbolIntervalFromLimitParam, SymbolParam } from './types/shared'; +import { + APIResponse, + APIResponseWithTime, + AssetExchangeRecordsReq, + CoinParam, + SymbolFromLimitParam, + SymbolInfo, + SymbolIntervalFromLimitParam, + SymbolLimitParam, + SymbolParam, + SymbolPeriodLimitParam, + TimeResult, + WalletFundRecordsReq, + WithdrawRecordsReq, +} from './types/shared'; +import BaseRestClient from './util/BaseRestClient'; -export class InverseClient extends SharedEndpoints { +export class InverseClient extends BaseRestClient { + /** @deprecated, */ protected requestWrapper: RequestWrapper; /** @@ -23,8 +42,13 @@ export class InverseClient extends SharedEndpoints { restClientOptions: RestClientOptions = {}, requestOptions: AxiosRequestConfig = {} ) { - super(); - + super( + key, + secret, + getRestBaseUrl(useLivenet, restClientOptions), + restClientOptions, + requestOptions + ); this.requestWrapper = new RequestWrapper( key, secret, @@ -35,46 +59,128 @@ export class InverseClient extends SharedEndpoints { return this; } + async fetchServerTime(): Promise { + const res = await this.getServerTime(); + return Number(res.time_now); + } + /** * * Market Data Endpoints * */ - getKline(params: SymbolIntervalFromLimitParam): GenericAPIResponse { + getOrderBook(params: SymbolParam): Promise> { + return this.requestWrapper.get('v2/public/orderBook/L2', params); + } + + getKline( + params: SymbolIntervalFromLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/kline/list', params); } /** - * @deprecated use getTickers() instead + * Get latest information for symbol */ - getLatestInformation(params?: Partial): GenericAPIResponse { - return this.getTickers(params); + getTickers( + params?: Partial + ): Promise> { + return this.requestWrapper.get('v2/public/tickers', params); } - /** - * @deprecated use getTrades() instead - */ - getPublicTradingRecords(params: SymbolFromLimitParam): GenericAPIResponse { - return this.getTrades(params); - } - - getTrades(params: SymbolFromLimitParam): GenericAPIResponse { + getTrades(params: SymbolLimitParam): Promise> { return this.requestWrapper.get('v2/public/trading-records', params); } - getMarkPriceKline(params: SymbolIntervalFromLimitParam): GenericAPIResponse { + getSymbols(): Promise> { + return this.requestWrapper.get('v2/public/symbols'); + } + + getMarkPriceKline( + params: SymbolIntervalFromLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/mark-price-kline', params); } - getIndexPriceKline(params: SymbolIntervalFromLimitParam): GenericAPIResponse { + getIndexPriceKline( + params: SymbolIntervalFromLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/index-price-kline', params); } - getPremiumIndexKline(params: SymbolIntervalFromLimitParam): GenericAPIResponse { + getPremiumIndexKline( + params: SymbolIntervalFromLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/premium-index-kline', params); } + /** + * + * Market Data : Advanced + * + */ + + getOpenInterest(params: SymbolPeriodLimitParam): GenericAPIResponse { + return this.requestWrapper.get('v2/public/open-interest', params); + } + + getLatestBigDeal(params: SymbolLimitParam): GenericAPIResponse { + return this.requestWrapper.get('v2/public/big-deal', params); + } + + getLongShortRatio(params: SymbolPeriodLimitParam): GenericAPIResponse { + return this.requestWrapper.get('v2/public/account-ratio', params); + } + + /** + * + * Account Data Endpoints + * + */ + + getApiKeyInfo(): GenericAPIResponse { + return this.requestWrapper.get('v2/private/account/api-key'); + } + + /** + * + * Wallet Data Endpoints + * + */ + + getWalletBalance(params?: Partial): GenericAPIResponse { + return this.requestWrapper.get('v2/private/wallet/balance', params); + } + + getWalletFundRecords(params?: WalletFundRecordsReq): GenericAPIResponse { + return this.requestWrapper.get('v2/private/wallet/fund/records', params); + } + + getWithdrawRecords(params: WithdrawRecordsReq): GenericAPIResponse { + return this.requestWrapper.get('v2/private/wallet/withdraw/list', params); + } + + getAssetExchangeRecords( + params?: AssetExchangeRecordsReq + ): GenericAPIResponse { + return this.requestWrapper.get('v2/private/exchange-order/list', params); + } + + /** + * + * API Data Endpoints + * + */ + + getServerTime(): Promise> { + return this.requestWrapper.get('v2/public/time'); + } + + getApiAnnouncements(): Promise> { + return this.requestWrapper.get('v2/public/announcement'); + } + /** * * Account Data Endpoints @@ -133,8 +239,8 @@ export class InverseClient extends SharedEndpoints { p_r_price?: string; take_profit?: number; stop_loss?: number; - tp_trigger_by?:string; - sl_trigger_by?:string; + tp_trigger_by?: string; + sl_trigger_by?: string; }): GenericAPIResponse { return this.requestWrapper.post('v2/private/order/replace', params); } @@ -254,7 +360,10 @@ export class InverseClient extends SharedEndpoints { leverage: number; leverage_only?: boolean; }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/position/leverage/save', params); + return this.requestWrapper.post( + 'v2/private/position/leverage/save', + params + ); } /** @@ -286,10 +395,7 @@ export class InverseClient extends SharedEndpoints { return this.requestWrapper.get('v2/private/trade/closed-pnl/list', params); } - setPositionMode(params: { - symbol: string; - mode: 0 | 3; - }): GenericAPIResponse { + setPositionMode(params: { symbol: string; mode: 0 | 3 }): GenericAPIResponse { return this.requestWrapper.post('v2/private/position/switch-mode', params); } @@ -306,7 +412,10 @@ export class InverseClient extends SharedEndpoints { buy_leverage: number; sell_leverage: number; }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/position/switch-isolated', params); + return this.requestWrapper.post( + 'v2/private/position/switch-isolated', + params + ); } /** @@ -329,7 +438,10 @@ export class InverseClient extends SharedEndpoints { */ getLastFundingRate(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get('v2/public/funding/prev-funding-rate', params); + return this.requestWrapper.get( + 'v2/public/funding/prev-funding-rate', + params + ); } getMyLastFundingFee(params: SymbolParam): GenericAPIResponse { @@ -337,7 +449,10 @@ export class InverseClient extends SharedEndpoints { } getPredictedFunding(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get('v2/private/funding/predicted-funding', params); + return this.requestWrapper.get( + 'v2/private/funding/predicted-funding', + params + ); } /** @@ -352,5 +467,4 @@ export class InverseClient extends SharedEndpoints { getAPIKeyInfo(): GenericAPIResponse { return this.requestWrapper.get('v2/private/account/api-key'); } - -}; +} diff --git a/src/inverse-futures-client.ts b/src/inverse-futures-client.ts index 9b24dcd..fc33195 100644 --- a/src/inverse-futures-client.ts +++ b/src/inverse-futures-client.ts @@ -1,10 +1,28 @@ import { AxiosRequestConfig } from 'axios'; -import { GenericAPIResponse, getRestBaseUrl, RestClientOptions } from './util/requestUtils'; +import { + GenericAPIResponse, + getRestBaseUrl, + RestClientOptions, +} from './util/requestUtils'; import RequestWrapper from './util/requestWrapper'; -import SharedEndpoints from './shared-endpoints'; -import { SymbolFromLimitParam, SymbolIntervalFromLimitParam, SymbolParam } from './types/shared'; +import { + APIResponse, + AssetExchangeRecordsReq, + CoinParam, + SymbolFromLimitParam, + SymbolInfo, + SymbolIntervalFromLimitParam, + SymbolLimitParam, + SymbolParam, + SymbolPeriodLimitParam, + TimeResult, + WalletFundRecordsReq, + WithdrawRecordsReq, +} from './types/shared'; +import BaseRestClient from './util/BaseRestClient'; -export class InverseFuturesClient extends SharedEndpoints { +export class InverseFuturesClient extends BaseRestClient { + /** @deprecated, */ protected requestWrapper: RequestWrapper; /** @@ -23,8 +41,13 @@ export class InverseFuturesClient extends SharedEndpoints { restClientOptions: RestClientOptions = {}, requestOptions: AxiosRequestConfig = {} ) { - super(); - + super( + key, + secret, + getRestBaseUrl(useLivenet, restClientOptions), + restClientOptions, + requestOptions + ); this.requestWrapper = new RequestWrapper( key, secret, @@ -35,6 +58,98 @@ export class InverseFuturesClient extends SharedEndpoints { return this; } + async fetchServerTime(): Promise { + const res = await this.getServerTime(); + return res.time_now; + } + + /** + * + * Market Data Endpoints + * + */ + + getOrderBook(params: SymbolParam): GenericAPIResponse { + return this.requestWrapper.get('v2/public/orderBook/L2', params); + } + + /** + * Get latest information for symbol + */ + getTickers(params?: Partial): GenericAPIResponse { + return this.requestWrapper.get('v2/public/tickers', params); + } + + getSymbols(): Promise> { + return this.requestWrapper.get('v2/public/symbols'); + } + + /** + * + * Market Data : Advanced + * + */ + + getOpenInterest(params: SymbolPeriodLimitParam): GenericAPIResponse { + return this.requestWrapper.get('v2/public/open-interest', params); + } + + getLatestBigDeal(params: SymbolLimitParam): GenericAPIResponse { + return this.requestWrapper.get('v2/public/big-deal', params); + } + + getLongShortRatio(params: SymbolPeriodLimitParam): GenericAPIResponse { + return this.requestWrapper.get('v2/public/account-ratio', params); + } + + /** + * + * Account Data Endpoints + * + */ + + getApiKeyInfo(): GenericAPIResponse { + return this.requestWrapper.get('v2/private/account/api-key'); + } + + /** + * + * Wallet Data Endpoints + * + */ + + getWalletBalance(params?: Partial): GenericAPIResponse { + return this.requestWrapper.get('v2/private/wallet/balance', params); + } + + getWalletFundRecords(params?: WalletFundRecordsReq): GenericAPIResponse { + return this.requestWrapper.get('v2/private/wallet/fund/records', params); + } + + getWithdrawRecords(params: WithdrawRecordsReq): GenericAPIResponse { + return this.requestWrapper.get('v2/private/wallet/withdraw/list', params); + } + + getAssetExchangeRecords( + params?: AssetExchangeRecordsReq + ): GenericAPIResponse { + return this.requestWrapper.get('v2/private/exchange-order/list', params); + } + + /** + * + * API Data Endpoints + * + */ + + getServerTime(): GenericAPIResponse { + return this.requestWrapper.get('v2/public/time'); + } + + getApiAnnouncements(): GenericAPIResponse { + return this.requestWrapper.get('v2/public/announcement'); + } + /** * * Market Data Endpoints @@ -60,7 +175,9 @@ export class InverseFuturesClient extends SharedEndpoints { return this.requestWrapper.get('v2/public/index-price-kline', params); } - getPremiumIndexKline(params: SymbolIntervalFromLimitParam): GenericAPIResponse { + getPremiumIndexKline( + params: SymbolIntervalFromLimitParam + ): GenericAPIResponse { return this.requestWrapper.get('v2/public/premium-index-kline', params); } @@ -70,7 +187,7 @@ export class InverseFuturesClient extends SharedEndpoints { * */ - /** + /** * Active orders */ @@ -87,7 +204,10 @@ export class InverseFuturesClient extends SharedEndpoints { close_on_trigger?: boolean; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post('futures/private/order/create', orderRequest); + return this.requestWrapper.post( + 'futures/private/order/create', + orderRequest + ); } getActiveOrderList(params: { @@ -130,7 +250,7 @@ export class InverseFuturesClient extends SharedEndpoints { return this.requestWrapper.get('futures/private/order', params); } - /** + /** * Conditional orders */ @@ -147,7 +267,10 @@ export class InverseFuturesClient extends SharedEndpoints { close_on_trigger?: boolean; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post('futures/private/stop-order/create', params); + return this.requestWrapper.post( + 'futures/private/stop-order/create', + params + ); } getConditionalOrder(params: { @@ -165,11 +288,17 @@ export class InverseFuturesClient extends SharedEndpoints { stop_order_id?: string; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post('futures/private/stop-order/cancel', params); + return this.requestWrapper.post( + 'futures/private/stop-order/cancel', + params + ); } cancelAllConditionalOrders(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.post('futures/private/stop-order/cancelAll', params); + return this.requestWrapper.post( + 'futures/private/stop-order/cancelAll', + params + ); } replaceConditionalOrder(params: { @@ -180,7 +309,10 @@ export class InverseFuturesClient extends SharedEndpoints { p_r_price?: string; p_r_trigger_price?: string; }): GenericAPIResponse { - return this.requestWrapper.post('futures/private/stop-order/replace', params); + return this.requestWrapper.post( + 'futures/private/stop-order/replace', + params + ); } queryConditionalOrder(params: { @@ -191,11 +323,10 @@ export class InverseFuturesClient extends SharedEndpoints { return this.requestWrapper.get('futures/private/stop-order', params); } - /** + /** * Position */ - /** * Get position list */ @@ -207,7 +338,10 @@ export class InverseFuturesClient extends SharedEndpoints { symbol: string; margin: string; }): GenericAPIResponse { - return this.requestWrapper.post('futures/private/position/change-position-margin', params); + return this.requestWrapper.post( + 'futures/private/position/change-position-margin', + params + ); } setTradingStop(params: { @@ -219,7 +353,10 @@ export class InverseFuturesClient extends SharedEndpoints { sl_trigger_by?: string; new_trailing_active?: number; }): GenericAPIResponse { - return this.requestWrapper.post('futures/private/position/trading-stop', params); + return this.requestWrapper.post( + 'futures/private/position/trading-stop', + params + ); } setUserLeverage(params: { @@ -227,7 +364,10 @@ export class InverseFuturesClient extends SharedEndpoints { buy_leverage: number; sell_leverage: number; }): GenericAPIResponse { - return this.requestWrapper.post('futures/private/position/leverage/save', params); + return this.requestWrapper.post( + 'futures/private/position/leverage/save', + params + ); } /** @@ -237,7 +377,10 @@ export class InverseFuturesClient extends SharedEndpoints { symbol: string; mode: number; }): GenericAPIResponse { - return this.requestWrapper.post('futures/private/position/switch-mode', params); + return this.requestWrapper.post( + 'futures/private/position/switch-mode', + params + ); } /** @@ -249,7 +392,10 @@ export class InverseFuturesClient extends SharedEndpoints { buy_leverage: number; sell_leverage: number; }): GenericAPIResponse { - return this.requestWrapper.post('futures/private/position/switch-isolated', params); + return this.requestWrapper.post( + 'futures/private/position/switch-isolated', + params + ); } getTradeRecords(params: { @@ -271,14 +417,17 @@ export class InverseFuturesClient extends SharedEndpoints { page?: number; limit?: number; }): GenericAPIResponse { - return this.requestWrapper.get('futures/private/trade/closed-pnl/list', params); + return this.requestWrapper.get( + 'futures/private/trade/closed-pnl/list', + params + ); } /** **** The following are all the same as the inverse client **** */ - /** + /** * Risk Limit */ getRiskLimitList(): GenericAPIResponse { @@ -292,12 +441,15 @@ export class InverseFuturesClient extends SharedEndpoints { return this.requestWrapper.post('open-api/wallet/risk-limit', params); } - /** + /** * Funding */ getLastFundingRate(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get('v2/public/funding/prev-funding-rate', params); + return this.requestWrapper.get( + 'v2/public/funding/prev-funding-rate', + params + ); } getMyLastFundingFee(params: SymbolParam): GenericAPIResponse { @@ -305,14 +457,17 @@ export class InverseFuturesClient extends SharedEndpoints { } getPredictedFunding(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get('v2/private/funding/predicted-funding', params); + return this.requestWrapper.get( + 'v2/private/funding/predicted-funding', + params + ); } - /** + /** * LCP Info */ getLcpInfo(params: SymbolParam): GenericAPIResponse { return this.requestWrapper.get('v2/private/account/lcp', params); } -}; +} diff --git a/src/linear-client.ts b/src/linear-client.ts index 88dff20..898a3e8 100644 --- a/src/linear-client.ts +++ b/src/linear-client.ts @@ -5,19 +5,28 @@ import { RestClientOptions, } from './util/requestUtils'; import RequestWrapper from './util/requestWrapper'; -import SharedEndpoints from './shared-endpoints'; import { + APIResponse, + AssetExchangeRecordsReq, + CoinParam, + SymbolInfo, SymbolIntervalFromLimitParam, SymbolLimitParam, SymbolParam, + SymbolPeriodLimitParam, + TimeResult, + WalletFundRecordsReq, + WithdrawRecordsReq, } from './types/shared'; import { linearPositionModeEnum, positionTpSlModeEnum } from './constants/enum'; +import BaseRestClient from './util/BaseRestClient'; -export class LinearClient extends SharedEndpoints { +export class LinearClient extends BaseRestClient { + /** @deprecated, */ protected requestWrapper: RequestWrapper; /** - * @public Creates an instance of the linear REST API client. + * @public Creates an instance of the linear (USD Perps) REST API client. * * @param {string} key - your API key * @param {string} secret - your API secret @@ -32,7 +41,13 @@ export class LinearClient extends SharedEndpoints { restClientOptions: RestClientOptions = {}, requestOptions: AxiosRequestConfig = {} ) { - super(); + super( + key, + secret, + getRestBaseUrl(useLivenet, restClientOptions), + restClientOptions, + requestOptions + ); this.requestWrapper = new RequestWrapper( key, @@ -44,6 +59,98 @@ export class LinearClient extends SharedEndpoints { return this; } + async fetchServerTime(): Promise { + const timeRes = await this.getServerTime(); + return timeRes.time_now; + } + + /** + * + * Market Data Endpoints + * + */ + + getOrderBook(params: SymbolParam): GenericAPIResponse { + return this.requestWrapper.get('v2/public/orderBook/L2', params); + } + + /** + * Get latest information for symbol + */ + getTickers(params?: Partial): GenericAPIResponse { + return this.requestWrapper.get('v2/public/tickers', params); + } + + getSymbols(): Promise> { + return this.requestWrapper.get('v2/public/symbols'); + } + + /** + * + * Market Data : Advanced + * + */ + + getOpenInterest(params: SymbolPeriodLimitParam): GenericAPIResponse { + return this.requestWrapper.get('v2/public/open-interest', params); + } + + getLatestBigDeal(params: SymbolLimitParam): GenericAPIResponse { + return this.requestWrapper.get('v2/public/big-deal', params); + } + + getLongShortRatio(params: SymbolPeriodLimitParam): GenericAPIResponse { + return this.requestWrapper.get('v2/public/account-ratio', params); + } + + /** + * + * Account Data Endpoints + * + */ + + getApiKeyInfo(): GenericAPIResponse { + return this.requestWrapper.get('v2/private/account/api-key'); + } + + /** + * + * Wallet Data Endpoints + * + */ + + getWalletBalance(params?: Partial): GenericAPIResponse { + return this.requestWrapper.get('v2/private/wallet/balance', params); + } + + getWalletFundRecords(params?: WalletFundRecordsReq): GenericAPIResponse { + return this.requestWrapper.get('v2/private/wallet/fund/records', params); + } + + getWithdrawRecords(params: WithdrawRecordsReq): GenericAPIResponse { + return this.requestWrapper.get('v2/private/wallet/withdraw/list', params); + } + + getAssetExchangeRecords( + params?: AssetExchangeRecordsReq + ): GenericAPIResponse { + return this.requestWrapper.get('v2/private/exchange-order/list', params); + } + + /** + * + * API Data Endpoints + * + */ + + getServerTime(): GenericAPIResponse { + return this.requestWrapper.get('v2/public/time'); + } + + getApiAnnouncements(): GenericAPIResponse { + return this.requestWrapper.get('v2/public/announcement'); + } + /** * * Market Data Endpoints diff --git a/src/shared-endpoints.ts b/src/shared-endpoints.ts deleted file mode 100644 index d778877..0000000 --- a/src/shared-endpoints.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { - APIResponse, - AssetExchangeRecordsReq, - CoinParam, - SymbolInfo, - SymbolLimitParam, - SymbolParam, - SymbolPeriodLimitParam, - WalletFundRecordsReq, - WithdrawRecordsReq, -} from './types/shared'; -import { GenericAPIResponse } from './util/requestUtils'; -import RequestWrapper from './util/requestWrapper'; - -export default class SharedEndpoints { - // TODO: Is there a way to say that Base has to provide this? - protected requestWrapper: RequestWrapper; - - /** - * - * Market Data Endpoints - * - */ - - getOrderBook(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get('v2/public/orderBook/L2', params); - } - - /** - * Get latest information for symbol - */ - getTickers(params?: Partial): GenericAPIResponse { - return this.requestWrapper.get('v2/public/tickers', params); - } - - getSymbols(): Promise> { - return this.requestWrapper.get('v2/public/symbols'); - } - - /** - * - * Market Data : Advanced - * - */ - - getOpenInterest(params: SymbolPeriodLimitParam): GenericAPIResponse { - return this.requestWrapper.get('v2/public/open-interest', params); - } - - getLatestBigDeal(params: SymbolLimitParam): GenericAPIResponse { - return this.requestWrapper.get('v2/public/big-deal', params); - } - - getLongShortRatio(params: SymbolPeriodLimitParam): GenericAPIResponse { - return this.requestWrapper.get('v2/public/account-ratio', params); - } - - /** - * - * Account Data Endpoints - * - */ - - getApiKeyInfo(): GenericAPIResponse { - return this.requestWrapper.get('v2/private/account/api-key'); - } - - /** - * - * Wallet Data Endpoints - * - */ - - getWalletBalance(params?: Partial): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/balance', params) - } - - getWalletFundRecords(params?: WalletFundRecordsReq): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/fund/records', params); - } - - getWithdrawRecords(params: WithdrawRecordsReq): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/withdraw/list', params); - } - - getAssetExchangeRecords(params?: AssetExchangeRecordsReq): GenericAPIResponse { - return this.requestWrapper.get('v2/private/exchange-order/list', params); - } - - /** - * - * API Data Endpoints - * - */ - - getServerTime(): GenericAPIResponse { - return this.requestWrapper.get('v2/public/time'); - } - - getApiAnnouncements(): GenericAPIResponse { - return this.requestWrapper.get('v2/public/announcement'); - } - - async getTimeOffset(): Promise { - const start = Date.now(); - return this.getServerTime().then(result => { - const end = Date.now(); - return Math.ceil((result.time_now * 1000) - end + ((end - start) / 2)); - }); - } -} diff --git a/src/spot-client.ts b/src/spot-client.ts index 4c8c8a5..4a9b266 100644 --- a/src/spot-client.ts +++ b/src/spot-client.ts @@ -1,8 +1,13 @@ import { AxiosRequestConfig } from 'axios'; import { KlineInterval } from './types/shared'; -import { NewSpotOrder, OrderSide, OrderTypeSpot, SpotOrderQueryById } from './types/spot'; +import { + NewSpotOrder, + OrderSide, + OrderTypeSpot, + SpotOrderQueryById, +} from './types/spot'; import BaseRestClient from './util/BaseRestClient'; -import { GenericAPIResponse, getRestBaseUrl, RestClientOptions } from './util/requestUtils'; +import { getRestBaseUrl, RestClientOptions } from './util/requestUtils'; import RequestWrapper from './util/requestWrapper'; export class SpotClient extends BaseRestClient { @@ -24,19 +29,22 @@ export class SpotClient extends BaseRestClient { restClientOptions: RestClientOptions = {}, requestOptions: AxiosRequestConfig = {} ) { - super(key, secret, getRestBaseUrl(useLivenet, restClientOptions), restClientOptions, requestOptions); + super( + key, + secret, + getRestBaseUrl(useLivenet, restClientOptions), + restClientOptions, + requestOptions + ); - // this.requestWrapper = new RequestWrapper( - // key, - // secret, - // getRestBaseUrl(useLivenet, restClientOptions), - // restClientOptions, - // requestOptions - // ); return this; } - async getServerTime(urlKeyOverride?: string): Promise { + fetchServerTime(): Promise { + return this.getServerTime(); + } + + async getServerTime(): Promise { const result = await this.get('/spot/v1/time'); return result.serverTime; } @@ -45,7 +53,7 @@ export class SpotClient extends BaseRestClient { * * Market Data Endpoints * - **/ + **/ getSymbols() { return this.get('/spot/v1/symbols'); @@ -53,7 +61,8 @@ export class SpotClient extends BaseRestClient { getOrderBook(symbol: string, limit?: number) { return this.get('/spot/quote/v1/depth', { - symbol, limit + symbol, + limit, }); } @@ -72,7 +81,13 @@ export class SpotClient extends BaseRestClient { }); } - getCandles(symbol: string, interval: KlineInterval, limit?: number, startTime?: number, endTime?: number) { + getCandles( + symbol: string, + interval: KlineInterval, + limit?: number, + startTime?: number, + endTime?: number + ) { return this.get('/spot/quote/v1/kline', { symbol, interval, @@ -113,9 +128,11 @@ export class SpotClient extends BaseRestClient { cancelOrderBatch(params: { symbol: string; side?: OrderSide; - orderTypes: OrderTypeSpot[] + orderTypes: OrderTypeSpot[]; }) { - const orderTypes = params.orderTypes ? params.orderTypes.join(',') : undefined; + const orderTypes = params.orderTypes + ? params.orderTypes.join(',') + : undefined; return this.deletePrivate('/spot/order/batch-cancel', { ...params, orderTypes, diff --git a/src/types/shared.ts b/src/types/shared.ts index 76e3fa7..0d38a84 100644 --- a/src/types/shared.ts +++ b/src/types/shared.ts @@ -1,4 +1,5 @@ -export type KlineInterval = '1m' +export type KlineInterval = + | '1m' | '3m' | '5m' | '15m' @@ -16,12 +17,17 @@ export type numberInString = string; export interface APIResponse { ret_code: number; - ret_msg: "OK" | string; + ret_msg: 'OK' | string; ext_code: string; ext_info: string; result: T; } +export interface APIResponseWithTime extends APIResponse { + /** UTC timestamp */ + time_now: string; +} + /** * Request Parameter Types */ @@ -116,3 +122,7 @@ export interface SymbolInfo { price_filter: PriceFilter; lot_size_filter: LotSizeFilter; } + +export interface TimeResult { + time_now: number; +} diff --git a/src/util/BaseRestClient.ts b/src/util/BaseRestClient.ts index 62db52e..e5f8782 100644 --- a/src/util/BaseRestClient.ts +++ b/src/util/BaseRestClient.ts @@ -1,7 +1,18 @@ -import axios, { AxiosError, AxiosRequestConfig, AxiosResponse, Method } from 'axios'; +import axios, { + AxiosError, + AxiosRequestConfig, + AxiosResponse, + Method, +} from 'axios'; import { signMessage } from './node-support'; -import { RestClientOptions, GenericAPIResponse, getRestBaseUrl, serializeParams, isPublicEndpoint } from './requestUtils'; +import { + RestClientOptions, + GenericAPIResponse, + getRestBaseUrl, + serializeParams, + isPublicEndpoint, +} from './requestUtils'; export default abstract class BaseRestClient { private timeOffset: number | null; @@ -12,6 +23,9 @@ export default abstract class BaseRestClient { private key: string | undefined; private secret: string | undefined; + /** Function that calls exchange API to query & resolve server time, used by time sync */ + abstract fetchServerTime(): Promise; + constructor( key: string | undefined, secret: string | undefined, @@ -28,7 +42,7 @@ export default abstract class BaseRestClient { sync_interval_ms: 3600000, // if true, we'll throw errors if any params are undefined strict_param_validation: false, - ...options + ...options, }; this.globalRequestOptions = { @@ -37,14 +51,16 @@ export default abstract class BaseRestClient { // custom request options based on axios specs - see: https://github.com/axios/axios#request-config ...requestOptions, headers: { - 'x-referer': 'bybitapinode' + 'x-referer': 'bybitapinode', }, }; this.baseUrl = baseUrl; if (key && !secret) { - throw new Error('API Key & Secret are both required for private enpoints') + throw new Error( + 'API Key & Secret are both required for private enpoints' + ); } if (this.options.disable_time_sync !== true) { @@ -79,7 +95,12 @@ export default abstract class BaseRestClient { /** * @private Make a HTTP request to a specific endpoint. Private endpoints are automatically signed. */ - private async _call(method: Method, endpoint: string, params?: any, isPublicApi?: boolean): GenericAPIResponse { + private async _call( + method: Method, + endpoint: string, + params?: any, + isPublicApi?: boolean + ): GenericAPIResponse { if (!isPublicApi) { if (!this.key || !this.secret) { throw new Error('Private endpoints require api and private keys set'); @@ -96,7 +117,7 @@ export default abstract class BaseRestClient { ...this.globalRequestOptions, url: [this.baseUrl, endpoint].join(endpoint.startsWith('/') ? '' : '/'), method: method, - json: true + json: true, }; if (method === 'GET') { @@ -105,13 +126,15 @@ export default abstract class BaseRestClient { options.data = params; } - return axios(options).then(response => { - if (response.status == 200) { - return response.data; - } + return axios(options) + .then((response) => { + if (response.status == 200) { + return response.data; + } - throw response; - }).catch(e => this.parseException(e)); + throw response; + }) + .catch((e) => this.parseException(e)); } /** @@ -140,7 +163,7 @@ export default abstract class BaseRestClient { message: response.statusText, body: response.data, headers: response.headers, - requestOptions: this.options + requestOptions: this.options, }; } @@ -151,7 +174,7 @@ export default abstract class BaseRestClient { const params = { ...data, api_key: this.key, - timestamp: Date.now() + (this.timeOffset || 0) + timestamp: Date.now() + (this.timeOffset || 0), }; // Optional, set to 5000 by default. Increase if timestamp/recv_window errors are seen. @@ -160,7 +183,10 @@ export default abstract class BaseRestClient { } if (this.key && this.secret) { - const serializedParams = serializeParams(params, this.options.strict_param_validation); + const serializedParams = serializeParams( + params, + this.options.strict_param_validation + ); params.sign = await signMessage(serializedParams, this.secret); } @@ -179,7 +205,7 @@ export default abstract class BaseRestClient { return this.syncTimePromise; } - this.syncTimePromise = this.fetchTimeOffset().then(offset => { + this.syncTimePromise = this.fetchTimeOffset().then((offset) => { this.timeOffset = offset; this.syncTimePromise = null; }); @@ -187,22 +213,27 @@ export default abstract class BaseRestClient { return this.syncTimePromise; } - abstract getServerTime(baseUrlKeyOverride?: string): Promise; - /** * Estimate drift based on client<->server latency */ async fetchTimeOffset(): Promise { try { const start = Date.now(); - const serverTime = await this.getServerTime(); + const serverTime = await this.fetchServerTime(); + + if (!serverTime || isNaN(serverTime)) { + throw new Error( + `fetchServerTime() returned non-number: "${serverTime}" typeof(${typeof serverTime})` + ); + } + const end = Date.now(); - const avgDrift = ((end - start) / 2); + const avgDrift = (end - start) / 2; return Math.ceil(serverTime - end + avgDrift); } catch (e) { console.error('Failed to fetch get time offset: ', e); return 0; } } -}; +} diff --git a/src/util/requestUtils.ts b/src/util/requestUtils.ts index d75a0a5..6342621 100644 --- a/src/util/requestUtils.ts +++ b/src/util/requestUtils.ts @@ -19,25 +19,33 @@ export interface RestClientOptions { parse_exceptions?: boolean; } -export type GenericAPIResponse = Promise; +export type GenericAPIResponse = Promise; -export function serializeParams(params: object = {}, strict_validation = false): string { +export function serializeParams( + params: object = {}, + strict_validation = false +): string { return Object.keys(params) .sort() - .map(key => { + .map((key) => { const value = params[key]; if (strict_validation === true && typeof value === 'undefined') { - throw new Error('Failed to sign API request due to undefined parameter'); + throw new Error( + 'Failed to sign API request due to undefined parameter' + ); } return `${key}=${value}`; }) .join('&'); -}; +} -export function getRestBaseUrl(useLivenet: boolean, restInverseOptions: RestClientOptions) { +export function getRestBaseUrl( + useLivenet: boolean, + restInverseOptions: RestClientOptions +) { const baseUrlsInverse = { livenet: 'https://api.bybit.com', - testnet: 'https://api-testnet.bybit.com' + testnet: 'https://api-testnet.bybit.com', }; if (restInverseOptions.baseUrl) { @@ -50,7 +58,7 @@ export function getRestBaseUrl(useLivenet: boolean, restInverseOptions: RestClie return baseUrlsInverse.testnet; } -export function isPublicEndpoint (endpoint: string): boolean { +export function isPublicEndpoint(endpoint: string): boolean { if (endpoint.startsWith('v2/public')) { return true; } diff --git a/src/websocket-client.ts b/src/websocket-client.ts index 1398585..31b77e9 100644 --- a/src/websocket-client.ts +++ b/src/websocket-client.ts @@ -12,20 +12,20 @@ import WsStore from './util/WsStore'; const inverseEndpoints = { livenet: 'wss://stream.bybit.com/realtime', - testnet: 'wss://stream-testnet.bybit.com/realtime' + testnet: 'wss://stream-testnet.bybit.com/realtime', }; const linearEndpoints = { private: { livenet: 'wss://stream.bybit.com/realtime_private', livenet2: 'wss://stream.bytick.com/realtime_private', - testnet: 'wss://stream-testnet.bybit.com/realtime_private' + testnet: 'wss://stream-testnet.bybit.com/realtime_private', }, public: { livenet: 'wss://stream.bybit.com/realtime_public', livenet2: 'wss://stream.bytick.com/realtime_public', - testnet: 'wss://stream-testnet.bybit.com/realtime_public' - } + testnet: 'wss://stream-testnet.bybit.com/realtime_public', + }, }; const spotEndpoints = { @@ -38,8 +38,8 @@ const spotEndpoints = { livenet2: 'wss://stream.bybit.com/spot/quote/ws/v2', testnet: 'wss://stream-testnet.bybit.com/spot/quote/ws/v1', testnet2: 'wss://stream-testnet.bybit.com/spot/quote/ws/v2', - } -} + }, +}; const loggerCategory = { category: 'bybit-ws' }; @@ -54,62 +54,71 @@ export enum WsConnectionState { READY_STATE_CONNECTING, READY_STATE_CONNECTED, READY_STATE_CLOSING, - READY_STATE_RECONNECTING -}; + READY_STATE_RECONNECTING, +} export type APIMarket = 'inverse' | 'linear' | 'spot'; // Same as inverse futures -export type WsPublicInverseTopic = 'orderBookL2_25' +export type WsPublicInverseTopic = + | 'orderBookL2_25' | 'orderBookL2_200' | 'trade' | 'insurance' | 'instrument_info' | 'klineV2'; -export type WsPublicUSDTPerpTopic = 'orderBookL2_25' +export type WsPublicUSDTPerpTopic = + | 'orderBookL2_25' | 'orderBookL2_200' | 'trade' | 'insurance' | 'instrument_info' | 'kline'; -export type WsPublicSpotV1Topic = 'trade' +export type WsPublicSpotV1Topic = + | 'trade' | 'realtimes' | 'kline' | 'depth' | 'mergedDepth' | 'diffDepth'; -export type WsPublicSpotV2Topic = 'depth' +export type WsPublicSpotV2Topic = + | 'depth' | 'kline' | 'trade' | 'bookTicker' | 'realtimes'; -export type WsPublicTopics = WsPublicInverseTopic +export type WsPublicTopics = + | WsPublicInverseTopic | WsPublicUSDTPerpTopic | WsPublicSpotV1Topic | WsPublicSpotV2Topic | string; // Same as inverse futures -export type WsPrivateInverseTopic = 'position' +export type WsPrivateInverseTopic = + | 'position' | 'execution' | 'order' | 'stop_order'; -export type WsPrivateUSDTPerpTopic = 'position' +export type WsPrivateUSDTPerpTopic = + | 'position' | 'execution' | 'order' | 'stop_order' | 'wallet'; -export type WsPrivateSpotTopic = 'outboundAccountInfo' +export type WsPrivateSpotTopic = + | 'outboundAccountInfo' | 'executionReport' | 'ticketInfo'; -export type WsPrivateTopic = WsPrivateInverseTopic +export type WsPrivateTopic = + | WsPrivateInverseTopic | WsPrivateUSDTPerpTopic | WsPrivateSpotTopic | string; @@ -135,7 +144,7 @@ export interface WSClientConfigurableOptions { restOptions?: any; requestOptions?: any; wsUrl?: string; -}; +} export interface WebsocketClientOptions extends WSClientConfigurableOptions { livenet: boolean; @@ -147,8 +156,7 @@ export interface WebsocketClientOptions extends WSClientConfigurableOptions { pongTimeout: number; pingInterval: number; reconnectTimeout: number; -}; - +} export const wsKeyInverse = 'inverse'; export const wsKeyLinearPrivate = 'linearPrivate'; @@ -157,29 +165,54 @@ export const wsKeySpotPrivate = 'spotPrivate'; export const wsKeySpotPublic = 'spotPublic'; // This is used to differentiate between each of the available websocket streams (as bybit has multiple websockets) -export type WsKey = 'inverse' | 'linearPrivate' | 'linearPublic' | 'spotPrivate' | 'spotPublic'; +export type WsKey = + | 'inverse' + | 'linearPrivate' + | 'linearPublic' + | 'spotPrivate' + | 'spotPublic'; const getLinearWsKeyForTopic = (topic: string): WsKey => { - const privateLinearTopics = ['position', 'execution', 'order', 'stop_order', 'wallet']; + const privateLinearTopics = [ + 'position', + 'execution', + 'order', + 'stop_order', + 'wallet', + ]; if (privateLinearTopics.includes(topic)) { return wsKeyLinearPrivate; } return wsKeyLinearPublic; -} +}; const getSpotWsKeyForTopic = (topic: string): WsKey => { - const privateLinearTopics = ['position', 'execution', 'order', 'stop_order', 'outboundAccountInfo', 'executionReport', 'ticketInfo']; + const privateLinearTopics = [ + 'position', + 'execution', + 'order', + 'stop_order', + 'outboundAccountInfo', + 'executionReport', + 'ticketInfo', + ]; if (privateLinearTopics.includes(topic)) { return wsKeySpotPrivate; } return wsKeySpotPublic; -} +}; export declare interface WebsocketClient { - on(event: 'open' | 'reconnected', listener: ({ wsKey: WsKey, event: any }) => void): this; - on(event: 'response' | 'update' | 'error', listener: (response: any) => void): this; + on( + event: 'open' | 'reconnected', + listener: ({ wsKey: WsKey, event: any }) => void + ): this; + on( + event: 'response' | 'update' | 'error', + listener: (response: any) => void + ): this; on(event: 'reconnect' | 'close', listener: ({ wsKey: WsKey }) => void): this; } @@ -196,7 +229,10 @@ export class WebsocketClient extends EventEmitter { private options: WebsocketClientOptions; private wsStore: WsStore; - constructor(options: WSClientConfigurableOptions, logger?: typeof DefaultLogger) { + constructor( + options: WSClientConfigurableOptions, + logger?: typeof DefaultLogger + ) { super(); this.logger = logger || DefaultLogger; @@ -207,7 +243,7 @@ export class WebsocketClient extends EventEmitter { pongTimeout: 1000, pingInterval: 10000, reconnectTimeout: 500, - ...options + ...options, }; if (!this.options.market) { @@ -215,13 +251,31 @@ export class WebsocketClient extends EventEmitter { } if (this.isLinear()) { - this.restClient = new LinearClient(undefined, undefined, this.isLivenet(), this.options.restOptions, this.options.requestOptions); + this.restClient = new LinearClient( + undefined, + undefined, + this.isLivenet(), + this.options.restOptions, + this.options.requestOptions + ); } else if (this.isSpot()) { // TODO: spot client - this.restClient = new LinearClient(undefined, undefined, this.isLivenet(), this.options.restOptions, this.options.requestOptions); + this.restClient = new LinearClient( + undefined, + undefined, + this.isLivenet(), + this.options.restOptions, + this.options.requestOptions + ); this.connectPublic(); } else { - this.restClient = new InverseClient(undefined, undefined, this.isLivenet(), this.options.restOptions, this.options.requestOptions); + this.restClient = new InverseClient( + undefined, + undefined, + this.isLivenet(), + this.options.restOptions, + this.options.requestOptions + ); } } @@ -246,10 +300,9 @@ export class WebsocketClient extends EventEmitter { */ public subscribe(wsTopics: WsTopic[] | WsTopic) { const topics = Array.isArray(wsTopics) ? wsTopics : [wsTopics]; - topics.forEach(topic => this.wsStore.addTopic( - this.getWsKeyForTopic(topic), - topic - )); + topics.forEach((topic) => + this.wsStore.addTopic(this.getWsKeyForTopic(topic), topic) + ); // attempt to send subscription topic per websocket this.wsStore.getKeys().forEach((wsKey: WsKey) => { @@ -273,10 +326,9 @@ export class WebsocketClient extends EventEmitter { */ public unsubscribe(wsTopics: WsTopic[] | WsTopic) { const topics = Array.isArray(wsTopics) ? wsTopics : [wsTopics]; - topics.forEach(topic => this.wsStore.deleteTopic( - this.getWsKeyForTopic(topic), - topic - )); + topics.forEach((topic) => + this.wsStore.deleteTopic(this.getWsKeyForTopic(topic), topic) + ); this.wsStore.getKeys().forEach((wsKey: WsKey) => { // unsubscribe request only necessary if active connection exists @@ -303,7 +355,10 @@ export class WebsocketClient extends EventEmitter { } if (this.isLinear()) { - return [this.connect(wsKeyLinearPublic), this.connect(wsKeyLinearPrivate)]; + return [ + this.connect(wsKeyLinearPublic), + this.connect(wsKeyLinearPrivate), + ]; } if (this.isSpot()) { @@ -342,12 +397,18 @@ export class WebsocketClient extends EventEmitter { private async connect(wsKey: WsKey): Promise { try { if (this.wsStore.isWsOpen(wsKey)) { - this.logger.error('Refused to connect to ws with existing active connection', { ...loggerCategory, wsKey }) + this.logger.error( + 'Refused to connect to ws with existing active connection', + { ...loggerCategory, wsKey } + ); return this.wsStore.getWs(wsKey); } if (this.wsStore.isConnectionState(wsKey, READY_STATE_CONNECTING)) { - this.logger.error('Refused to connect to ws, connection attempt already active', { ...loggerCategory, wsKey }) + this.logger.error( + 'Refused to connect to ws, connection attempt already active', + { ...loggerCategory, wsKey } + ); return; } @@ -377,11 +438,17 @@ export class WebsocketClient extends EventEmitter { switch (error.message) { case 'Unexpected server response: 401': - this.logger.error(`${context} due to 401 authorization failure.`, { ...loggerCategory, wsKey }); + this.logger.error(`${context} due to 401 authorization failure.`, { + ...loggerCategory, + wsKey, + }); break; default: - this.logger.error(`{context} due to unexpected response error: ${error.msg}`, { ...loggerCategory, wsKey }); + this.logger.error( + `{context} due to unexpected response error: ${error.msg}`, + { ...loggerCategory, wsKey } + ); break; } } @@ -392,23 +459,39 @@ export class WebsocketClient extends EventEmitter { private async getAuthParams(wsKey: WsKey): Promise { const { key, secret } = this.options; - if (key && secret && wsKey !== wsKeyLinearPublic && wsKey !== wsKeySpotPublic) { - this.logger.debug('Getting auth\'d request params', { ...loggerCategory, wsKey }); + if ( + key && + secret && + wsKey !== wsKeyLinearPublic && + wsKey !== wsKeySpotPublic + ) { + this.logger.debug("Getting auth'd request params", { + ...loggerCategory, + wsKey, + }); - const timeOffset = await this.restClient.getTimeOffset(); + const timeOffset = await this.restClient.fetchTimeOffset(); const params: any = { api_key: this.options.key, - expires: (Date.now() + timeOffset + 5000) + expires: Date.now() + timeOffset + 5000, }; - params.signature = await signMessage('GET/realtime' + params.expires, secret); + params.signature = await signMessage( + 'GET/realtime' + params.expires, + secret + ); return '?' + serializeParams(params); - } else if (!key || !secret) { - this.logger.warning('Connot authenticate websocket, either api or private keys missing.', { ...loggerCategory, wsKey }); + this.logger.warning( + 'Connot authenticate websocket, either api or private keys missing.', + { ...loggerCategory, wsKey } + ); } else { - this.logger.debug('Starting public only websocket client.', { ...loggerCategory, wsKey }); + this.logger.debug('Starting public only websocket client.', { + ...loggerCategory, + wsKey, + }); } return ''; @@ -421,7 +504,10 @@ export class WebsocketClient extends EventEmitter { } setTimeout(() => { - this.logger.info('Reconnecting to websocket', { ...loggerCategory, wsKey }); + this.logger.info('Reconnecting to websocket', { + ...loggerCategory, + wsKey, + }); this.connect(wsKey); }, connectionDelayMs); } @@ -433,7 +519,10 @@ export class WebsocketClient extends EventEmitter { this.tryWsSend(wsKey, JSON.stringify({ op: 'ping' })); this.wsStore.get(wsKey, true)!.activePongTimer = setTimeout(() => { - this.logger.info('Pong timeout - closing socket to reconnect', { ...loggerCategory, wsKey }); + this.logger.info('Pong timeout - closing socket to reconnect', { + ...loggerCategory, + wsKey, + }); this.getWs(wsKey)?.close(); }, this.options.pongTimeout); } @@ -470,7 +559,7 @@ export class WebsocketClient extends EventEmitter { } const wsMessage = JSON.stringify({ op: 'subscribe', - args: topics + args: topics, }); this.tryWsSend(wsKey, wsMessage); @@ -485,7 +574,7 @@ export class WebsocketClient extends EventEmitter { } const wsMessage = JSON.stringify({ op: 'unsubscribe', - args: topics + args: topics, }); this.tryWsSend(wsKey, wsMessage); @@ -493,38 +582,62 @@ export class WebsocketClient extends EventEmitter { private tryWsSend(wsKey: WsKey, wsMessage: string) { try { - this.logger.silly(`Sending upstream ws message: `, { ...loggerCategory, wsMessage, wsKey }); + this.logger.silly(`Sending upstream ws message: `, { + ...loggerCategory, + wsMessage, + wsKey, + }); if (!wsKey) { - throw new Error('Cannot send message due to no known websocket for this wsKey'); + throw new Error( + 'Cannot send message due to no known websocket for this wsKey' + ); } const ws = this.getWs(wsKey); if (!ws) { - throw new Error(`${wsKey} socket not connected yet, call "connect(${wsKey}) first then try again when the "open" event arrives`); + throw new Error( + `${wsKey} socket not connected yet, call "connect(${wsKey}) first then try again when the "open" event arrives` + ); } ws.send(wsMessage); } catch (e) { - this.logger.error(`Failed to send WS message`, { ...loggerCategory, wsMessage, wsKey, exception: e }); + this.logger.error(`Failed to send WS message`, { + ...loggerCategory, + wsMessage, + wsKey, + exception: e, + }); } } private connectToWsUrl(url: string, wsKey: WsKey): WebSocket { - this.logger.silly(`Opening WS connection to URL: ${url}`, { ...loggerCategory, wsKey }) + this.logger.silly(`Opening WS connection to URL: ${url}`, { + ...loggerCategory, + wsKey, + }); const agent = this.options.requestOptions?.agent; const ws = new WebSocket(url, undefined, agent ? { agent } : undefined); - ws.onopen = event => this.onWsOpen(event, wsKey); - ws.onmessage = event => this.onWsMessage(event, wsKey); - ws.onerror = event => this.onWsError(event, wsKey); - ws.onclose = event => this.onWsClose(event, wsKey); + ws.onopen = (event) => this.onWsOpen(event, wsKey); + ws.onmessage = (event) => this.onWsMessage(event, wsKey); + ws.onerror = (event) => this.onWsError(event, wsKey); + ws.onclose = (event) => this.onWsClose(event, wsKey); return ws; } private onWsOpen(event, wsKey: WsKey) { if (this.wsStore.isConnectionState(wsKey, READY_STATE_CONNECTING)) { - this.logger.info('Websocket connected', { ...loggerCategory, wsKey, livenet: this.isLivenet(), linear: this.isLinear(), spot: this.isSpot() }); + this.logger.info('Websocket connected', { + ...loggerCategory, + wsKey, + livenet: this.isLivenet(), + linear: this.isLinear(), + spot: this.isSpot(), + }); this.emit('open', { wsKey, event }); - } else if (this.wsStore.isConnectionState(wsKey, READY_STATE_RECONNECTING)) { + } else if ( + this.wsStore.isConnectionState(wsKey, READY_STATE_RECONNECTING) + ) { this.logger.info('Websocket reconnected', { ...loggerCategory, wsKey }); this.emit('reconnected', { wsKey, event }); } @@ -547,16 +660,26 @@ export class WebsocketClient extends EventEmitter { // any message can clear the pong timer - wouldn't get a message if the ws dropped this.clearPongTimer(wsKey); - const msg = JSON.parse(event && event.data || event); + const msg = JSON.parse((event && event.data) || event); if ('success' in msg || msg?.pong) { this.onWsMessageResponse(msg, wsKey); } else if (msg.topic) { this.onWsMessageUpdate(msg); } else { - this.logger.warning('Got unhandled ws message', { ...loggerCategory, message: msg, event, wsKey}); + this.logger.warning('Got unhandled ws message', { + ...loggerCategory, + message: msg, + event, + wsKey, + }); } } catch (e) { - this.logger.error('Failed to parse ws event message', { ...loggerCategory, error: e, event, wsKey}) + this.logger.error('Failed to parse ws event message', { + ...loggerCategory, + error: e, + event, + wsKey, + }); } } @@ -568,7 +691,10 @@ export class WebsocketClient extends EventEmitter { } private onWsClose(event, wsKey: WsKey) { - this.logger.info('Websocket connection closed', { ...loggerCategory, wsKey}); + this.logger.info('Websocket connection closed', { + ...loggerCategory, + wsKey, + }); if (this.wsStore.getConnectionState(wsKey) !== READY_STATE_CLOSING) { this.reconnectWithDelay(wsKey, this.options.reconnectTimeout!); @@ -606,7 +732,7 @@ export class WebsocketClient extends EventEmitter { const networkKey = this.isLivenet() ? 'livenet' : 'testnet'; // TODO: reptitive - if (this.isLinear() || wsKey.startsWith('linear')){ + if (this.isLinear() || wsKey.startsWith('linear')) { if (wsKey === wsKeyLinearPublic) { return linearEndpoints.public[networkKey]; } @@ -615,11 +741,14 @@ export class WebsocketClient extends EventEmitter { return linearEndpoints.private[networkKey]; } - this.logger.error('Unhandled linear wsKey: ', { ...loggerCategory, wsKey }); + this.logger.error('Unhandled linear wsKey: ', { + ...loggerCategory, + wsKey, + }); return linearEndpoints[networkKey]; } - if (this.isSpot() || wsKey.startsWith('spot')){ + if (this.isSpot() || wsKey.startsWith('spot')) { if (wsKey === wsKeySpotPublic) { return spotEndpoints.public[networkKey]; } @@ -641,13 +770,15 @@ export class WebsocketClient extends EventEmitter { return wsKeyInverse; } if (this.isLinear()) { - return getLinearWsKeyForTopic(topic) + return getLinearWsKeyForTopic(topic); } return getSpotWsKeyForTopic(topic); } private wrongMarketError(market: APIMarket) { - return new Error(`This WS client was instanced for the ${this.options.market} market. Make another WebsocketClient instance with "market: '${market}' to listen to spot topics`); + return new Error( + `This WS client was instanced for the ${this.options.market} market. Make another WebsocketClient instance with "market: '${market}' to listen to spot topics` + ); } // TODO: persistance for subbed topics. Look at ftx-api implementation. @@ -656,14 +787,17 @@ export class WebsocketClient extends EventEmitter { throw this.wrongMarketError('spot'); } - return this.tryWsSend(wsKeySpotPublic, JSON.stringify({ - topic: 'trade', - event: 'sub', - symbol, - params: { - binary: !!binary, - } - })); + return this.tryWsSend( + wsKeySpotPublic, + JSON.stringify({ + topic: 'trade', + event: 'sub', + symbol, + params: { + binary: !!binary, + }, + }) + ); } public subscribePublicSpotTradingPair(symbol: string, binary?: boolean) { @@ -671,35 +805,50 @@ export class WebsocketClient extends EventEmitter { throw this.wrongMarketError('spot'); } - return this.tryWsSend(wsKeySpotPublic, JSON.stringify({ - symbol, - topic: 'realtimes', - event: 'sub', - params: { - binary: !!binary, - }, - })); + return this.tryWsSend( + wsKeySpotPublic, + JSON.stringify({ + symbol, + topic: 'realtimes', + event: 'sub', + params: { + binary: !!binary, + }, + }) + ); } - public subscribePublicSpotV1Kline(symbol: string, candleSize: KlineInterval, binary?: boolean) { + public subscribePublicSpotV1Kline( + symbol: string, + candleSize: KlineInterval, + binary?: boolean + ) { if (!this.isSpot()) { throw this.wrongMarketError('spot'); } - return this.tryWsSend(wsKeySpotPublic, JSON.stringify({ - symbol, - topic: 'kline_' + candleSize, - event: 'sub', - params: { - binary: !!binary, - }, - })); + return this.tryWsSend( + wsKeySpotPublic, + JSON.stringify({ + symbol, + topic: 'kline_' + candleSize, + event: 'sub', + params: { + binary: !!binary, + }, + }) + ); } //ws.send('{"symbol":"BTCUSDT","topic":"depth","event":"sub","params":{"binary":false}}'); //ws.send('{"symbol":"BTCUSDT","topic":"mergedDepth","event":"sub","params":{"binary":false,"dumpScale":1}}'); //ws.send('{"symbol":"BTCUSDT","topic":"diffDepth","event":"sub","params":{"binary":false}}'); - public subscribePublicSpotOrderbook(symbol: string, depth: 'full' | 'merge' | 'delta', dumpScale?: number, binary?: boolean) { + public subscribePublicSpotOrderbook( + symbol: string, + depth: 'full' | 'merge' | 'delta', + dumpScale?: number, + binary?: boolean + ) { if (!this.isSpot()) { throw this.wrongMarketError('spot'); } @@ -709,7 +858,7 @@ export class WebsocketClient extends EventEmitter { case 'full': { topic = 'depth'; break; - }; + } case 'merge': { topic = 'mergedDepth'; if (!dumpScale) { @@ -736,5 +885,4 @@ export class WebsocketClient extends EventEmitter { } return this.tryWsSend(wsKeySpotPublic, JSON.stringify(msg)); } - -}; +} diff --git a/test/inverse/public.test.ts b/test/inverse/public.test.ts index 9139d0d..15eb147 100644 --- a/test/inverse/public.test.ts +++ b/test/inverse/public.test.ts @@ -1,66 +1,96 @@ -import { InverseClient } from "../../src/inverse-client"; -import { notAuthenticatedError, successResponseList, successResponseObject } from "../response.util"; +import { InverseClient } from '../../src/inverse-client'; +import { + notAuthenticatedError, + successResponseList, + successResponseObject, +} from '../response.util'; describe('Public Inverse REST API Endpoints', () => { const useLivenet = true; - const api = new InverseClient(undefined, undefined, useLivenet, { disable_time_sync: true }); + const api = new InverseClient(undefined, undefined, useLivenet, { + disable_time_sync: true, + }); const symbol = 'BTCUSD'; const interval = '15'; - const timestampOneHourAgo = (new Date().getTime() / 1000) - (1000 * 60 * 60); + const timestampOneHourAgo = new Date().getTime() / 1000 - 1000 * 60 * 60; const from = Number(timestampOneHourAgo.toFixed(0)); describe('Inverse only endpoints', () => { it('should throw for unauthenticated private calls', async () => { - expect(() => api.getPosition()).rejects.toMatchObject(notAuthenticatedError()); - }); - - it('getKline()', async () => { - expect( - await api.getKline({ symbol, interval, from }) - ).toMatchObject(successResponseList()); - }); - - it('getTrades()', async () => { - expect(await api.getTrades({ symbol })).toMatchObject(successResponseList()); - }); - - it('getIndexPriceKline()', async () => { - expect(await api.getIndexPriceKline({ symbol, interval, from })).toMatchObject(successResponseList()); - }); - - it('getPremiumIndexKline()', async () => { - expect(await api.getPremiumIndexKline({ symbol, interval, from })).toMatchObject(successResponseList()); - }); - - it('getLastFundingRate()', async () => { - expect(await api.getLastFundingRate({ symbol })).toMatchObject(successResponseObject()); - }); - }); - - describe('Shared endpoints', () => { - it('should throw for unauthenticated private calls', async () => { - expect(() => api.getApiKeyInfo()).rejects.toMatchObject(notAuthenticatedError()); + expect(() => api.getPosition()).rejects.toMatchObject( + notAuthenticatedError() + ); + expect(() => api.getApiKeyInfo()).rejects.toMatchObject( + notAuthenticatedError() + ); }); it('getOrderBook()', async () => { - expect(await api.getOrderBook({ symbol })).toMatchObject(successResponseList()); + expect(await api.getOrderBook({ symbol })).toMatchObject( + successResponseList() + ); + }); + + it('getKline()', async () => { + expect(await api.getKline({ symbol, interval, from })).toMatchObject( + successResponseList() + ); }); it('getTickers()', async () => { expect(await api.getTickers()).toMatchObject(successResponseList()); }); + it('getTrades()', async () => { + expect(await api.getTrades({ symbol })).toMatchObject( + successResponseList() + ); + }); + it('getSymbols()', async () => { expect(await api.getSymbols()).toMatchObject(successResponseList()); }); + it('getMarkPriceKline()', async () => { + expect( + await api.getMarkPriceKline({ symbol, interval, from }) + ).toMatchObject(successResponseList()); + }); + + it('getIndexPriceKline()', async () => { + expect( + await api.getIndexPriceKline({ symbol, interval, from }) + ).toMatchObject(successResponseList()); + }); + + it('getPremiumIndexKline()', async () => { + expect( + await api.getPremiumIndexKline({ symbol, interval, from }) + ).toMatchObject(successResponseList()); + }); + + // + // + // + // + // + // + + it('getLastFundingRate()', async () => { + expect(await api.getLastFundingRate({ symbol })).toMatchObject( + successResponseObject() + ); + }); + it('getServerTime()', async () => { expect(await api.getServerTime()).toMatchObject(successResponseObject()); }); it('getApiAnnouncements()', async () => { - expect(await api.getApiAnnouncements()).toMatchObject(successResponseList()); + expect(await api.getApiAnnouncements()).toMatchObject( + successResponseList() + ); }); }); }); From 603a07ec852d216fd3abc6ee839e0161d1942f73 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 5 May 2022 21:28:36 +0100 Subject: [PATCH 02/24] rm note --- test/inverse/public.test.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/inverse/public.test.ts b/test/inverse/public.test.ts index 15eb147..7ff235c 100644 --- a/test/inverse/public.test.ts +++ b/test/inverse/public.test.ts @@ -70,13 +70,6 @@ describe('Public Inverse REST API Endpoints', () => { ).toMatchObject(successResponseList()); }); - // - // - // - // - // - // - it('getLastFundingRate()', async () => { expect(await api.getLastFundingRate({ symbol })).toMatchObject( successResponseObject() From 784555cf9f76ba3bd1b7d8b0e741a61e7e9ec147 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 5 May 2022 21:46:58 +0100 Subject: [PATCH 03/24] cleaned public inverse futures endpoints & expanded tests --- src/inverse-client.ts | 13 ++-- src/inverse-futures-client.ts | 88 ++++++++++++++------------ src/types/shared.ts | 4 -- test/inverse-futures/public.test.ts | 97 ++++++++++++++++++----------- test/inverse/public.test.ts | 4 ++ 5 files changed, 123 insertions(+), 83 deletions(-) diff --git a/src/inverse-client.ts b/src/inverse-client.ts index 340e596..822400a 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -16,7 +16,6 @@ import { SymbolLimitParam, SymbolParam, SymbolPeriodLimitParam, - TimeResult, WalletFundRecordsReq, WithdrawRecordsReq, } from './types/shared'; @@ -121,15 +120,21 @@ export class InverseClient extends BaseRestClient { * */ - getOpenInterest(params: SymbolPeriodLimitParam): GenericAPIResponse { + getOpenInterest( + params: SymbolPeriodLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/open-interest', params); } - getLatestBigDeal(params: SymbolLimitParam): GenericAPIResponse { + getLatestBigDeal( + params: SymbolLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/big-deal', params); } - getLongShortRatio(params: SymbolPeriodLimitParam): GenericAPIResponse { + getLongShortRatio( + params: SymbolPeriodLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/account-ratio', params); } diff --git a/src/inverse-futures-client.ts b/src/inverse-futures-client.ts index fc33195..cd6c073 100644 --- a/src/inverse-futures-client.ts +++ b/src/inverse-futures-client.ts @@ -7,6 +7,7 @@ import { import RequestWrapper from './util/requestWrapper'; import { APIResponse, + APIResponseWithTime, AssetExchangeRecordsReq, CoinParam, SymbolFromLimitParam, @@ -15,7 +16,6 @@ import { SymbolLimitParam, SymbolParam, SymbolPeriodLimitParam, - TimeResult, WalletFundRecordsReq, WithdrawRecordsReq, } from './types/shared'; @@ -60,7 +60,7 @@ export class InverseFuturesClient extends BaseRestClient { async fetchServerTime(): Promise { const res = await this.getServerTime(); - return res.time_now; + return Number(res.time_now); } /** @@ -69,36 +69,75 @@ export class InverseFuturesClient extends BaseRestClient { * */ - getOrderBook(params: SymbolParam): GenericAPIResponse { + getOrderBook(params: SymbolParam): Promise> { return this.requestWrapper.get('v2/public/orderBook/L2', params); } + getKline( + params: SymbolIntervalFromLimitParam + ): Promise> { + return this.requestWrapper.get('v2/public/kline/list', params); + } + /** * Get latest information for symbol */ - getTickers(params?: Partial): GenericAPIResponse { + getTickers( + params?: Partial + ): Promise> { return this.requestWrapper.get('v2/public/tickers', params); } - getSymbols(): Promise> { + /** + * Public trading records + */ + getTrades(params: SymbolLimitParam): Promise> { + return this.requestWrapper.get('v2/public/trading-records', params); + } + + getSymbols(): Promise> { return this.requestWrapper.get('v2/public/symbols'); } + getMarkPriceKline( + params: SymbolIntervalFromLimitParam + ): Promise> { + return this.requestWrapper.get('v2/public/mark-price-kline', params); + } + + getIndexPriceKline( + params: SymbolIntervalFromLimitParam + ): Promise> { + return this.requestWrapper.get('v2/public/index-price-kline', params); + } + + getPremiumIndexKline( + params: SymbolIntervalFromLimitParam + ): Promise> { + return this.requestWrapper.get('v2/public/premium-index-kline', params); + } + /** * * Market Data : Advanced * */ - getOpenInterest(params: SymbolPeriodLimitParam): GenericAPIResponse { + getOpenInterest( + params: SymbolPeriodLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/open-interest', params); } - getLatestBigDeal(params: SymbolLimitParam): GenericAPIResponse { + getLatestBigDeal( + params: SymbolLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/big-deal', params); } - getLongShortRatio(params: SymbolPeriodLimitParam): GenericAPIResponse { + getLongShortRatio( + params: SymbolPeriodLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/account-ratio', params); } @@ -142,7 +181,7 @@ export class InverseFuturesClient extends BaseRestClient { * */ - getServerTime(): GenericAPIResponse { + getServerTime(): Promise> { return this.requestWrapper.get('v2/public/time'); } @@ -150,37 +189,6 @@ export class InverseFuturesClient extends BaseRestClient { return this.requestWrapper.get('v2/public/announcement'); } - /** - * - * Market Data Endpoints - * Note: These are currently the same as the inverse client - */ - - getKline(params: SymbolIntervalFromLimitParam): GenericAPIResponse { - return this.requestWrapper.get('v2/public/kline/list', params); - } - - /** - * Public trading records - */ - getTrades(params: SymbolFromLimitParam): GenericAPIResponse { - return this.requestWrapper.get('v2/public/trading-records', params); - } - - getMarkPriceKline(params: SymbolIntervalFromLimitParam): GenericAPIResponse { - return this.requestWrapper.get('v2/public/mark-price-kline', params); - } - - getIndexPriceKline(params: SymbolIntervalFromLimitParam): GenericAPIResponse { - return this.requestWrapper.get('v2/public/index-price-kline', params); - } - - getPremiumIndexKline( - params: SymbolIntervalFromLimitParam - ): GenericAPIResponse { - return this.requestWrapper.get('v2/public/premium-index-kline', params); - } - /** * * Account Data Endpoints diff --git a/src/types/shared.ts b/src/types/shared.ts index 0d38a84..68baf69 100644 --- a/src/types/shared.ts +++ b/src/types/shared.ts @@ -122,7 +122,3 @@ export interface SymbolInfo { price_filter: PriceFilter; lot_size_filter: LotSizeFilter; } - -export interface TimeResult { - time_now: number; -} diff --git a/test/inverse-futures/public.test.ts b/test/inverse-futures/public.test.ts index 213701c..5a99aa4 100644 --- a/test/inverse-futures/public.test.ts +++ b/test/inverse-futures/public.test.ts @@ -1,66 +1,93 @@ -import { InverseFuturesClient } from "../../src/inverse-futures-client"; -import { notAuthenticatedError, successResponseList, successResponseObject } from "../response.util"; +import { InverseFuturesClient } from '../../src/inverse-futures-client'; +import { + notAuthenticatedError, + successResponseList, + successResponseObject, +} from '../response.util'; describe('Public Inverse Futures REST API Endpoints', () => { const useLivenet = true; - const api = new InverseFuturesClient(undefined, undefined, useLivenet, { disable_time_sync: true }); + const api = new InverseFuturesClient(undefined, undefined, useLivenet, { + disable_time_sync: true, + }); const symbol = 'BTCUSD'; const interval = '15'; - const timestampOneHourAgo = (new Date().getTime() / 1000) - (1000 * 60 * 60); + const timestampOneHourAgo = new Date().getTime() / 1000 - 1000 * 60 * 60; const from = Number(timestampOneHourAgo.toFixed(0)); describe('Inverse-Futures only endpoints', () => { it('should throw for unauthenticated private calls', async () => { - expect(() => api.getPosition()).rejects.toMatchObject(notAuthenticatedError()); - }); - - it('getKline()', async () => { - expect( - await api.getKline({ symbol, interval, from }) - ).toMatchObject(successResponseList()); - }); - - it('getTrades()', async () => { - expect(await api.getTrades({ symbol })).toMatchObject(successResponseList()); - }); - - it('getIndexPriceKline()', async () => { - expect(await api.getIndexPriceKline({ symbol, interval, from })).toMatchObject(successResponseList()); - }); - - it('getPremiumIndexKline()', async () => { - expect(await api.getPremiumIndexKline({ symbol, interval, from })).toMatchObject(successResponseList()); - }); - - it('getLastFundingRate()', async () => { - expect(await api.getLastFundingRate({ symbol })).toMatchObject(successResponseObject()); - }); - }); - - describe('Shared endpoints', () => { - it('should throw for unauthenticated private calls', async () => { - expect(() => api.getApiKeyInfo()).rejects.toMatchObject(notAuthenticatedError()); + expect(() => api.getPosition()).rejects.toMatchObject( + notAuthenticatedError() + ); + expect(() => api.getApiKeyInfo()).rejects.toMatchObject( + notAuthenticatedError() + ); }); it('getOrderBook()', async () => { - expect(await api.getOrderBook({ symbol })).toMatchObject(successResponseList()); + expect(await api.getOrderBook({ symbol })).toMatchObject( + successResponseList() + ); + }); + + it('getKline()', async () => { + expect(await api.getKline({ symbol, interval, from })).toMatchObject( + successResponseList() + ); }); it('getTickers()', async () => { expect(await api.getTickers()).toMatchObject(successResponseList()); }); + it('getTrades()', async () => { + expect(await api.getTrades({ symbol })).toMatchObject( + successResponseList() + ); + }); + it('getSymbols()', async () => { expect(await api.getSymbols()).toMatchObject(successResponseList()); }); + it('getMarkPriceKline()', async () => { + expect( + await api.getMarkPriceKline({ symbol, interval, from }) + ).toMatchObject(successResponseList()); + }); + + it('getIndexPriceKline()', async () => { + expect( + await api.getIndexPriceKline({ symbol, interval, from }) + ).toMatchObject(successResponseList()); + }); + + it('getPremiumIndexKline()', async () => { + expect( + await api.getPremiumIndexKline({ symbol, interval, from }) + ).toMatchObject(successResponseList()); + }); + + it('getLastFundingRate()', async () => { + expect(await api.getLastFundingRate({ symbol })).toMatchObject( + successResponseObject() + ); + }); + it('getServerTime()', async () => { expect(await api.getServerTime()).toMatchObject(successResponseObject()); }); + it('fetchServertime() returns number', async () => { + expect(await api.fetchServerTime()).toStrictEqual(expect.any(Number)); + }); + it('getApiAnnouncements()', async () => { - expect(await api.getApiAnnouncements()).toMatchObject(successResponseList()); + expect(await api.getApiAnnouncements()).toMatchObject( + successResponseList() + ); }); }); }); diff --git a/test/inverse/public.test.ts b/test/inverse/public.test.ts index 7ff235c..a61cebf 100644 --- a/test/inverse/public.test.ts +++ b/test/inverse/public.test.ts @@ -80,6 +80,10 @@ describe('Public Inverse REST API Endpoints', () => { expect(await api.getServerTime()).toMatchObject(successResponseObject()); }); + it('fetchServertime() returns number', async () => { + expect(await api.fetchServerTime()).toStrictEqual(expect.any(Number)); + }); + it('getApiAnnouncements()', async () => { expect(await api.getApiAnnouncements()).toMatchObject( successResponseList() From 0b8bed8faf59d4cd79ef2eb0070a3d13ee1c66b3 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 5 May 2022 22:09:45 +0100 Subject: [PATCH 04/24] migrate linear public methods + expand tests --- src/inverse-client.ts | 2 +- src/inverse-futures-client.ts | 2 +- src/linear-client.ts | 102 ++++++++++++++++++---------------- test/linear/public.test.ts | 96 ++++++++++++++++++++------------ 4 files changed, 118 insertions(+), 84 deletions(-) diff --git a/src/inverse-client.ts b/src/inverse-client.ts index 822400a..22eb7bd 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -52,7 +52,7 @@ export class InverseClient extends BaseRestClient { key, secret, getRestBaseUrl(useLivenet, restClientOptions), - restClientOptions, + { ...restClientOptions, disable_time_sync: true }, requestOptions ); return this; diff --git a/src/inverse-futures-client.ts b/src/inverse-futures-client.ts index cd6c073..7a0b1e1 100644 --- a/src/inverse-futures-client.ts +++ b/src/inverse-futures-client.ts @@ -52,7 +52,7 @@ export class InverseFuturesClient extends BaseRestClient { key, secret, getRestBaseUrl(useLivenet, restClientOptions), - restClientOptions, + { ...restClientOptions, disable_time_sync: true }, requestOptions ); return this; diff --git a/src/linear-client.ts b/src/linear-client.ts index 898a3e8..9f731c8 100644 --- a/src/linear-client.ts +++ b/src/linear-client.ts @@ -7,6 +7,7 @@ import { import RequestWrapper from './util/requestWrapper'; import { APIResponse, + APIResponseWithTime, AssetExchangeRecordsReq, CoinParam, SymbolInfo, @@ -14,7 +15,6 @@ import { SymbolLimitParam, SymbolParam, SymbolPeriodLimitParam, - TimeResult, WalletFundRecordsReq, WithdrawRecordsReq, } from './types/shared'; @@ -53,7 +53,7 @@ export class LinearClient extends BaseRestClient { key, secret, getRestBaseUrl(useLivenet, restClientOptions), - restClientOptions, + { ...restClientOptions, disable_time_sync: true }, requestOptions ); return this; @@ -61,7 +61,7 @@ export class LinearClient extends BaseRestClient { async fetchServerTime(): Promise { const timeRes = await this.getServerTime(); - return timeRes.time_now; + return Number(timeRes.time_now); } /** @@ -70,36 +70,82 @@ export class LinearClient extends BaseRestClient { * */ - getOrderBook(params: SymbolParam): GenericAPIResponse { + getOrderBook(params: SymbolParam): Promise> { return this.requestWrapper.get('v2/public/orderBook/L2', params); } + getKline( + params: SymbolIntervalFromLimitParam + ): Promise> { + return this.requestWrapper.get('public/linear/kline', params); + } + /** * Get latest information for symbol */ - getTickers(params?: Partial): GenericAPIResponse { + getTickers( + params?: Partial + ): Promise> { return this.requestWrapper.get('v2/public/tickers', params); } + getTrades(params: SymbolLimitParam): Promise> { + return this.requestWrapper.get( + 'public/linear/recent-trading-records', + params + ); + } + getSymbols(): Promise> { return this.requestWrapper.get('v2/public/symbols'); } + getLastFundingRate(params: SymbolParam): Promise> { + return this.requestWrapper.get( + 'public/linear/funding/prev-funding-rate', + params + ); + } + + getMarkPriceKline( + params: SymbolIntervalFromLimitParam + ): Promise> { + return this.requestWrapper.get('public/linear/mark-price-kline', params); + } + + getIndexPriceKline( + params: SymbolIntervalFromLimitParam + ): Promise> { + return this.requestWrapper.get('public/linear/index-price-kline', params); + } + + getPremiumIndexKline( + params: SymbolIntervalFromLimitParam + ): Promise> { + return this.requestWrapper.get('public/linear/premium-index-kline', params); + } + /** * * Market Data : Advanced * */ - getOpenInterest(params: SymbolPeriodLimitParam): GenericAPIResponse { + getOpenInterest( + params: SymbolPeriodLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/open-interest', params); } - getLatestBigDeal(params: SymbolLimitParam): GenericAPIResponse { + getLatestBigDeal( + params: SymbolLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/big-deal', params); } - getLongShortRatio(params: SymbolPeriodLimitParam): GenericAPIResponse { + getLongShortRatio( + params: SymbolPeriodLimitParam + ): Promise> { return this.requestWrapper.get('v2/public/account-ratio', params); } @@ -143,7 +189,7 @@ export class LinearClient extends BaseRestClient { * */ - getServerTime(): GenericAPIResponse { + getServerTime(): Promise> { return this.requestWrapper.get('v2/public/time'); } @@ -151,44 +197,6 @@ export class LinearClient extends BaseRestClient { return this.requestWrapper.get('v2/public/announcement'); } - /** - * - * Market Data Endpoints - * - */ - - getKline(params: SymbolIntervalFromLimitParam): GenericAPIResponse { - return this.requestWrapper.get('public/linear/kline', params); - } - - getTrades(params: SymbolLimitParam): GenericAPIResponse { - return this.requestWrapper.get( - 'public/linear/recent-trading-records', - params - ); - } - - getLastFundingRate(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get( - 'public/linear/funding/prev-funding-rate', - params - ); - } - - getMarkPriceKline(params: SymbolIntervalFromLimitParam): GenericAPIResponse { - return this.requestWrapper.get('public/linear/mark-price-kline', params); - } - - getIndexPriceKline(params: SymbolIntervalFromLimitParam): GenericAPIResponse { - return this.requestWrapper.get('public/linear/index-price-kline', params); - } - - getPremiumIndexKline( - params: SymbolIntervalFromLimitParam - ): GenericAPIResponse { - return this.requestWrapper.get('public/linear/premium-index-kline', params); - } - /** * * Account Data Endpoints diff --git a/test/linear/public.test.ts b/test/linear/public.test.ts index 7cf195a..6b6cadd 100644 --- a/test/linear/public.test.ts +++ b/test/linear/public.test.ts @@ -1,66 +1,92 @@ -import { LinearClient } from "../../src/linear-client"; -import { notAuthenticatedError, successResponseList, successResponseObject } from "../response.util"; +import { LinearClient } from '../../src/linear-client'; +import { + notAuthenticatedError, + successResponseList, + successResponseObject, +} from '../response.util'; describe('Public Linear REST API Endpoints', () => { const useLivenet = true; - const api = new LinearClient(undefined, undefined, useLivenet, { disable_time_sync: true }); + const api = new LinearClient(undefined, undefined, useLivenet, { + disable_time_sync: true, + }); const symbol = 'BTCUSDT'; const interval = '15'; - const timestampOneHourAgo = (new Date().getTime() / 1000) - (1000 * 60 * 60); + const timestampOneHourAgo = new Date().getTime() / 1000 - 1000 * 60 * 60; const from = Number(timestampOneHourAgo.toFixed(0)); describe('Linear only endpoints', () => { it('should throw for unauthenticated private calls', async () => { - expect(() => api.getPosition()).rejects.toMatchObject(notAuthenticatedError()); - }); - - it('getKline()', async () => { - expect( - await api.getKline({ symbol, interval, from }) - ).toMatchObject(successResponseList()); - }); - - it('getTrades()', async () => { - expect(await api.getTrades({ symbol })).toMatchObject(successResponseList()); - }); - - it('getIndexPriceKline()', async () => { - expect(await api.getIndexPriceKline({ symbol, interval, from })).toMatchObject(successResponseList()); - }); - - it('getPremiumIndexKline()', async () => { - expect(await api.getPremiumIndexKline({ symbol, interval, from })).toMatchObject(successResponseList()); - }); - - it('getLastFundingRate()', async () => { - expect(await api.getLastFundingRate({ symbol })).toMatchObject(successResponseObject()); - }); - }); - - describe('Shared endpoints', () => { - it('should throw for unauthenticated private calls', async () => { - expect(() => api.getApiKeyInfo()).rejects.toMatchObject(notAuthenticatedError()); + expect(() => api.getPosition()).rejects.toMatchObject( + notAuthenticatedError() + ); + expect(() => api.getApiKeyInfo()).rejects.toMatchObject( + notAuthenticatedError() + ); }); it('getOrderBook()', async () => { - expect(await api.getOrderBook({ symbol })).toMatchObject(successResponseList()); + expect(await api.getOrderBook({ symbol })).toMatchObject( + successResponseList() + ); + }); + + it('getKline()', async () => { + expect(await api.getKline({ symbol, interval, from })).toMatchObject( + successResponseList() + ); }); it('getTickers()', async () => { expect(await api.getTickers()).toMatchObject(successResponseList()); }); + it('getTrades()', async () => { + expect(await api.getTrades({ symbol })).toMatchObject( + successResponseList() + ); + }); it('getSymbols()', async () => { expect(await api.getSymbols()).toMatchObject(successResponseList()); }); + it('getMarkPriceKline()', async () => { + expect( + await api.getMarkPriceKline({ symbol, interval, from }) + ).toMatchObject(successResponseList()); + }); + + it('getIndexPriceKline()', async () => { + expect( + await api.getIndexPriceKline({ symbol, interval, from }) + ).toMatchObject(successResponseList()); + }); + + it('getPremiumIndexKline()', async () => { + expect( + await api.getPremiumIndexKline({ symbol, interval, from }) + ).toMatchObject(successResponseList()); + }); + + it('getLastFundingRate()', async () => { + expect(await api.getLastFundingRate({ symbol })).toMatchObject( + successResponseObject() + ); + }); + it('getServerTime()', async () => { expect(await api.getServerTime()).toMatchObject(successResponseObject()); }); + it('fetchServertime() returns number', async () => { + expect(await api.fetchServerTime()).toStrictEqual(expect.any(Number)); + }); + it('getApiAnnouncements()', async () => { - expect(await api.getApiAnnouncements()).toMatchObject(successResponseList()); + expect(await api.getApiAnnouncements()).toMatchObject( + successResponseList() + ); }); }); }); From a7aaedac41436fd4e0273bcbe6a27dd2698db6b9 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 5 May 2022 22:45:38 +0100 Subject: [PATCH 05/24] bootstrap public spot test --- src/spot-client.ts | 45 ++++++++++++++++++++++++++++++++-------- src/types/shared.ts | 6 +++--- src/types/spot.ts | 17 +++++++++++++++ src/util/WsStore.ts | 33 +++++++++++++++++++---------- test/response.util.ts | 29 ++++++++++---------------- test/spot/public.test.ts | 37 +++++++++++++++++++++++++++++++++ 6 files changed, 126 insertions(+), 41 deletions(-) create mode 100644 test/spot/public.test.ts diff --git a/src/spot-client.ts b/src/spot-client.ts index 4a9b266..647ac47 100644 --- a/src/spot-client.ts +++ b/src/spot-client.ts @@ -1,10 +1,11 @@ import { AxiosRequestConfig } from 'axios'; -import { KlineInterval } from './types/shared'; +import { APIResponse, KlineInterval } from './types/shared'; import { NewSpotOrder, OrderSide, OrderTypeSpot, SpotOrderQueryById, + SpotSymbolInfo, } from './types/spot'; import BaseRestClient from './util/BaseRestClient'; import { getRestBaseUrl, RestClientOptions } from './util/requestUtils'; @@ -55,18 +56,22 @@ export class SpotClient extends BaseRestClient { * **/ - getSymbols() { + getSymbols(): Promise> { return this.get('/spot/v1/symbols'); } - getOrderBook(symbol: string, limit?: number) { + getOrderBook(symbol: string, limit?: number): Promise> { return this.get('/spot/quote/v1/depth', { symbol, limit, }); } - getMergedOrderBook(symbol: string, scale?: number, limit?: number) { + getMergedOrderBook( + symbol: string, + scale?: number, + limit?: number + ): Promise> { return this.get('/spot/quote/v1/depth/merged', { symbol, scale, @@ -74,7 +79,7 @@ export class SpotClient extends BaseRestClient { }); } - getTrades(symbol: string, limit?: number) { + getTrades(symbol: string, limit?: number): Promise> { return this.get('/spot/v1/trades', { symbol, limit, @@ -87,7 +92,7 @@ export class SpotClient extends BaseRestClient { limit?: number, startTime?: number, endTime?: number - ) { + ): Promise> { return this.get('/spot/quote/v1/kline', { symbol, interval, @@ -97,15 +102,15 @@ export class SpotClient extends BaseRestClient { }); } - get24hrTicker(symbol?: string) { + get24hrTicker(symbol?: string): Promise> { return this.get('/spot/quote/v1/ticker/24hr', { symbol }); } - getLastTradedPrice(symbol?: string) { + getLastTradedPrice(symbol?: string): Promise> { return this.get('/spot/quote/v1/ticker/price', { symbol }); } - getBestBidAskPrice(symbol?: string) { + getBestBidAskPrice(symbol?: string): Promise> { return this.get('/spot/quote/v1/ticker/book_ticker', { symbol }); } @@ -171,4 +176,26 @@ export class SpotClient extends BaseRestClient { getBalances() { return this.getPrivate('/spot/v1/account'); } + + /** + * Leveraged Token Endpoints + */ + + getLeveragedTokenAssetInfo( + leverageTokenCode: string, + timestamp?: number + ): Promise> { + return this.get('/spot/lt/v1/info', { + ltCode: leverageTokenCode, + timestamp, + }); + } + + getLeveragedTokenMarketInfo( + leverageTokenCode: string + ): Promise> { + return this.get('/spot/lt/v1/reference', { + ltCode: leverageTokenCode, + }); + } } diff --git a/src/types/shared.ts b/src/types/shared.ts index 68baf69..7bc7e9d 100644 --- a/src/types/shared.ts +++ b/src/types/shared.ts @@ -18,14 +18,14 @@ export type numberInString = string; export interface APIResponse { ret_code: number; ret_msg: 'OK' | string; - ext_code: string; - ext_info: string; + ext_code: string | null; + ext_info: string | null; result: T; } export interface APIResponseWithTime extends APIResponse { /** UTC timestamp */ - time_now: string; + time_now: numberInString; } /** diff --git a/src/types/spot.ts b/src/types/spot.ts index 9e92081..a514686 100644 --- a/src/types/spot.ts +++ b/src/types/spot.ts @@ -1,3 +1,5 @@ +import { numberInString } from './shared'; + export type OrderSide = 'Buy' | 'Sell'; export type OrderTypeSpot = 'LIMIT' | 'MARKET' | 'LIMIT_MAKER'; export type OrderTimeInForce = 'GTC' | 'FOK' | 'IOC'; @@ -16,3 +18,18 @@ export interface SpotOrderQueryById { orderId?: string; orderLinkId?: string; } + +export interface SpotSymbolInfo { + name: string; + alias: string; + baseCurrency: string; + quoteCurrency: string; + basePrecision: numberInString; + quotePrecision: numberInString; + minTradeQuantity: numberInString; + minTradeAmount: numberInString; + minPricePrecision: numberInString; + maxTradeQuantity: numberInString; + maxTradeAmount: numberInString; + category: numberInString; +} diff --git a/src/util/WsStore.ts b/src/util/WsStore.ts index 8ebbd2c..995106c 100644 --- a/src/util/WsStore.ts +++ b/src/util/WsStore.ts @@ -9,14 +9,13 @@ type WsTopicList = Set; interface WsStoredState { ws?: WebSocket; connectionState?: WsConnectionState; - activePingTimer?: NodeJS.Timeout | undefined; - activePongTimer?: NodeJS.Timeout | undefined; + activePingTimer?: ReturnType | undefined; + activePongTimer?: ReturnType | undefined; subscribedTopics: WsTopicList; -}; - +} export default class WsStore { - private wsState: Record + private wsState: Record; private logger: typeof DefaultLogger; constructor(logger: typeof DefaultLogger) { @@ -40,11 +39,14 @@ export default class WsStore { create(key: string): WsStoredState | undefined { if (this.hasExistingActiveConnection(key)) { - this.logger.warning('WsStore setConnection() overwriting existing open connection: ', this.getWs(key)); + this.logger.warning( + 'WsStore setConnection() overwriting existing open connection: ', + this.getWs(key) + ); } this.wsState[key] = { subscribedTopics: new Set(), - connectionState: WsConnectionState.READY_STATE_INITIAL + connectionState: WsConnectionState.READY_STATE_INITIAL, }; return this.get(key); } @@ -52,7 +54,10 @@ export default class WsStore { delete(key: string) { if (this.hasExistingActiveConnection(key)) { const ws = this.getWs(key); - this.logger.warning('WsStore deleting state for connection still open: ', ws); + this.logger.warning( + 'WsStore deleting state for connection still open: ', + ws + ); ws?.close(); } delete this.wsState[key]; @@ -70,7 +75,10 @@ export default class WsStore { setWs(key: string, wsConnection: WebSocket): WebSocket { if (this.isWsOpen(key)) { - this.logger.warning('WsStore setConnection() overwriting existing open connection: ', this.getWs(key)); + this.logger.warning( + 'WsStore setConnection() overwriting existing open connection: ', + this.getWs(key) + ); } this.get(key, true)!.ws = wsConnection; return wsConnection; @@ -80,7 +88,10 @@ export default class WsStore { isWsOpen(key: string): boolean { const existingConnection = this.getWs(key); - return !!existingConnection && existingConnection.readyState === existingConnection.OPEN; + return ( + !!existingConnection && + existingConnection.readyState === existingConnection.OPEN + ); } getConnectionState(key: string): WsConnectionState { @@ -102,7 +113,7 @@ export default class WsStore { } getTopicsByKey(): Record { - const result = {}; + const result = {}; for (const refKey in this.wsState) { result[refKey] = this.getTopics(refKey); } diff --git a/test/response.util.ts b/test/response.util.ts index 6bc3974..312a67f 100644 --- a/test/response.util.ts +++ b/test/response.util.ts @@ -1,26 +1,19 @@ - -export function successResponseList() { +export function successResponseList(successMsg: string | null = 'OK') { return { - "ext_code": "", - "ext_info": "", - "result": expect.any(Array), - "ret_code": 0, - "ret_msg": "OK", - "time_now": expect.any(String), + result: expect.any(Array), + ret_code: 0, + ret_msg: successMsg, }; -}; +} -export function successResponseObject() { +export function successResponseObject(successMsg: string | null = 'OK') { return { - "ext_code": "", - "ext_info": "", - "result": expect.any(Object), - "ret_code": 0, - "ret_msg": "OK", - "time_now": expect.any(String), + result: expect.any(Object), + ret_code: 0, + ret_msg: successMsg, }; -}; +} export function notAuthenticatedError() { return new Error('Private endpoints require api and private keys set'); -}; +} diff --git a/test/spot/public.test.ts b/test/spot/public.test.ts new file mode 100644 index 0000000..ae8e2f3 --- /dev/null +++ b/test/spot/public.test.ts @@ -0,0 +1,37 @@ +import { SpotClient } from '../../src'; +import { + notAuthenticatedError, + successResponseList, + successResponseObject, +} from '../response.util'; + +describe('Public Spot REST API Endpoints', () => { + const useLivenet = true; + const api = new SpotClient(undefined, undefined, useLivenet, { + disable_time_sync: true, + }); + + const symbol = 'BTCUSDT'; + const interval = '15'; + const timestampOneHourAgo = new Date().getTime() / 1000 - 1000 * 60 * 60; + const from = Number(timestampOneHourAgo.toFixed(0)); + + it('should throw for unauthenticated private calls', async () => { + expect(() => api.getOpenOrders()).rejects.toMatchObject( + notAuthenticatedError() + ); + expect(() => api.getBalances()).rejects.toMatchObject( + notAuthenticatedError() + ); + }); + + it('getSymbols()', async () => { + expect(await api.getSymbols()).toMatchObject(successResponseList('')); + }); + + it('getOrderBook()', async () => { + expect(await api.getOrderBook(symbol)).toMatchObject( + successResponseObject(null) + ); + }); +}); From 44fb95ae80b2614d6f1eac6193e5ea2e219eb49b Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 5 May 2022 23:21:27 +0100 Subject: [PATCH 06/24] expand spot public tests, fix broken trades and server time endpoints --- src/spot-client.ts | 28 +++--------------------- test/spot/public.test.ts | 46 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/spot-client.ts b/src/spot-client.ts index 647ac47..f657021 100644 --- a/src/spot-client.ts +++ b/src/spot-client.ts @@ -46,8 +46,8 @@ export class SpotClient extends BaseRestClient { } async getServerTime(): Promise { - const result = await this.get('/spot/v1/time'); - return result.serverTime; + const res = await this.get('/spot/v1/time'); + return res.result.serverTime; } /** @@ -80,7 +80,7 @@ export class SpotClient extends BaseRestClient { } getTrades(symbol: string, limit?: number): Promise> { - return this.get('/spot/v1/trades', { + return this.get('/spot/quote/v1/trades', { symbol, limit, }); @@ -176,26 +176,4 @@ export class SpotClient extends BaseRestClient { getBalances() { return this.getPrivate('/spot/v1/account'); } - - /** - * Leveraged Token Endpoints - */ - - getLeveragedTokenAssetInfo( - leverageTokenCode: string, - timestamp?: number - ): Promise> { - return this.get('/spot/lt/v1/info', { - ltCode: leverageTokenCode, - timestamp, - }); - } - - getLeveragedTokenMarketInfo( - leverageTokenCode: string - ): Promise> { - return this.get('/spot/lt/v1/reference', { - ltCode: leverageTokenCode, - }); - } } diff --git a/test/spot/public.test.ts b/test/spot/public.test.ts index ae8e2f3..0aa7fb2 100644 --- a/test/spot/public.test.ts +++ b/test/spot/public.test.ts @@ -12,7 +12,7 @@ describe('Public Spot REST API Endpoints', () => { }); const symbol = 'BTCUSDT'; - const interval = '15'; + const interval = '15m'; const timestampOneHourAgo = new Date().getTime() / 1000 - 1000 * 60 * 60; const from = Number(timestampOneHourAgo.toFixed(0)); @@ -34,4 +34,48 @@ describe('Public Spot REST API Endpoints', () => { successResponseObject(null) ); }); + + it('getMergedOrderBook()', async () => { + expect(await api.getMergedOrderBook(symbol)).toMatchObject( + successResponseObject(null) + ); + }); + + it('getTrades()', async () => { + expect(await api.getTrades(symbol)).toMatchObject( + successResponseObject(null) + ); + }); + + it('getCandles()', async () => { + expect(await api.getCandles(symbol, interval)).toMatchObject( + successResponseObject(null) + ); + }); + + it('get24hrTicker()', async () => { + expect(await api.get24hrTicker()).toMatchObject( + successResponseObject(null) + ); + }); + + it('getLastTradedPrice()', async () => { + expect(await api.getLastTradedPrice()).toMatchObject( + successResponseObject(null) + ); + }); + + it('getBestBidAskPrice()', async () => { + expect(await api.getBestBidAskPrice()).toMatchObject( + successResponseObject(null) + ); + }); + + it('getServerTime()', async () => { + expect(await api.getServerTime()).toStrictEqual(expect.any(Number)); + }); + + it('fetchServertime() returns number', async () => { + expect(await api.fetchServerTime()).toStrictEqual(expect.any(Number)); + }); }); From f4e41331dba55e72c11ebe6cb3b14d945a6bb0fb Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 5 May 2022 23:39:47 +0100 Subject: [PATCH 07/24] placeholder private test. Deprecate requestWrapper public getters --- src/inverse-client.ts | 31 ++++++++++++--------------- src/inverse-futures-client.ts | 26 +++++++++++------------ test/inverse/private.test.ts | 40 +++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 30 deletions(-) create mode 100644 test/inverse/private.test.ts diff --git a/src/inverse-client.ts b/src/inverse-client.ts index 22eb7bd..222fbd5 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -70,13 +70,13 @@ export class InverseClient extends BaseRestClient { */ getOrderBook(params: SymbolParam): Promise> { - return this.requestWrapper.get('v2/public/orderBook/L2', params); + return this.get('v2/public/orderBook/L2', params); } getKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/kline/list', params); + return this.get('v2/public/kline/list', params); } /** @@ -85,33 +85,33 @@ export class InverseClient extends BaseRestClient { getTickers( params?: Partial ): Promise> { - return this.requestWrapper.get('v2/public/tickers', params); + return this.get('v2/public/tickers', params); } getTrades(params: SymbolLimitParam): Promise> { - return this.requestWrapper.get('v2/public/trading-records', params); + return this.get('v2/public/trading-records', params); } getSymbols(): Promise> { - return this.requestWrapper.get('v2/public/symbols'); + return this.get('v2/public/symbols'); } getMarkPriceKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/mark-price-kline', params); + return this.get('v2/public/mark-price-kline', params); } getIndexPriceKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/index-price-kline', params); + return this.get('v2/public/index-price-kline', params); } getPremiumIndexKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/premium-index-kline', params); + return this.get('v2/public/premium-index-kline', params); } /** @@ -123,19 +123,19 @@ export class InverseClient extends BaseRestClient { getOpenInterest( params: SymbolPeriodLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/open-interest', params); + return this.get('v2/public/open-interest', params); } getLatestBigDeal( params: SymbolLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/big-deal', params); + return this.get('v2/public/big-deal', params); } getLongShortRatio( params: SymbolPeriodLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/account-ratio', params); + return this.get('v2/public/account-ratio', params); } /** @@ -179,11 +179,11 @@ export class InverseClient extends BaseRestClient { */ getServerTime(): Promise> { - return this.requestWrapper.get('v2/public/time'); + return this.get('v2/public/time'); } getApiAnnouncements(): Promise> { - return this.requestWrapper.get('v2/public/announcement'); + return this.get('v2/public/announcement'); } /** @@ -443,10 +443,7 @@ export class InverseClient extends BaseRestClient { */ getLastFundingRate(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get( - 'v2/public/funding/prev-funding-rate', - params - ); + return this.get('v2/public/funding/prev-funding-rate', params); } getMyLastFundingFee(params: SymbolParam): GenericAPIResponse { diff --git a/src/inverse-futures-client.ts b/src/inverse-futures-client.ts index 7a0b1e1..836867c 100644 --- a/src/inverse-futures-client.ts +++ b/src/inverse-futures-client.ts @@ -70,13 +70,13 @@ export class InverseFuturesClient extends BaseRestClient { */ getOrderBook(params: SymbolParam): Promise> { - return this.requestWrapper.get('v2/public/orderBook/L2', params); + return this.get('v2/public/orderBook/L2', params); } getKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/kline/list', params); + return this.get('v2/public/kline/list', params); } /** @@ -85,36 +85,36 @@ export class InverseFuturesClient extends BaseRestClient { getTickers( params?: Partial ): Promise> { - return this.requestWrapper.get('v2/public/tickers', params); + return this.get('v2/public/tickers', params); } /** * Public trading records */ getTrades(params: SymbolLimitParam): Promise> { - return this.requestWrapper.get('v2/public/trading-records', params); + return this.get('v2/public/trading-records', params); } getSymbols(): Promise> { - return this.requestWrapper.get('v2/public/symbols'); + return this.get('v2/public/symbols'); } getMarkPriceKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/mark-price-kline', params); + return this.get('v2/public/mark-price-kline', params); } getIndexPriceKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/index-price-kline', params); + return this.get('v2/public/index-price-kline', params); } getPremiumIndexKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/premium-index-kline', params); + return this.get('v2/public/premium-index-kline', params); } /** @@ -126,19 +126,19 @@ export class InverseFuturesClient extends BaseRestClient { getOpenInterest( params: SymbolPeriodLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/open-interest', params); + return this.get('v2/public/open-interest', params); } getLatestBigDeal( params: SymbolLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/big-deal', params); + return this.get('v2/public/big-deal', params); } getLongShortRatio( params: SymbolPeriodLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/account-ratio', params); + return this.get('v2/public/account-ratio', params); } /** @@ -182,11 +182,11 @@ export class InverseFuturesClient extends BaseRestClient { */ getServerTime(): Promise> { - return this.requestWrapper.get('v2/public/time'); + return this.get('v2/public/time'); } getApiAnnouncements(): GenericAPIResponse { - return this.requestWrapper.get('v2/public/announcement'); + return this.get('v2/public/announcement'); } /** diff --git a/test/inverse/private.test.ts b/test/inverse/private.test.ts new file mode 100644 index 0000000..6932c9c --- /dev/null +++ b/test/inverse/private.test.ts @@ -0,0 +1,40 @@ +import { InverseClient } from '../../src/inverse-client'; +import { + notAuthenticatedError, + successResponseList, + successResponseObject, +} from '../response.util'; + +describe.skip('Private Inverse REST API Endpoints', () => { + const useLivenet = true; + const API_KEY = process.env.API_KEY_COM; + const API_SECRET = process.env.API_SECRET_COM; + + it('should have api credentials to test with', () => { + expect(API_KEY).toStrictEqual(expect.any(String)); + expect(API_SECRET).toStrictEqual(expect.any(String)); + }); + + const api = new InverseClient(API_KEY, API_SECRET, useLivenet, { + disable_time_sync: true, + }); + + const symbol = 'BTCUSD'; + const interval = '15'; + const timestampOneHourAgo = new Date().getTime() / 1000 - 1000 * 60 * 60; + const from = Number(timestampOneHourAgo.toFixed(0)); + + describe('Inverse only endpoints', () => { + it('getOrderBook()', async () => { + expect(await api.getOrderBook({ symbol })).toMatchObject( + successResponseList() + ); + }); + + it('getKline()', async () => { + expect(await api.getKline({ symbol, interval, from })).toMatchObject( + successResponseList() + ); + }); + }); +}); From 4ba36374ccc534a1a7d41f26c9aa86470ad3ec28 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 5 May 2022 23:42:14 +0100 Subject: [PATCH 08/24] remove requestWrapper from remaining public getter methods --- src/linear-client.ts | 36 +++++++++++++++--------------------- src/spot-client.ts | 3 --- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/linear-client.ts b/src/linear-client.ts index 9f731c8..d01636f 100644 --- a/src/linear-client.ts +++ b/src/linear-client.ts @@ -71,13 +71,13 @@ export class LinearClient extends BaseRestClient { */ getOrderBook(params: SymbolParam): Promise> { - return this.requestWrapper.get('v2/public/orderBook/L2', params); + return this.get('v2/public/orderBook/L2', params); } getKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('public/linear/kline', params); + return this.get('public/linear/kline', params); } /** @@ -86,43 +86,37 @@ export class LinearClient extends BaseRestClient { getTickers( params?: Partial ): Promise> { - return this.requestWrapper.get('v2/public/tickers', params); + return this.get('v2/public/tickers', params); } getTrades(params: SymbolLimitParam): Promise> { - return this.requestWrapper.get( - 'public/linear/recent-trading-records', - params - ); + return this.get('public/linear/recent-trading-records', params); } getSymbols(): Promise> { - return this.requestWrapper.get('v2/public/symbols'); + return this.get('v2/public/symbols'); } getLastFundingRate(params: SymbolParam): Promise> { - return this.requestWrapper.get( - 'public/linear/funding/prev-funding-rate', - params - ); + return this.get('public/linear/funding/prev-funding-rate', params); } getMarkPriceKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('public/linear/mark-price-kline', params); + return this.get('public/linear/mark-price-kline', params); } getIndexPriceKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('public/linear/index-price-kline', params); + return this.get('public/linear/index-price-kline', params); } getPremiumIndexKline( params: SymbolIntervalFromLimitParam ): Promise> { - return this.requestWrapper.get('public/linear/premium-index-kline', params); + return this.get('public/linear/premium-index-kline', params); } /** @@ -134,19 +128,19 @@ export class LinearClient extends BaseRestClient { getOpenInterest( params: SymbolPeriodLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/open-interest', params); + return this.get('v2/public/open-interest', params); } getLatestBigDeal( params: SymbolLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/big-deal', params); + return this.get('v2/public/big-deal', params); } getLongShortRatio( params: SymbolPeriodLimitParam ): Promise> { - return this.requestWrapper.get('v2/public/account-ratio', params); + return this.get('v2/public/account-ratio', params); } /** @@ -190,11 +184,11 @@ export class LinearClient extends BaseRestClient { */ getServerTime(): Promise> { - return this.requestWrapper.get('v2/public/time'); + return this.get('v2/public/time'); } getApiAnnouncements(): GenericAPIResponse { - return this.requestWrapper.get('v2/public/announcement'); + return this.get('v2/public/announcement'); } /** @@ -481,7 +475,7 @@ export class LinearClient extends BaseRestClient { */ getRiskLimitList(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get('public/linear/risk-limit', params); + return this.get('public/linear/risk-limit', params); } setRiskLimit(params: { diff --git a/src/spot-client.ts b/src/spot-client.ts index f657021..52decb8 100644 --- a/src/spot-client.ts +++ b/src/spot-client.ts @@ -9,11 +9,8 @@ import { } from './types/spot'; import BaseRestClient from './util/BaseRestClient'; import { getRestBaseUrl, RestClientOptions } from './util/requestUtils'; -import RequestWrapper from './util/requestWrapper'; export class SpotClient extends BaseRestClient { - protected requestWrapper: RequestWrapper; - /** * @public Creates an instance of the Spot REST API client. * From 749efad303de68b3b37f626b8e72d9bc574cb2c9 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 5 May 2022 23:53:28 +0100 Subject: [PATCH 09/24] add tests for private query endpoints --- src/inverse-client.ts | 31 +-------- test/inverse/private.read.test.ts | 101 ++++++++++++++++++++++++++++++ test/inverse/private.test.ts | 40 ------------ test/inverse/public.test.ts | 4 ++ 4 files changed, 108 insertions(+), 68 deletions(-) create mode 100644 test/inverse/private.read.test.ts delete mode 100644 test/inverse/private.test.ts diff --git a/src/inverse-client.ts b/src/inverse-client.ts index 222fbd5..f88842d 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -162,7 +162,7 @@ export class InverseClient extends BaseRestClient { return this.requestWrapper.get('v2/private/wallet/fund/records', params); } - getWithdrawRecords(params: WithdrawRecordsReq): GenericAPIResponse { + getWithdrawRecords(params?: WithdrawRecordsReq): GenericAPIResponse { return this.requestWrapper.get('v2/private/wallet/withdraw/list', params); } @@ -278,6 +278,7 @@ export class InverseClient extends BaseRestClient { return this.requestWrapper.post('v2/private/stop-order/create', params); } + /** get conditional order list. This may see delays, use queryConditionalOrder() for real-time queries */ getConditionalOrder(params: { symbol: string; stop_order_status?: string; @@ -323,24 +324,10 @@ export class InverseClient extends BaseRestClient { * Position */ - /** - * @deprecated use getPosition() instead - */ - getUserLeverage(): GenericAPIResponse { - return this.requestWrapper.get('user/leverage'); - } - getPosition(params?: Partial): GenericAPIResponse { return this.requestWrapper.get('v2/private/position/list', params); } - /** - * @deprecated use getPosition() instead - */ - getPositions(): GenericAPIResponse { - return this.requestWrapper.get('position/list'); - } - changePositionMargin(params: { symbol: string; margin: string; @@ -371,13 +358,6 @@ export class InverseClient extends BaseRestClient { ); } - /** - * @deprecated use setUserLeverage() instead - */ - changeUserLeverage(params: any): GenericAPIResponse { - return this.setUserLeverage(params); - } - getTradeRecords(params: { order_id?: string; symbol: string; @@ -428,7 +408,7 @@ export class InverseClient extends BaseRestClient { */ getRiskLimitList(): GenericAPIResponse { - return this.requestWrapper.get('open-api/wallet/risk-limit/list'); + return this.get('open-api/wallet/risk-limit/list'); } setRiskLimit(params: { @@ -464,9 +444,4 @@ export class InverseClient extends BaseRestClient { getLcpInfo(params: SymbolParam): GenericAPIResponse { return this.requestWrapper.get('v2/private/account/lcp', params); } - - //API Key Info - getAPIKeyInfo(): GenericAPIResponse { - return this.requestWrapper.get('v2/private/account/api-key'); - } } diff --git a/test/inverse/private.read.test.ts b/test/inverse/private.read.test.ts new file mode 100644 index 0000000..b0607a6 --- /dev/null +++ b/test/inverse/private.read.test.ts @@ -0,0 +1,101 @@ +import { InverseClient } from '../../src/inverse-client'; +import { successResponseList, successResponseObject } from '../response.util'; + +describe('Private Inverse REST API Endpoints', () => { + const useLivenet = true; + const API_KEY = process.env.API_KEY_COM; + const API_SECRET = process.env.API_SECRET_COM; + + it('should have api credentials to test with', () => { + expect(API_KEY).toStrictEqual(expect.any(String)); + expect(API_SECRET).toStrictEqual(expect.any(String)); + }); + + const api = new InverseClient(API_KEY, API_SECRET, useLivenet, { + disable_time_sync: true, + }); + + const symbol = 'BTCUSD'; + + describe('Inverse only private GET endpoints', () => { + it('getApiKeyInfo()', async () => { + expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject()); + }); + + it('getWalletBalance()', async () => { + expect(await api.getWalletBalance()).toMatchObject( + successResponseObject() + ); + }); + + it('getWalletFundRecords()', async () => { + expect(await api.getWalletFundRecords()).toMatchObject( + successResponseObject() + ); + }); + + it('getWithdrawRecords()', async () => { + expect(await api.getWithdrawRecords()).toMatchObject( + successResponseObject() + ); + }); + + it('getAssetExchangeRecords()', async () => { + expect(await api.getAssetExchangeRecords()).toMatchObject( + successResponseList() + ); + }); + + it('getActiveOrderList()', async () => { + expect(await api.getActiveOrderList({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('queryActiveOrder()', async () => { + expect(await api.queryActiveOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getConditionalOrder()', async () => { + expect(await api.getConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('queryConditionalOrder()', async () => { + expect(await api.queryConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getPosition()', async () => { + expect(await api.getPosition()).toMatchObject(successResponseObject()); + }); + + it('getTradeRecords()', async () => { + expect(await api.getTradeRecords({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getClosedPnl()', async () => { + expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getMyLastFundingFee()', async () => { + expect(await api.getMyLastFundingFee({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getLcpInfo()', async () => { + expect(await api.getLcpInfo({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + }); +}); diff --git a/test/inverse/private.test.ts b/test/inverse/private.test.ts deleted file mode 100644 index 6932c9c..0000000 --- a/test/inverse/private.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { InverseClient } from '../../src/inverse-client'; -import { - notAuthenticatedError, - successResponseList, - successResponseObject, -} from '../response.util'; - -describe.skip('Private Inverse REST API Endpoints', () => { - const useLivenet = true; - const API_KEY = process.env.API_KEY_COM; - const API_SECRET = process.env.API_SECRET_COM; - - it('should have api credentials to test with', () => { - expect(API_KEY).toStrictEqual(expect.any(String)); - expect(API_SECRET).toStrictEqual(expect.any(String)); - }); - - const api = new InverseClient(API_KEY, API_SECRET, useLivenet, { - disable_time_sync: true, - }); - - const symbol = 'BTCUSD'; - const interval = '15'; - const timestampOneHourAgo = new Date().getTime() / 1000 - 1000 * 60 * 60; - const from = Number(timestampOneHourAgo.toFixed(0)); - - describe('Inverse only endpoints', () => { - it('getOrderBook()', async () => { - expect(await api.getOrderBook({ symbol })).toMatchObject( - successResponseList() - ); - }); - - it('getKline()', async () => { - expect(await api.getKline({ symbol, interval, from })).toMatchObject( - successResponseList() - ); - }); - }); -}); diff --git a/test/inverse/public.test.ts b/test/inverse/public.test.ts index a61cebf..144f390 100644 --- a/test/inverse/public.test.ts +++ b/test/inverse/public.test.ts @@ -70,6 +70,10 @@ describe('Public Inverse REST API Endpoints', () => { ).toMatchObject(successResponseList()); }); + it('getRiskLimitList()', async () => { + expect(await api.getRiskLimitList()).toMatchObject(successResponseList()); + }); + it('getLastFundingRate()', async () => { expect(await api.getLastFundingRate({ symbol })).toMatchObject( successResponseObject() From d11fbfa227241d921cdb1b479baaf4df3bed4562 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Fri, 6 May 2022 22:06:32 +0100 Subject: [PATCH 10/24] add coverage for inverse futures private getter endpoints, migrate private getter methods to base class --- src/inverse-client.ts | 33 +++---- src/inverse-futures-client.ts | 47 ++++----- src/util/node-support.ts | 11 ++- src/util/requestUtils.ts | 17 +++- test/inverse-futures/private.read.test.ts | 113 ++++++++++++++++++++++ 5 files changed, 164 insertions(+), 57 deletions(-) create mode 100644 test/inverse-futures/private.read.test.ts diff --git a/src/inverse-client.ts b/src/inverse-client.ts index f88842d..21f9d80 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -145,7 +145,7 @@ export class InverseClient extends BaseRestClient { */ getApiKeyInfo(): GenericAPIResponse { - return this.requestWrapper.get('v2/private/account/api-key'); + return this.getPrivate('v2/private/account/api-key'); } /** @@ -155,21 +155,21 @@ export class InverseClient extends BaseRestClient { */ getWalletBalance(params?: Partial): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/balance', params); + return this.getPrivate('v2/private/wallet/balance', params); } getWalletFundRecords(params?: WalletFundRecordsReq): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/fund/records', params); + return this.getPrivate('v2/private/wallet/fund/records', params); } getWithdrawRecords(params?: WithdrawRecordsReq): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/withdraw/list', params); + return this.getPrivate('v2/private/wallet/withdraw/list', params); } getAssetExchangeRecords( params?: AssetExchangeRecordsReq ): GenericAPIResponse { - return this.requestWrapper.get('v2/private/exchange-order/list', params); + return this.getPrivate('v2/private/exchange-order/list', params); } /** @@ -221,7 +221,7 @@ export class InverseClient extends BaseRestClient { limit?: number; cursor?: string; }): GenericAPIResponse { - return this.requestWrapper.get('v2/private/order/list', params); + return this.getPrivate('v2/private/order/list', params); } cancelActiveOrder(params: { @@ -255,7 +255,7 @@ export class InverseClient extends BaseRestClient { order_link_id?: string; symbol: string; }): GenericAPIResponse { - return this.requestWrapper.get('v2/private/order', params); + return this.getPrivate('v2/private/order', params); } /** @@ -286,7 +286,7 @@ export class InverseClient extends BaseRestClient { limit?: number; cursor?: string; }): GenericAPIResponse { - return this.requestWrapper.get('v2/private/stop-order/list', params); + return this.getPrivate('v2/private/stop-order/list', params); } cancelConditionalOrder(params: { @@ -317,7 +317,7 @@ export class InverseClient extends BaseRestClient { stop_order_id?: string; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.get('v2/private/stop-order', params); + return this.getPrivate('v2/private/stop-order', params); } /** @@ -325,7 +325,7 @@ export class InverseClient extends BaseRestClient { */ getPosition(params?: Partial): GenericAPIResponse { - return this.requestWrapper.get('v2/private/position/list', params); + return this.getPrivate('v2/private/position/list', params); } changePositionMargin(params: { @@ -366,7 +366,7 @@ export class InverseClient extends BaseRestClient { limit?: number; order?: string; }): GenericAPIResponse { - return this.requestWrapper.get('v2/private/execution/list', params); + return this.getPrivate('v2/private/execution/list', params); } getClosedPnl(params: { @@ -377,7 +377,7 @@ export class InverseClient extends BaseRestClient { page?: number; limit?: number; }): GenericAPIResponse { - return this.requestWrapper.get('v2/private/trade/closed-pnl/list', params); + return this.getPrivate('v2/private/trade/closed-pnl/list', params); } setPositionMode(params: { symbol: string; mode: 0 | 3 }): GenericAPIResponse { @@ -427,14 +427,11 @@ export class InverseClient extends BaseRestClient { } getMyLastFundingFee(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get('v2/private/funding/prev-funding', params); + return this.getPrivate('v2/private/funding/prev-funding', params); } getPredictedFunding(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get( - 'v2/private/funding/predicted-funding', - params - ); + return this.getPrivate('v2/private/funding/predicted-funding', params); } /** @@ -442,6 +439,6 @@ export class InverseClient extends BaseRestClient { */ getLcpInfo(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get('v2/private/account/lcp', params); + return this.getPrivate('v2/private/account/lcp', params); } } diff --git a/src/inverse-futures-client.ts b/src/inverse-futures-client.ts index 836867c..d3feb21 100644 --- a/src/inverse-futures-client.ts +++ b/src/inverse-futures-client.ts @@ -6,11 +6,9 @@ import { } from './util/requestUtils'; import RequestWrapper from './util/requestWrapper'; import { - APIResponse, APIResponseWithTime, AssetExchangeRecordsReq, CoinParam, - SymbolFromLimitParam, SymbolInfo, SymbolIntervalFromLimitParam, SymbolLimitParam, @@ -148,7 +146,7 @@ export class InverseFuturesClient extends BaseRestClient { */ getApiKeyInfo(): GenericAPIResponse { - return this.requestWrapper.get('v2/private/account/api-key'); + return this.getPrivate('v2/private/account/api-key'); } /** @@ -158,21 +156,21 @@ export class InverseFuturesClient extends BaseRestClient { */ getWalletBalance(params?: Partial): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/balance', params); + return this.getPrivate('v2/private/wallet/balance', params); } getWalletFundRecords(params?: WalletFundRecordsReq): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/fund/records', params); + return this.getPrivate('v2/private/wallet/fund/records', params); } - getWithdrawRecords(params: WithdrawRecordsReq): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/withdraw/list', params); + getWithdrawRecords(params?: WithdrawRecordsReq): GenericAPIResponse { + return this.getPrivate('v2/private/wallet/withdraw/list', params); } getAssetExchangeRecords( params?: AssetExchangeRecordsReq ): GenericAPIResponse { - return this.requestWrapper.get('v2/private/exchange-order/list', params); + return this.getPrivate('v2/private/exchange-order/list', params); } /** @@ -225,7 +223,7 @@ export class InverseFuturesClient extends BaseRestClient { limit?: number; cursor?: string; }): GenericAPIResponse { - return this.requestWrapper.get('futures/private/order/list', params); + return this.getPrivate('futures/private/order/list', params); } cancelActiveOrder(params: { @@ -255,7 +253,7 @@ export class InverseFuturesClient extends BaseRestClient { order_link_id?: string; symbol: string; }): GenericAPIResponse { - return this.requestWrapper.get('futures/private/order', params); + return this.getPrivate('futures/private/order', params); } /** @@ -288,7 +286,7 @@ export class InverseFuturesClient extends BaseRestClient { limit?: number; cursor?: string; }): GenericAPIResponse { - return this.requestWrapper.get('futures/private/stop-order/list', params); + return this.getPrivate('futures/private/stop-order/list', params); } cancelConditionalOrder(params: { @@ -328,7 +326,7 @@ export class InverseFuturesClient extends BaseRestClient { stop_order_id?: string; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.get('futures/private/stop-order', params); + return this.getPrivate('futures/private/stop-order', params); } /** @@ -339,7 +337,7 @@ export class InverseFuturesClient extends BaseRestClient { * Get position list */ getPosition(params?: Partial): GenericAPIResponse { - return this.requestWrapper.get('futures/private/position/list', params); + return this.getPrivate('futures/private/position/list', params); } changePositionMargin(params: { @@ -414,7 +412,7 @@ export class InverseFuturesClient extends BaseRestClient { limit?: number; order?: string; }): GenericAPIResponse { - return this.requestWrapper.get('futures/private/execution/list', params); + return this.getPrivate('futures/private/execution/list', params); } getClosedPnl(params: { @@ -425,10 +423,7 @@ export class InverseFuturesClient extends BaseRestClient { page?: number; limit?: number; }): GenericAPIResponse { - return this.requestWrapper.get( - 'futures/private/trade/closed-pnl/list', - params - ); + return this.getPrivate('futures/private/trade/closed-pnl/list', params); } /** @@ -439,7 +434,7 @@ export class InverseFuturesClient extends BaseRestClient { * Risk Limit */ getRiskLimitList(): GenericAPIResponse { - return this.requestWrapper.get('open-api/wallet/risk-limit/list'); + return this.getPrivate('open-api/wallet/risk-limit/list'); } setRiskLimit(params: { @@ -454,21 +449,15 @@ export class InverseFuturesClient extends BaseRestClient { */ getLastFundingRate(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get( - 'v2/public/funding/prev-funding-rate', - params - ); + return this.get('v2/public/funding/prev-funding-rate', params); } getMyLastFundingFee(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get('v2/private/funding/prev-funding', params); + return this.getPrivate('v2/private/funding/prev-funding', params); } getPredictedFunding(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get( - 'v2/private/funding/predicted-funding', - params - ); + return this.getPrivate('v2/private/funding/predicted-funding', params); } /** @@ -476,6 +465,6 @@ export class InverseFuturesClient extends BaseRestClient { */ getLcpInfo(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get('v2/private/account/lcp', params); + return this.getPrivate('v2/private/account/lcp', params); } } diff --git a/src/util/node-support.ts b/src/util/node-support.ts index 7561ca4..bc3b159 100644 --- a/src/util/node-support.ts +++ b/src/util/node-support.ts @@ -1,7 +1,8 @@ import { createHmac } from 'crypto'; -export async function signMessage(message: string, secret: string): Promise { - return createHmac('sha256', secret) - .update(message) - .digest('hex'); -}; +export async function signMessage( + message: string, + secret: string +): Promise { + return createHmac('sha256', secret).update(message).digest('hex'); +} diff --git a/src/util/requestUtils.ts b/src/util/requestUtils.ts index 6342621..2ff11af 100644 --- a/src/util/requestUtils.ts +++ b/src/util/requestUtils.ts @@ -59,11 +59,18 @@ export function getRestBaseUrl( } export function isPublicEndpoint(endpoint: string): boolean { - if (endpoint.startsWith('v2/public')) { - return true; - } - if (endpoint.startsWith('public/linear')) { - return true; + const publicPrefixes = [ + 'v2/public', + 'public/linear', + 'spot/quote/v1', + 'spot/v1/symbols', + 'spot/v1/time', + ]; + + for (const prefix of publicPrefixes) { + if (endpoint.startsWith(prefix)) { + return true; + } } return false; } diff --git a/test/inverse-futures/private.read.test.ts b/test/inverse-futures/private.read.test.ts new file mode 100644 index 0000000..78feceb --- /dev/null +++ b/test/inverse-futures/private.read.test.ts @@ -0,0 +1,113 @@ +import { InverseFuturesClient } from '../../src/inverse-futures-client'; +import { + notAuthenticatedError, + successResponseList, + successResponseObject, +} from '../response.util'; + +describe('Public Inverse Futures REST API Endpoints', () => { + const useLivenet = true; + const API_KEY = process.env.API_KEY_COM; + const API_SECRET = process.env.API_SECRET_COM; + + const api = new InverseFuturesClient(API_KEY, API_SECRET, useLivenet, { + disable_time_sync: true, + }); + + // Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol! + const symbol = 'BTCUSDU22'; + + describe('Inverse-Futures only private GET endpoints', () => { + it('getApiKeyInfo()', async () => { + expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject()); + }); + + it('getWalletBalance()', async () => { + expect(await api.getWalletBalance()).toMatchObject( + successResponseObject() + ); + }); + + it('getWalletFundRecords()', async () => { + expect(await api.getWalletFundRecords()).toMatchObject( + successResponseObject() + ); + }); + + it('getWithdrawRecords()', async () => { + expect(await api.getWithdrawRecords()).toMatchObject( + successResponseObject() + ); + }); + + it('getAssetExchangeRecords()', async () => { + expect(await api.getAssetExchangeRecords()).toMatchObject( + successResponseList() + ); + }); + + it('getActiveOrderList()', async () => { + expect(await api.getActiveOrderList({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('queryActiveOrder()', async () => { + expect(await api.queryActiveOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getConditionalOrder()', async () => { + expect(await api.getConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('queryConditionalOrder()', async () => { + expect(await api.queryConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getPosition()', async () => { + expect(await api.getPosition()).toMatchObject(successResponseObject()); + }); + + it('getTradeRecords()', async () => { + expect(await api.getTradeRecords({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getClosedPnl()', async () => { + expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getRiskLimitList()', async () => { + expect(await api.getRiskLimitList()).toMatchObject( + successResponseList('ok') + ); + }); + + it('getMyLastFundingFee()', async () => { + expect(await api.getMyLastFundingFee({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getPredictedFunding()', async () => { + expect(await api.getPredictedFunding({ symbol: 'BTCUSD' })).toMatchObject( + successResponseObject() + ); + }); + + it('getLcpInfo()', async () => { + expect(await api.getLcpInfo({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + }); +}); From 72ce693d24a1755ebfe1ad7396a1c54dba893e2c Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Sat, 7 May 2022 22:23:58 +0100 Subject: [PATCH 11/24] move test to private --- src/inverse-client.ts | 2 +- test/inverse/private.read.test.ts | 6 ++++++ test/inverse/public.test.ts | 4 ---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/inverse-client.ts b/src/inverse-client.ts index 21f9d80..ca127cf 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -408,7 +408,7 @@ export class InverseClient extends BaseRestClient { */ getRiskLimitList(): GenericAPIResponse { - return this.get('open-api/wallet/risk-limit/list'); + return this.getPrivate('open-api/wallet/risk-limit/list'); } setRiskLimit(params: { diff --git a/test/inverse/private.read.test.ts b/test/inverse/private.read.test.ts index b0607a6..349db3e 100644 --- a/test/inverse/private.read.test.ts +++ b/test/inverse/private.read.test.ts @@ -80,6 +80,12 @@ describe('Private Inverse REST API Endpoints', () => { ); }); + it('getRiskLimitList()', async () => { + expect(await api.getRiskLimitList()).toMatchObject( + successResponseList('ok') + ); + }); + it('getClosedPnl()', async () => { expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( successResponseObject() diff --git a/test/inverse/public.test.ts b/test/inverse/public.test.ts index 144f390..a61cebf 100644 --- a/test/inverse/public.test.ts +++ b/test/inverse/public.test.ts @@ -70,10 +70,6 @@ describe('Public Inverse REST API Endpoints', () => { ).toMatchObject(successResponseList()); }); - it('getRiskLimitList()', async () => { - expect(await api.getRiskLimitList()).toMatchObject(successResponseList()); - }); - it('getLastFundingRate()', async () => { expect(await api.getLastFundingRate({ symbol })).toMatchObject( successResponseObject() From 78408294543ba86b7bf84c8eef1bedac69c7ede0 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Sat, 7 May 2022 23:35:24 +0100 Subject: [PATCH 12/24] fix linear request type, fix linear request method, add private read tests --- src/linear-client.ts | 46 +++++-------- test/linear/private.read.test.ts | 114 +++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 29 deletions(-) create mode 100644 test/linear/private.read.test.ts diff --git a/src/linear-client.ts b/src/linear-client.ts index d01636f..df942c5 100644 --- a/src/linear-client.ts +++ b/src/linear-client.ts @@ -150,7 +150,7 @@ export class LinearClient extends BaseRestClient { */ getApiKeyInfo(): GenericAPIResponse { - return this.requestWrapper.get('v2/private/account/api-key'); + return this.getPrivate('v2/private/account/api-key'); } /** @@ -160,21 +160,21 @@ export class LinearClient extends BaseRestClient { */ getWalletBalance(params?: Partial): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/balance', params); + return this.getPrivate('v2/private/wallet/balance', params); } getWalletFundRecords(params?: WalletFundRecordsReq): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/fund/records', params); + return this.getPrivate('v2/private/wallet/fund/records', params); } - getWithdrawRecords(params: WithdrawRecordsReq): GenericAPIResponse { - return this.requestWrapper.get('v2/private/wallet/withdraw/list', params); + getWithdrawRecords(params?: WithdrawRecordsReq): GenericAPIResponse { + return this.getPrivate('v2/private/wallet/withdraw/list', params); } getAssetExchangeRecords( params?: AssetExchangeRecordsReq ): GenericAPIResponse { - return this.requestWrapper.get('v2/private/exchange-order/list', params); + return this.getPrivate('v2/private/exchange-order/list', params); } /** @@ -225,7 +225,7 @@ export class LinearClient extends BaseRestClient { limit?: number; order_status?: string; }): GenericAPIResponse { - return this.requestWrapper.get('private/linear/order/list', params); + return this.getPrivate('private/linear/order/list', params); } cancelActiveOrder(params: { @@ -259,7 +259,7 @@ export class LinearClient extends BaseRestClient { order_link_id?: string; symbol: string; }): GenericAPIResponse { - return this.requestWrapper.get('private/linear/order/search', params); + return this.getPrivate('private/linear/order/search', params); } /** @@ -296,7 +296,7 @@ export class LinearClient extends BaseRestClient { page?: number; limit?: number; }): GenericAPIResponse { - return this.requestWrapper.get('private/linear/stop-order/list', params); + return this.getPrivate('private/linear/stop-order/list', params); } cancelConditionalOrder(params: { @@ -337,7 +337,7 @@ export class LinearClient extends BaseRestClient { stop_order_id?: string; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.get('private/linear/stop-order/search', params); + return this.getPrivate('private/linear/stop-order/search', params); } /** @@ -345,7 +345,7 @@ export class LinearClient extends BaseRestClient { */ getPosition(params?: Partial): GenericAPIResponse { - return this.requestWrapper.get('private/linear/position/list', params); + return this.getPrivate('private/linear/position/list', params); } setAutoAddMargin(params?: { @@ -450,10 +450,7 @@ export class LinearClient extends BaseRestClient { page?: number; limit?: number; }): GenericAPIResponse { - return this.requestWrapper.get( - 'private/linear/trade/execution/list', - params - ); + return this.getPrivate('private/linear/trade/execution/list', params); } getClosedPnl(params: { @@ -464,10 +461,7 @@ export class LinearClient extends BaseRestClient { page?: number; limit?: number; }): GenericAPIResponse { - return this.requestWrapper.get( - 'private/linear/trade/closed-pnl/list', - params - ); + return this.getPrivate('private/linear/trade/closed-pnl/list', params); } /** @@ -475,7 +469,7 @@ export class LinearClient extends BaseRestClient { */ getRiskLimitList(params: SymbolParam): GenericAPIResponse { - return this.get('public/linear/risk-limit', params); + return this.getPrivate('public/linear/risk-limit', params); } setRiskLimit(params: { @@ -483,7 +477,7 @@ export class LinearClient extends BaseRestClient { side: string; risk_id: string; }): GenericAPIResponse { - return this.requestWrapper.get('private/linear/position/set-risk', params); + return this.requestWrapper.post('private/linear/position/set-risk', params); } /** @@ -491,16 +485,10 @@ export class LinearClient extends BaseRestClient { */ getPredictedFundingFee(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get( - 'private/linear/funding/predicted-funding', - params - ); + return this.getPrivate('private/linear/funding/predicted-funding', params); } getLastFundingFee(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.get( - 'private/linear/funding/prev-funding', - params - ); + return this.getPrivate('private/linear/funding/prev-funding', params); } } diff --git a/test/linear/private.read.test.ts b/test/linear/private.read.test.ts new file mode 100644 index 0000000..b0da942 --- /dev/null +++ b/test/linear/private.read.test.ts @@ -0,0 +1,114 @@ +import { LinearClient } from '../../src/linear-client'; +import { + notAuthenticatedError, + successResponseList, + successResponseObject, +} from '../response.util'; + +describe('Public Linear REST API Endpoints', () => { + const useLivenet = true; + const API_KEY = process.env.API_KEY_COM; + const API_SECRET = process.env.API_SECRET_COM; + + it('should have api credentials to test with', () => { + expect(API_KEY).toStrictEqual(expect.any(String)); + expect(API_SECRET).toStrictEqual(expect.any(String)); + }); + + const api = new LinearClient(API_KEY, API_SECRET, useLivenet, { + disable_time_sync: true, + }); + + const symbol = 'BTCUSDT'; + const interval = '15'; + const timestampOneHourAgo = new Date().getTime() / 1000 - 1000 * 60 * 60; + const from = Number(timestampOneHourAgo.toFixed(0)); + + describe('Linear only private GET endpoints', () => { + it('getApiKeyInfo()', async () => { + expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject()); + }); + + it('getWalletBalance()', async () => { + expect(await api.getWalletBalance()).toMatchObject( + successResponseObject() + ); + }); + + it('getWalletFundRecords()', async () => { + expect(await api.getWalletFundRecords()).toMatchObject( + successResponseObject() + ); + }); + + it('getWithdrawRecords()', async () => { + expect(await api.getWithdrawRecords()).toMatchObject( + successResponseObject() + ); + }); + + it('getAssetExchangeRecords()', async () => { + expect(await api.getAssetExchangeRecords()).toMatchObject( + successResponseList() + ); + }); + + it('getActiveOrderList()', async () => { + expect(await api.getActiveOrderList({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('queryActiveOrder()', async () => { + expect(await api.queryActiveOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getConditionalOrder()', async () => { + expect(await api.getConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('queryConditionalOrder()', async () => { + expect(await api.queryConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getPosition()', async () => { + expect(await api.getPosition()).toMatchObject(successResponseObject()); + }); + + it('getTradeRecords()', async () => { + expect(await api.getTradeRecords({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getClosedPnl()', async () => { + expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + + it('getRiskLimitList()', async () => { + expect(await api.getRiskLimitList({ symbol: symbol })).toMatchObject( + successResponseList() + ); + }); + + it('getPredictedFundingFee()', async () => { + expect( + await api.getPredictedFundingFee({ symbol: symbol }) + ).toMatchObject(successResponseObject()); + }); + + it('getLastFundingFee()', async () => { + expect(await api.getLastFundingFee({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); + }); +}); From 38f5a6286cf80869d2885277091176f4b918cb02 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Sun, 8 May 2022 01:00:12 +0100 Subject: [PATCH 13/24] fixes for private spot GET calls, improve signing process, add private read tests for spot & linear --- src/inverse-client.ts | 4 +- src/inverse-futures-client.ts | 4 +- src/linear-client.ts | 4 +- src/spot-client.ts | 9 ++- src/util/BaseRestClient.ts | 109 +++++++++++++++++++++++-------- src/util/requestUtils.ts | 12 +++- test/linear/private.read.test.ts | 9 +-- test/response.util.ts | 12 ++++ test/spot/private.read.test.ts | 54 +++++++++++++++ 9 files changed, 176 insertions(+), 41 deletions(-) create mode 100644 test/spot/private.read.test.ts diff --git a/src/inverse-client.ts b/src/inverse-client.ts index ca127cf..f2f706e 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -3,6 +3,7 @@ import { GenericAPIResponse, getRestBaseUrl, RestClientOptions, + REST_CLIENT_TYPE_ENUM, } from './util/requestUtils'; import RequestWrapper from './util/requestWrapper'; import { @@ -46,7 +47,8 @@ export class InverseClient extends BaseRestClient { secret, getRestBaseUrl(useLivenet, restClientOptions), restClientOptions, - requestOptions + requestOptions, + REST_CLIENT_TYPE_ENUM.inverse ); this.requestWrapper = new RequestWrapper( key, diff --git a/src/inverse-futures-client.ts b/src/inverse-futures-client.ts index d3feb21..e4e1dc7 100644 --- a/src/inverse-futures-client.ts +++ b/src/inverse-futures-client.ts @@ -3,6 +3,7 @@ import { GenericAPIResponse, getRestBaseUrl, RestClientOptions, + REST_CLIENT_TYPE_ENUM, } from './util/requestUtils'; import RequestWrapper from './util/requestWrapper'; import { @@ -44,7 +45,8 @@ export class InverseFuturesClient extends BaseRestClient { secret, getRestBaseUrl(useLivenet, restClientOptions), restClientOptions, - requestOptions + requestOptions, + REST_CLIENT_TYPE_ENUM.inverseFutures ); this.requestWrapper = new RequestWrapper( key, diff --git a/src/linear-client.ts b/src/linear-client.ts index df942c5..e5842fb 100644 --- a/src/linear-client.ts +++ b/src/linear-client.ts @@ -3,6 +3,7 @@ import { GenericAPIResponse, getRestBaseUrl, RestClientOptions, + REST_CLIENT_TYPE_ENUM, } from './util/requestUtils'; import RequestWrapper from './util/requestWrapper'; import { @@ -46,7 +47,8 @@ export class LinearClient extends BaseRestClient { secret, getRestBaseUrl(useLivenet, restClientOptions), restClientOptions, - requestOptions + requestOptions, + REST_CLIENT_TYPE_ENUM.linear ); this.requestWrapper = new RequestWrapper( diff --git a/src/spot-client.ts b/src/spot-client.ts index 52decb8..a4cb849 100644 --- a/src/spot-client.ts +++ b/src/spot-client.ts @@ -8,7 +8,11 @@ import { SpotSymbolInfo, } from './types/spot'; import BaseRestClient from './util/BaseRestClient'; -import { getRestBaseUrl, RestClientOptions } from './util/requestUtils'; +import { + getRestBaseUrl, + RestClientOptions, + REST_CLIENT_TYPE_ENUM, +} from './util/requestUtils'; export class SpotClient extends BaseRestClient { /** @@ -32,7 +36,8 @@ export class SpotClient extends BaseRestClient { secret, getRestBaseUrl(useLivenet, restClientOptions), restClientOptions, - requestOptions + requestOptions, + REST_CLIENT_TYPE_ENUM.spot ); return this; diff --git a/src/util/BaseRestClient.ts b/src/util/BaseRestClient.ts index e5f8782..4d7e3c7 100644 --- a/src/util/BaseRestClient.ts +++ b/src/util/BaseRestClient.ts @@ -9,11 +9,26 @@ import { signMessage } from './node-support'; import { RestClientOptions, GenericAPIResponse, - getRestBaseUrl, serializeParams, - isPublicEndpoint, + RestClientType, + REST_CLIENT_TYPE_ENUM, } from './requestUtils'; + +interface SignedRequestContext { + timestamp: number; + api_key?: string; + recv_window?: number; + // spot is diff from the rest... + recvWindow?: number; +} + +interface SignedRequest { + originalParams: T & SignedRequestContext; + paramsWithSign?: T & SignedRequestContext & { sign: string }; + sign: string; +} + export default abstract class BaseRestClient { private timeOffset: number | null; private syncTimePromise: null | Promise; @@ -22,6 +37,7 @@ export default abstract class BaseRestClient { private globalRequestOptions: AxiosRequestConfig; private key: string | undefined; private secret: string | undefined; + private clientType: RestClientType; /** Function that calls exchange API to query & resolve server time, used by time sync */ abstract fetchServerTime(): Promise; @@ -31,11 +47,14 @@ export default abstract class BaseRestClient { secret: string | undefined, baseUrl: string, options: RestClientOptions = {}, - requestOptions: AxiosRequestConfig = {} + requestOptions: AxiosRequestConfig = {}, + clientType: RestClientType ) { this.timeOffset = null; this.syncTimePromise = null; + this.clientType = clientType; + this.options = { recv_window: 5000, // how often to sync time drift with bybit servers @@ -72,6 +91,10 @@ export default abstract class BaseRestClient { this.secret = secret; } + private isSpotClient() { + return this.clientType === REST_CLIENT_TYPE_ENUM.spot; + } + get(endpoint: string, params?: any): GenericAPIResponse { return this._call('GET', endpoint, params, true); } @@ -92,6 +115,26 @@ export default abstract class BaseRestClient { return this._call('DELETE', endpoint, params, false); } + private async prepareSignParams(params?: any, isPublicApi?: boolean) { + if (isPublicApi) { + return { + originalParams: params, + paramsWithSign: params, + }; + } + + if (!this.key || !this.secret) { + throw new Error('Private endpoints require api and private keys set'); + } + + if (this.timeOffset === null) { + await this.syncTime(); + } + + const signedRequest = await this.signRequest(params); + return signedRequest; + } + /** * @private Make a HTTP request to a specific endpoint. Private endpoints are automatically signed. */ @@ -101,18 +144,6 @@ export default abstract class BaseRestClient { params?: any, isPublicApi?: boolean ): GenericAPIResponse { - if (!isPublicApi) { - if (!this.key || !this.secret) { - throw new Error('Private endpoints require api and private keys set'); - } - - if (this.timeOffset === null) { - await this.syncTime(); - } - - params = await this.signRequest(params); - } - const options = { ...this.globalRequestOptions, url: [this.baseUrl, endpoint].join(endpoint.startsWith('/') ? '' : '/'), @@ -120,10 +151,21 @@ export default abstract class BaseRestClient { json: true, }; + for (const key in params) { + if (typeof params[key] === 'undefined') { + delete params[key]; + } + } + + const preparedRequestParams = await this.prepareSignParams( + params, + isPublicApi + ); + if (method === 'GET') { - options.params = params; + options.params = preparedRequestParams.paramsWithSign; } else { - options.data = params; + options.data = preparedRequestParams.paramsWithSign; } return axios(options) @@ -170,27 +212,40 @@ export default abstract class BaseRestClient { /** * @private sign request and set recv window */ - async signRequest(data: any): Promise { - const params = { - ...data, - api_key: this.key, - timestamp: Date.now() + (this.timeOffset || 0), + private async signRequest( + data: T & SignedRequestContext + ): Promise> { + const res: SignedRequest = { + originalParams: { + ...data, + api_key: this.key, + timestamp: Date.now() + (this.timeOffset || 0), + }, + sign: '', }; // Optional, set to 5000 by default. Increase if timestamp/recv_window errors are seen. - if (this.options.recv_window && !params.recv_window) { - params.recv_window = this.options.recv_window; + if (this.options.recv_window && !res.originalParams.recv_window) { + if (this.isSpotClient()) { + res.originalParams.recvWindow = this.options.recv_window; + } else { + res.originalParams.recv_window = this.options.recv_window; + } } if (this.key && this.secret) { const serializedParams = serializeParams( - params, + res.originalParams, this.options.strict_param_validation ); - params.sign = await signMessage(serializedParams, this.secret); + res.sign = await signMessage(serializedParams, this.secret); + res.paramsWithSign = { + ...res.originalParams, + sign: res.sign, + }; } - return params; + return res; } /** diff --git a/src/util/requestUtils.ts b/src/util/requestUtils.ts index 2ff11af..08f5ecc 100644 --- a/src/util/requestUtils.ts +++ b/src/util/requestUtils.ts @@ -76,7 +76,7 @@ export function isPublicEndpoint(endpoint: string): boolean { } export function isWsPong(response: any) { - if (response.pong) { + if (response.pong || response.ping) { return true; } return ( @@ -86,3 +86,13 @@ export function isWsPong(response: any) { response.success === true ); } + +export const REST_CLIENT_TYPE_ENUM = { + inverse: 'inverse', + inverseFutures: 'inverseFutures', + linear: 'linear', + spot: 'spot', +} as const; + +export type RestClientType = + typeof REST_CLIENT_TYPE_ENUM[keyof typeof REST_CLIENT_TYPE_ENUM]; diff --git a/test/linear/private.read.test.ts b/test/linear/private.read.test.ts index b0da942..f061cf7 100644 --- a/test/linear/private.read.test.ts +++ b/test/linear/private.read.test.ts @@ -1,9 +1,5 @@ import { LinearClient } from '../../src/linear-client'; -import { - notAuthenticatedError, - successResponseList, - successResponseObject, -} from '../response.util'; +import { successResponseList, successResponseObject } from '../response.util'; describe('Public Linear REST API Endpoints', () => { const useLivenet = true; @@ -20,9 +16,6 @@ describe('Public Linear REST API Endpoints', () => { }); const symbol = 'BTCUSDT'; - const interval = '15'; - const timestampOneHourAgo = new Date().getTime() / 1000 - 1000 * 60 * 60; - const from = Number(timestampOneHourAgo.toFixed(0)); describe('Linear only private GET endpoints', () => { it('getApiKeyInfo()', async () => { diff --git a/test/response.util.ts b/test/response.util.ts index 312a67f..fa9313c 100644 --- a/test/response.util.ts +++ b/test/response.util.ts @@ -14,6 +14,18 @@ export function successResponseObject(successMsg: string | null = 'OK') { }; } +export function errorResponseObject( + result: null | any = null, + ret_code: number, + ret_msg: string +) { + return { + result, + ret_code, + ret_msg, + }; +} + export function notAuthenticatedError() { return new Error('Private endpoints require api and private keys set'); } diff --git a/test/spot/private.read.test.ts b/test/spot/private.read.test.ts new file mode 100644 index 0000000..77762d6 --- /dev/null +++ b/test/spot/private.read.test.ts @@ -0,0 +1,54 @@ +import { SpotClient } from '../../src'; +import { + errorResponseObject, + notAuthenticatedError, + successResponseList, + successResponseObject, +} from '../response.util'; + +describe('Private Spot REST API Endpoints', () => { + const useLivenet = true; + const API_KEY = process.env.API_KEY_COM; + const API_SECRET = process.env.API_SECRET_COM; + + it('should have api credentials to test with', () => { + expect(API_KEY).toStrictEqual(expect.any(String)); + expect(API_SECRET).toStrictEqual(expect.any(String)); + }); + + const api = new SpotClient(API_KEY, API_SECRET, useLivenet, { + disable_time_sync: true, + }); + + const symbol = 'BTCUSDT'; + const interval = '15m'; + + it('getOrder()', async () => { + // No auth error == test pass + expect(await api.getOrder({ orderId: '123123' })).toMatchObject( + errorResponseObject(null, -2013, 'Order does not exist.') + ); + }); + + it('getOpenOrders()', async () => { + expect(await api.getOpenOrders()).toMatchObject(successResponseList('')); + }); + + it('getPastOrders()', async () => { + expect(await api.getPastOrders()).toMatchObject(successResponseList('')); + }); + + it('getMyTrades()', async () => { + expect(await api.getMyTrades()).toMatchObject(successResponseList('')); + }); + + it('getBalances()', async () => { + expect(await api.getBalances()).toMatchObject({ + result: { + balances: expect.any(Array), + }, + ret_code: 0, + ret_msg: '', + }); + }); +}); From c94b4d16ffdace67923d0dbdde5eaf09bd46e62f Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Sun, 8 May 2022 01:09:04 +0100 Subject: [PATCH 14/24] small clean --- src/util/BaseRestClient.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/util/BaseRestClient.ts b/src/util/BaseRestClient.ts index 4d7e3c7..4d0c957 100644 --- a/src/util/BaseRestClient.ts +++ b/src/util/BaseRestClient.ts @@ -157,15 +157,12 @@ export default abstract class BaseRestClient { } } - const preparedRequestParams = await this.prepareSignParams( - params, - isPublicApi - ); + const signResult = await this.prepareSignParams(params, isPublicApi); if (method === 'GET') { - options.params = preparedRequestParams.paramsWithSign; + options.params = signResult.paramsWithSign; } else { - options.data = preparedRequestParams.paramsWithSign; + options.data = signResult.paramsWithSign; } return axios(options) From c6758b65cc6c47f6738b48428f493d5d701da6a9 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Tue, 10 May 2022 13:22:28 +0100 Subject: [PATCH 15/24] remove dead inverse method, add write tests, update read tests, add error enums used by tests --- src/index.ts | 21 ++-- src/inverse-client.ts | 6 - src/util/BaseRestClient.ts | 3 +- src/util/enum.ts | 12 ++ test/inverse/private.read.test.ts | 140 ++++++++++----------- test/inverse/private.write.test.ts | 193 +++++++++++++++++++++++++++++ 6 files changed, 285 insertions(+), 90 deletions(-) create mode 100644 src/util/enum.ts create mode 100644 test/inverse/private.write.test.ts diff --git a/src/index.ts b/src/index.ts index df2faad..941d3ea 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,11 @@ -export * from "./inverse-client"; -export * from "./inverse-futures-client"; -export * from "./linear-client"; -export * from "./spot-client"; -export * from "./websocket-client"; -export * from "./logger"; -export * from "./types/shared"; -export * from "./types/spot"; -export * from "./util/WsStore"; -export * from "./constants/enum"; +export * from './inverse-client'; +export * from './inverse-futures-client'; +export * from './linear-client'; +export * from './spot-client'; +export * from './websocket-client'; +export * from './logger'; +export * from './types/shared'; +export * from './types/spot'; +export * from './util/WsStore'; +export * from './util/enum'; +export * from './constants/enum'; diff --git a/src/inverse-client.ts b/src/inverse-client.ts index f2f706e..0dbd297 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -7,11 +7,9 @@ import { } from './util/requestUtils'; import RequestWrapper from './util/requestWrapper'; import { - APIResponse, APIResponseWithTime, AssetExchangeRecordsReq, CoinParam, - SymbolFromLimitParam, SymbolInfo, SymbolIntervalFromLimitParam, SymbolLimitParam, @@ -382,10 +380,6 @@ export class InverseClient extends BaseRestClient { return this.getPrivate('v2/private/trade/closed-pnl/list', params); } - setPositionMode(params: { symbol: string; mode: 0 | 3 }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/position/switch-mode', params); - } - setSlTpPositionMode(params: { symbol: string; tp_sl_mode: 'Full' | 'Partial'; diff --git a/src/util/BaseRestClient.ts b/src/util/BaseRestClient.ts index 4d0c957..e9296cc 100644 --- a/src/util/BaseRestClient.ts +++ b/src/util/BaseRestClient.ts @@ -131,8 +131,7 @@ export default abstract class BaseRestClient { await this.syncTime(); } - const signedRequest = await this.signRequest(params); - return signedRequest; + return this.signRequest(params); } /** diff --git a/src/util/enum.ts b/src/util/enum.ts new file mode 100644 index 0000000..a0072e2 --- /dev/null +++ b/src/util/enum.ts @@ -0,0 +1,12 @@ +export const API_ERROR_CODE = { + ORDER_NOT_FOUND_OR_TOO_LATE: 20001, + CANNOT_SET_TRADING_STOP_FOR_ZERO_POS: 30024, + /** Seen when placing an order */ + INSUFFICIENT_BALANCE_FOR_ORDER_COST: 30031, + /** Seen if a conditional order is too large */ + INSUFFICIENT_BALANCE: 30042, + /** E.g. trying to change position margin while on cross */ + POSITION_IS_CROSS_MARGIN: 30056, + RISK_LIMIT_NOT_EXISTS: 30090, + SAME_SLTP_MODE: 37002, +} as const; diff --git a/test/inverse/private.read.test.ts b/test/inverse/private.read.test.ts index 349db3e..12301c1 100644 --- a/test/inverse/private.read.test.ts +++ b/test/inverse/private.read.test.ts @@ -17,91 +17,87 @@ describe('Private Inverse REST API Endpoints', () => { const symbol = 'BTCUSD'; - describe('Inverse only private GET endpoints', () => { - it('getApiKeyInfo()', async () => { - expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject()); - }); + it('getApiKeyInfo()', async () => { + expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject()); + }); - it('getWalletBalance()', async () => { - expect(await api.getWalletBalance()).toMatchObject( - successResponseObject() - ); - }); + it('getWalletBalance()', async () => { + expect(await api.getWalletBalance()).toMatchObject(successResponseObject()); + }); - it('getWalletFundRecords()', async () => { - expect(await api.getWalletFundRecords()).toMatchObject( - successResponseObject() - ); - }); + it('getWalletFundRecords()', async () => { + expect(await api.getWalletFundRecords()).toMatchObject( + successResponseObject() + ); + }); - it('getWithdrawRecords()', async () => { - expect(await api.getWithdrawRecords()).toMatchObject( - successResponseObject() - ); - }); + it('getWithdrawRecords()', async () => { + expect(await api.getWithdrawRecords()).toMatchObject( + successResponseObject() + ); + }); - it('getAssetExchangeRecords()', async () => { - expect(await api.getAssetExchangeRecords()).toMatchObject( - successResponseList() - ); - }); + it('getAssetExchangeRecords()', async () => { + expect(await api.getAssetExchangeRecords()).toMatchObject( + successResponseList() + ); + }); - it('getActiveOrderList()', async () => { - expect(await api.getActiveOrderList({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getActiveOrderList()', async () => { + expect(await api.getActiveOrderList({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('queryActiveOrder()', async () => { - expect(await api.queryActiveOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('queryActiveOrder()', async () => { + expect(await api.queryActiveOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getConditionalOrder()', async () => { - expect(await api.getConditionalOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getConditionalOrder()', async () => { + expect(await api.getConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('queryConditionalOrder()', async () => { - expect(await api.queryConditionalOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('queryConditionalOrder()', async () => { + expect(await api.queryConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getPosition()', async () => { - expect(await api.getPosition()).toMatchObject(successResponseObject()); - }); + it('getPosition()', async () => { + expect(await api.getPosition()).toMatchObject(successResponseObject()); + }); - it('getTradeRecords()', async () => { - expect(await api.getTradeRecords({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getTradeRecords()', async () => { + expect(await api.getTradeRecords({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getRiskLimitList()', async () => { - expect(await api.getRiskLimitList()).toMatchObject( - successResponseList('ok') - ); - }); + it('getRiskLimitList()', async () => { + expect(await api.getRiskLimitList()).toMatchObject( + successResponseList('ok') + ); + }); - it('getClosedPnl()', async () => { - expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getClosedPnl()', async () => { + expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getMyLastFundingFee()', async () => { - expect(await api.getMyLastFundingFee({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getMyLastFundingFee()', async () => { + expect(await api.getMyLastFundingFee({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getLcpInfo()', async () => { - expect(await api.getLcpInfo({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getLcpInfo()', async () => { + expect(await api.getLcpInfo({ symbol: symbol })).toMatchObject( + successResponseObject() + ); }); }); diff --git a/test/inverse/private.write.test.ts b/test/inverse/private.write.test.ts new file mode 100644 index 0000000..8577c3d --- /dev/null +++ b/test/inverse/private.write.test.ts @@ -0,0 +1,193 @@ +import { InverseClient } from '../../src/inverse-client'; +import { API_ERROR_CODE } from '../../src/util/enum'; +import { successResponseList, successResponseObject } from '../response.util'; + +describe('Private Inverse REST API Endpoints', () => { + const useLivenet = true; + const API_KEY = process.env.API_KEY_COM; + const API_SECRET = process.env.API_SECRET_COM; + + it('should have api credentials to test with', () => { + expect(API_KEY).toStrictEqual(expect.any(String)); + expect(API_SECRET).toStrictEqual(expect.any(String)); + }); + + const api = new InverseClient(API_KEY, API_SECRET, useLivenet, { + disable_time_sync: true, + }); + + const symbol = 'BTCUSD'; + + // These tests are primarily check auth is working by expecting balance or order not found style errors + + it('placeActiveOrder()', async () => { + expect( + await api.placeActiveOrder({ + side: 'Buy', + symbol, + order_type: 'Limit', + price: 30000, + qty: 1, + time_in_force: 'GoodTillCancel', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.INSUFFICIENT_BALANCE_FOR_ORDER_COST, + }); + }); + + it('cancelActiveOrder()', async () => { + expect( + await api.cancelActiveOrder({ + symbol, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to cancel', + }); + }); + + it('cancelAllActiveOrders()', async () => { + expect( + await api.cancelAllActiveOrders({ + symbol, + }) + ).toMatchObject(successResponseObject()); + }); + + it('replaceActiveOrder()', async () => { + expect( + await api.replaceActiveOrder({ + symbol, + order_id: '123123123', + p_r_qty: 1, + p_r_price: '30000', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to replace', + }); + }); + + it('placeConditionalOrder()', async () => { + expect( + await api.placeConditionalOrder({ + order_type: 'Limit', + side: 'Buy', + symbol, + qty: '1', + price: '8100', + base_price: '8300', + stop_px: '8150', + time_in_force: 'GoodTillCancel', + order_link_id: 'cus_order_id_1', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.INSUFFICIENT_BALANCE, + ret_msg: 'Insufficient wallet balance', + }); + }); + + it('cancelConditionalOrder()', async () => { + expect( + await api.cancelConditionalOrder({ + symbol, + order_link_id: 'lkasmdflasd', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to cancel', + }); + }); + + it('cancelAllConditionalOrders()', async () => { + expect( + await api.cancelAllConditionalOrders({ + symbol, + }) + ).toMatchObject(successResponseObject()); + }); + + it('replaceConditionalOrder()', async () => { + expect( + await api.replaceConditionalOrder({ + symbol, + p_r_price: '50000', + p_r_qty: 1, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to replace', + }); + }); + + it('changePositionMargin()', async () => { + expect( + await api.changePositionMargin({ + symbol, + margin: '10', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.POSITION_IS_CROSS_MARGIN, + ret_msg: 'position is in crossMargin', + }); + }); + + it('setTradingStop()', async () => { + expect( + await api.setTradingStop({ + symbol, + take_profit: 5555, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.CANNOT_SET_TRADING_STOP_FOR_ZERO_POS, + ret_msg: 'can not set tp/sl/ts for zero position', + }); + }); + + it('setUserLeverage()', async () => { + expect( + await api.setUserLeverage({ + symbol, + leverage: 5, + }) + ).toMatchObject({ + result: 5, + ret_code: 0, + }); + }); + + it('setSlTpPositionMode()', async () => { + expect( + await api.setSlTpPositionMode({ + symbol, + tp_sl_mode: 'Full', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.SAME_SLTP_MODE, + ret_msg: 'same tp sl mode2', + }); + }); + + it('setMarginType()', async () => { + expect( + await api.setMarginType({ + symbol, + is_isolated: false, + buy_leverage: 5, + sell_leverage: 5, + }) + ).toMatchObject(successResponseObject()); + }); + + it('setRiskLimit()', async () => { + expect( + await api.setRiskLimit({ + symbol, + risk_id: 'myriskid', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.RISK_LIMIT_NOT_EXISTS, + ret_msg: 'risk limit not exists', + }); + }); +}); From 07ec505407725b241fd45b1508d74fdd32c58034 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Tue, 10 May 2022 13:32:37 +0100 Subject: [PATCH 16/24] inverse futures write tests --- src/util/enum.ts | 5 + test/inverse-futures/private.read.test.ts | 158 ++++++++-------- test/inverse-futures/private.write.test.ts | 199 +++++++++++++++++++++ 3 files changed, 279 insertions(+), 83 deletions(-) create mode 100644 test/inverse-futures/private.write.test.ts diff --git a/src/util/enum.ts b/src/util/enum.ts index a0072e2..152f3d4 100644 --- a/src/util/enum.ts +++ b/src/util/enum.ts @@ -1,12 +1,17 @@ export const API_ERROR_CODE = { ORDER_NOT_FOUND_OR_TOO_LATE: 20001, + POSITION_STATUS_NOT_NORMAL: 30013, CANNOT_SET_TRADING_STOP_FOR_ZERO_POS: 30024, /** Seen when placing an order */ INSUFFICIENT_BALANCE_FOR_ORDER_COST: 30031, + POSITION_IDX_NOT_MATCH_POSITION_MODE: 30041, /** Seen if a conditional order is too large */ INSUFFICIENT_BALANCE: 30042, /** E.g. trying to change position margin while on cross */ POSITION_IS_CROSS_MARGIN: 30056, + POSITION_MODE_NOT_MODIFIED: 30083, + ISOLATED_NOT_MODIFIED: 30084, RISK_LIMIT_NOT_EXISTS: 30090, + LEVERAGE_NOT_MODIFIED: 34036, SAME_SLTP_MODE: 37002, } as const; diff --git a/test/inverse-futures/private.read.test.ts b/test/inverse-futures/private.read.test.ts index 78feceb..af52130 100644 --- a/test/inverse-futures/private.read.test.ts +++ b/test/inverse-futures/private.read.test.ts @@ -1,11 +1,7 @@ import { InverseFuturesClient } from '../../src/inverse-futures-client'; -import { - notAuthenticatedError, - successResponseList, - successResponseObject, -} from '../response.util'; +import { successResponseList, successResponseObject } from '../response.util'; -describe('Public Inverse Futures REST API Endpoints', () => { +describe('Public Inverse-Futures REST API GET Endpoints', () => { const useLivenet = true; const API_KEY = process.env.API_KEY_COM; const API_SECRET = process.env.API_SECRET_COM; @@ -17,97 +13,93 @@ describe('Public Inverse Futures REST API Endpoints', () => { // Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol! const symbol = 'BTCUSDU22'; - describe('Inverse-Futures only private GET endpoints', () => { - it('getApiKeyInfo()', async () => { - expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject()); - }); + it('getApiKeyInfo()', async () => { + expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject()); + }); - it('getWalletBalance()', async () => { - expect(await api.getWalletBalance()).toMatchObject( - successResponseObject() - ); - }); + it('getWalletBalance()', async () => { + expect(await api.getWalletBalance()).toMatchObject(successResponseObject()); + }); - it('getWalletFundRecords()', async () => { - expect(await api.getWalletFundRecords()).toMatchObject( - successResponseObject() - ); - }); + it('getWalletFundRecords()', async () => { + expect(await api.getWalletFundRecords()).toMatchObject( + successResponseObject() + ); + }); - it('getWithdrawRecords()', async () => { - expect(await api.getWithdrawRecords()).toMatchObject( - successResponseObject() - ); - }); + it('getWithdrawRecords()', async () => { + expect(await api.getWithdrawRecords()).toMatchObject( + successResponseObject() + ); + }); - it('getAssetExchangeRecords()', async () => { - expect(await api.getAssetExchangeRecords()).toMatchObject( - successResponseList() - ); - }); + it('getAssetExchangeRecords()', async () => { + expect(await api.getAssetExchangeRecords()).toMatchObject( + successResponseList() + ); + }); - it('getActiveOrderList()', async () => { - expect(await api.getActiveOrderList({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getActiveOrderList()', async () => { + expect(await api.getActiveOrderList({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('queryActiveOrder()', async () => { - expect(await api.queryActiveOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('queryActiveOrder()', async () => { + expect(await api.queryActiveOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getConditionalOrder()', async () => { - expect(await api.getConditionalOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getConditionalOrder()', async () => { + expect(await api.getConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('queryConditionalOrder()', async () => { - expect(await api.queryConditionalOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('queryConditionalOrder()', async () => { + expect(await api.queryConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getPosition()', async () => { - expect(await api.getPosition()).toMatchObject(successResponseObject()); - }); + it('getPosition()', async () => { + expect(await api.getPosition()).toMatchObject(successResponseObject()); + }); - it('getTradeRecords()', async () => { - expect(await api.getTradeRecords({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getTradeRecords()', async () => { + expect(await api.getTradeRecords({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getClosedPnl()', async () => { - expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getClosedPnl()', async () => { + expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getRiskLimitList()', async () => { - expect(await api.getRiskLimitList()).toMatchObject( - successResponseList('ok') - ); - }); + it('getRiskLimitList()', async () => { + expect(await api.getRiskLimitList()).toMatchObject( + successResponseList('ok') + ); + }); - it('getMyLastFundingFee()', async () => { - expect(await api.getMyLastFundingFee({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getMyLastFundingFee()', async () => { + expect(await api.getMyLastFundingFee({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getPredictedFunding()', async () => { - expect(await api.getPredictedFunding({ symbol: 'BTCUSD' })).toMatchObject( - successResponseObject() - ); - }); + it('getPredictedFunding()', async () => { + expect(await api.getPredictedFunding({ symbol: 'BTCUSD' })).toMatchObject( + successResponseObject() + ); + }); - it('getLcpInfo()', async () => { - expect(await api.getLcpInfo({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getLcpInfo()', async () => { + expect(await api.getLcpInfo({ symbol: symbol })).toMatchObject( + successResponseObject() + ); }); }); diff --git a/test/inverse-futures/private.write.test.ts b/test/inverse-futures/private.write.test.ts new file mode 100644 index 0000000..f79707c --- /dev/null +++ b/test/inverse-futures/private.write.test.ts @@ -0,0 +1,199 @@ +import { InverseFuturesClient } from '../../src'; +import { API_ERROR_CODE } from '../../src/util/enum'; +import { successResponseObject } from '../response.util'; + +describe('Private Inverse-Futures REST API POST Endpoints', () => { + const useLivenet = true; + const API_KEY = process.env.API_KEY_COM; + const API_SECRET = process.env.API_SECRET_COM; + + it('should have api credentials to test with', () => { + expect(API_KEY).toStrictEqual(expect.any(String)); + expect(API_SECRET).toStrictEqual(expect.any(String)); + }); + + const api = new InverseFuturesClient(API_KEY, API_SECRET, useLivenet, { + disable_time_sync: true, + }); + + // Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol! + const symbol = 'BTCUSDU22'; + + // These tests are primarily check auth is working by expecting balance or order not found style errors + + it('placeActiveOrder()', async () => { + expect( + await api.placeActiveOrder({ + side: 'Buy', + symbol, + order_type: 'Limit', + price: 30000, + qty: 1, + time_in_force: 'GoodTillCancel', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.POSITION_IDX_NOT_MATCH_POSITION_MODE, + ret_msg: 'position idx not match position mode', + }); + }); + + it('cancelActiveOrder()', async () => { + expect( + await api.cancelActiveOrder({ + symbol, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to cancel', + }); + }); + + it('cancelAllActiveOrders()', async () => { + expect( + await api.cancelAllActiveOrders({ + symbol, + }) + ).toMatchObject(successResponseObject()); + }); + + it('replaceActiveOrder()', async () => { + expect( + await api.replaceActiveOrder({ + symbol, + order_id: '123123123', + p_r_qty: '1', + p_r_price: '30000', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to replace', + }); + }); + + it('placeConditionalOrder()', async () => { + expect( + await api.placeConditionalOrder({ + order_type: 'Limit', + side: 'Buy', + symbol, + qty: '1', + price: '8100', + base_price: '8300', + stop_px: '8150', + time_in_force: 'GoodTillCancel', + order_link_id: 'cus_order_id_1', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.POSITION_IDX_NOT_MATCH_POSITION_MODE, + ret_msg: 'position idx not match position mode', + }); + }); + + it('cancelConditionalOrder()', async () => { + expect( + await api.cancelConditionalOrder({ + symbol, + order_link_id: 'lkasmdflasd', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to cancel', + }); + }); + + it('cancelAllConditionalOrders()', async () => { + expect( + await api.cancelAllConditionalOrders({ + symbol, + }) + ).toMatchObject(successResponseObject()); + }); + + it('replaceConditionalOrder()', async () => { + expect( + await api.replaceConditionalOrder({ + symbol, + p_r_price: '50000', + p_r_qty: 1, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to replace', + }); + }); + + it('changePositionMargin()', async () => { + expect( + await api.changePositionMargin({ + symbol, + margin: '10', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.POSITION_IDX_NOT_MATCH_POSITION_MODE, + ret_msg: 'position idx not match position mode', + }); + }); + + it('setTradingStop()', async () => { + expect( + await api.setTradingStop({ + symbol, + take_profit: 50000, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.POSITION_STATUS_NOT_NORMAL, + ret_msg: 'position status is not normal', + }); + }); + + it('setUserLeverage()', async () => { + expect( + await api.setUserLeverage({ + symbol, + buy_leverage: 5, + sell_leverage: 5, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.LEVERAGE_NOT_MODIFIED, + ret_msg: 'leverage not modified', + }); + }); + + it('setPositionMode()', async () => { + expect( + await api.setPositionMode({ + symbol, + mode: 3, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.POSITION_MODE_NOT_MODIFIED, + ret_msg: 'position mode not modified', + }); + }); + + it('setMarginType()', async () => { + expect( + await api.setMarginType({ + symbol, + is_isolated: false, + buy_leverage: 5, + sell_leverage: 5, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ISOLATED_NOT_MODIFIED, + ret_msg: 'Isolated not modified', + }); + }); + + it('setRiskLimit()', async () => { + expect( + await api.setRiskLimit({ + symbol, + risk_id: 'myriskid', + }) + ).toMatchObject({ + ret_code: -1, + ret_msg: `Currently not support symbol[${symbol}]`, + }); + }); +}); From 61c278c31886e6c47dfdde8f8340fde21e10cf8b Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Wed, 11 May 2022 18:12:44 +0100 Subject: [PATCH 17/24] expand test coverage to linear endpoints --- src/linear-client.ts | 10 +- src/util/enum.ts | 10 ++ test/linear/private.read.test.ts | 142 +++++++++--------- test/linear/private.write.test.ts | 231 ++++++++++++++++++++++++++++++ 4 files changed, 311 insertions(+), 82 deletions(-) create mode 100644 test/linear/private.write.test.ts diff --git a/src/linear-client.ts b/src/linear-client.ts index e5842fb..94d4ac3 100644 --- a/src/linear-client.ts +++ b/src/linear-client.ts @@ -386,14 +386,6 @@ export class LinearClient extends BaseRestClient { ); } - /** @deprecated use setPositionTpSlMode() instead */ - setSwitchMode(params?: { - symbol: string; - tp_sl_mode: typeof positionTpSlModeEnum[keyof typeof positionTpSlModeEnum]; - }): GenericAPIResponse { - return this.requestWrapper.post('private/linear/tpsl/switch-mode', params); - } - /** * Switch TP/SL mode between full or partial. When set to Partial, TP/SL orders may have a quantity less than the position size. * This is set with the setTradingStop() method. Use `positionTpSlModeEnum` for the tp_sl_mode parameter. @@ -477,7 +469,7 @@ export class LinearClient extends BaseRestClient { setRiskLimit(params: { symbol: string; side: string; - risk_id: string; + risk_id: number; }): GenericAPIResponse { return this.requestWrapper.post('private/linear/position/set-risk', params); } diff --git a/src/util/enum.ts b/src/util/enum.ts index 152f3d4..fb36dc5 100644 --- a/src/util/enum.ts +++ b/src/util/enum.ts @@ -1,4 +1,5 @@ export const API_ERROR_CODE = { + PARAMS_MISSING_OR_WRONG: 10001, ORDER_NOT_FOUND_OR_TOO_LATE: 20001, POSITION_STATUS_NOT_NORMAL: 30013, CANNOT_SET_TRADING_STOP_FOR_ZERO_POS: 30024, @@ -14,4 +15,13 @@ export const API_ERROR_CODE = { RISK_LIMIT_NOT_EXISTS: 30090, LEVERAGE_NOT_MODIFIED: 34036, SAME_SLTP_MODE: 37002, + ORDER_NOT_FOUND_OR_TOO_LATE_LINEAR: 130010, + ORDER_COST_NOT_AVAILABLE: 130021, + CANNOT_SET_LINEAR_TRADING_STOP_FOR_ZERO_POS: 130024, + ISOLATED_NOT_MODIFIED_LINEAR: 130056, + POSITION_SIZE_IS_ZERO: 130057, + AUTO_ADD_MARGIN_NOT_MODIFIED: 130060, + INSUFFICIENT_BALANCE_FOR_ORDER_COST_LINEAR: 130080, + SAME_SLTP_MODE_LINEAR: 130150, + RISK_ID_NOT_MODIFIED: 134026, } as const; diff --git a/test/linear/private.read.test.ts b/test/linear/private.read.test.ts index f061cf7..fea1db4 100644 --- a/test/linear/private.read.test.ts +++ b/test/linear/private.read.test.ts @@ -1,7 +1,7 @@ import { LinearClient } from '../../src/linear-client'; import { successResponseList, successResponseObject } from '../response.util'; -describe('Public Linear REST API Endpoints', () => { +describe('Public Linear REST API GET Endpoints', () => { const useLivenet = true; const API_KEY = process.env.API_KEY_COM; const API_SECRET = process.env.API_SECRET_COM; @@ -17,91 +17,87 @@ describe('Public Linear REST API Endpoints', () => { const symbol = 'BTCUSDT'; - describe('Linear only private GET endpoints', () => { - it('getApiKeyInfo()', async () => { - expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject()); - }); + it('getApiKeyInfo()', async () => { + expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject()); + }); - it('getWalletBalance()', async () => { - expect(await api.getWalletBalance()).toMatchObject( - successResponseObject() - ); - }); + it('getWalletBalance()', async () => { + expect(await api.getWalletBalance()).toMatchObject(successResponseObject()); + }); - it('getWalletFundRecords()', async () => { - expect(await api.getWalletFundRecords()).toMatchObject( - successResponseObject() - ); - }); + it('getWalletFundRecords()', async () => { + expect(await api.getWalletFundRecords()).toMatchObject( + successResponseObject() + ); + }); - it('getWithdrawRecords()', async () => { - expect(await api.getWithdrawRecords()).toMatchObject( - successResponseObject() - ); - }); + it('getWithdrawRecords()', async () => { + expect(await api.getWithdrawRecords()).toMatchObject( + successResponseObject() + ); + }); - it('getAssetExchangeRecords()', async () => { - expect(await api.getAssetExchangeRecords()).toMatchObject( - successResponseList() - ); - }); + it('getAssetExchangeRecords()', async () => { + expect(await api.getAssetExchangeRecords()).toMatchObject( + successResponseList() + ); + }); - it('getActiveOrderList()', async () => { - expect(await api.getActiveOrderList({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getActiveOrderList()', async () => { + expect(await api.getActiveOrderList({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('queryActiveOrder()', async () => { - expect(await api.queryActiveOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('queryActiveOrder()', async () => { + expect(await api.queryActiveOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getConditionalOrder()', async () => { - expect(await api.getConditionalOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getConditionalOrder()', async () => { + expect(await api.getConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('queryConditionalOrder()', async () => { - expect(await api.queryConditionalOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('queryConditionalOrder()', async () => { + expect(await api.queryConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getPosition()', async () => { - expect(await api.getPosition()).toMatchObject(successResponseObject()); - }); + it('getPosition()', async () => { + expect(await api.getPosition()).toMatchObject(successResponseObject()); + }); - it('getTradeRecords()', async () => { - expect(await api.getTradeRecords({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getTradeRecords()', async () => { + expect(await api.getTradeRecords({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getClosedPnl()', async () => { - expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getClosedPnl()', async () => { + expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getRiskLimitList()', async () => { - expect(await api.getRiskLimitList({ symbol: symbol })).toMatchObject( - successResponseList() - ); - }); + it('getRiskLimitList()', async () => { + expect(await api.getRiskLimitList({ symbol: symbol })).toMatchObject( + successResponseList() + ); + }); - it('getPredictedFundingFee()', async () => { - expect( - await api.getPredictedFundingFee({ symbol: symbol }) - ).toMatchObject(successResponseObject()); - }); + it('getPredictedFundingFee()', async () => { + expect(await api.getPredictedFundingFee({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getLastFundingFee()', async () => { - expect(await api.getLastFundingFee({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getLastFundingFee()', async () => { + expect(await api.getLastFundingFee({ symbol: symbol })).toMatchObject( + successResponseObject() + ); }); }); diff --git a/test/linear/private.write.test.ts b/test/linear/private.write.test.ts new file mode 100644 index 0000000..dec3a40 --- /dev/null +++ b/test/linear/private.write.test.ts @@ -0,0 +1,231 @@ +import { LinearClient } from '../../src'; +import { API_ERROR_CODE } from '../../src/util/enum'; +import { successResponseObject } from '../response.util'; + +describe('Private Inverse-Futures REST API POST Endpoints', () => { + const useLivenet = true; + const API_KEY = process.env.API_KEY_COM; + const API_SECRET = process.env.API_SECRET_COM; + + it('should have api credentials to test with', () => { + expect(API_KEY).toStrictEqual(expect.any(String)); + expect(API_SECRET).toStrictEqual(expect.any(String)); + }); + + const api = new LinearClient(API_KEY, API_SECRET, useLivenet, { + disable_time_sync: true, + }); + + // Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol! + const symbol = 'BTCUSDT'; + + // These tests are primarily check auth is working by expecting balance or order not found style errors + + it('placeActiveOrder()', async () => { + expect( + await api.placeActiveOrder({ + side: 'Buy', + symbol, + order_type: 'Limit', + price: 20000, + qty: 1, + time_in_force: 'GoodTillCancel', + reduce_only: false, + close_on_trigger: false, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_COST_NOT_AVAILABLE, + }); + }); + + it('cancelActiveOrder()', async () => { + expect( + await api.cancelActiveOrder({ + symbol, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to cancel', + }); + }); + + it('cancelAllActiveOrders()', async () => { + expect( + await api.cancelAllActiveOrders({ + symbol, + }) + ).toMatchObject(successResponseObject()); + }); + + it('replaceActiveOrder()', async () => { + expect( + await api.replaceActiveOrder({ + symbol, + order_id: '123123123', + p_r_qty: 1, + p_r_price: 30000, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to replace', + }); + }); + + it('placeConditionalOrder()', async () => { + expect( + await api.placeConditionalOrder({ + order_type: 'Limit', + side: 'Buy', + symbol, + qty: 1, + price: 8100, + base_price: 8300, + stop_px: 8150, + time_in_force: 'GoodTillCancel', + order_link_id: 'cus_order_id_1', + reduce_only: false, + trigger_by: 'LastPrice', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.INSUFFICIENT_BALANCE_FOR_ORDER_COST_LINEAR, + ret_msg: 'Insufficient wallet balance', + }); + }); + + it('cancelConditionalOrder()', async () => { + expect( + await api.cancelConditionalOrder({ + symbol, + order_link_id: 'lkasmdflasd', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE_LINEAR, + ret_msg: 'order not exists or too late to cancel', + }); + }); + + it('cancelAllConditionalOrders()', async () => { + expect( + await api.cancelAllConditionalOrders({ + symbol, + }) + ).toMatchObject(successResponseObject()); + }); + + it('replaceConditionalOrder()', async () => { + expect( + await api.replaceConditionalOrder({ + symbol, + p_r_price: 50000, + p_r_qty: 1, + order_link_id: 'someorderid', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE_LINEAR, + ret_msg: 'order not exists or too late to replace', + }); + }); + + it('setAutoAddMargin()', async () => { + expect( + await api.setAutoAddMargin({ + symbol, + side: 'Buy', + auto_add_margin: true, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.AUTO_ADD_MARGIN_NOT_MODIFIED, + ret_msg: 'autoAddMargin not modified', + }); + }); + + it('setMarginSwitch()', async () => { + expect( + await api.setMarginSwitch({ + symbol, + is_isolated: true, + buy_leverage: 5, + sell_leverage: 5, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ISOLATED_NOT_MODIFIED_LINEAR, + ret_msg: 'Isolated not modified', + }); + }); + + it('setPositionMode()', async () => { + expect( + await api.setPositionMode({ + symbol, + mode: 'BothSide', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.POSITION_MODE_NOT_MODIFIED, + ret_msg: 'position mode not modified', + }); + }); + + it('setPositionTpSlMode()', async () => { + expect( + await api.setPositionTpSlMode({ + symbol, + tp_sl_mode: 'Full', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.SAME_SLTP_MODE_LINEAR, + ret_msg: 'same tp sl mode2', + }); + }); + + it('setAddReduceMargin()', async () => { + expect( + await api.setAddReduceMargin({ + symbol, + side: 'Buy', + margin: 5, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.POSITION_SIZE_IS_ZERO, + ret_msg: 'position size is zero', + }); + }); + + it('setUserLeverage()', async () => { + expect( + await api.setUserLeverage({ + symbol, + buy_leverage: 5, + sell_leverage: 5, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.LEVERAGE_NOT_MODIFIED, + ret_msg: 'leverage not modified', + }); + }); + + it('setTradingStop()', async () => { + expect( + await api.setTradingStop({ + symbol, + side: 'Buy', + take_profit: 555, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.CANNOT_SET_LINEAR_TRADING_STOP_FOR_ZERO_POS, + ret_msg: 'can not set tp/sl/ts for zero position', + }); + }); + + it('setRiskLimit()', async () => { + expect( + await api.setRiskLimit({ + symbol, + side: 'Buy', + risk_id: 2, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.RISK_ID_NOT_MODIFIED, + ret_msg: 'risk id not modified', + }); + }); +}); From a89cb5148e2dcc5f8b3a38a41e72336eb181e8fa Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Wed, 11 May 2022 18:13:16 +0100 Subject: [PATCH 18/24] deprecate request wrapper completely --- src/inverse-client.ts | 45 +++----- src/inverse-futures-client.ts | 66 +++--------- src/linear-client.ts | 65 +++--------- src/util/requestWrapper.ts | 191 ---------------------------------- 4 files changed, 44 insertions(+), 323 deletions(-) delete mode 100644 src/util/requestWrapper.ts diff --git a/src/inverse-client.ts b/src/inverse-client.ts index 0dbd297..8dbbbf9 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -5,7 +5,6 @@ import { RestClientOptions, REST_CLIENT_TYPE_ENUM, } from './util/requestUtils'; -import RequestWrapper from './util/requestWrapper'; import { APIResponseWithTime, AssetExchangeRecordsReq, @@ -21,9 +20,6 @@ import { import BaseRestClient from './util/BaseRestClient'; export class InverseClient extends BaseRestClient { - /** @deprecated, */ - protected requestWrapper: RequestWrapper; - /** * @public Creates an instance of the inverse REST API client. * @@ -48,13 +44,6 @@ export class InverseClient extends BaseRestClient { requestOptions, REST_CLIENT_TYPE_ENUM.inverse ); - this.requestWrapper = new RequestWrapper( - key, - secret, - getRestBaseUrl(useLivenet, restClientOptions), - { ...restClientOptions, disable_time_sync: true }, - requestOptions - ); return this; } @@ -211,7 +200,7 @@ export class InverseClient extends BaseRestClient { close_on_trigger?: boolean; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/order/create', orderRequest); + return this.postPrivate('v2/private/order/create', orderRequest); } getActiveOrderList(params: { @@ -229,11 +218,11 @@ export class InverseClient extends BaseRestClient { order_id?: string; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/order/cancel', params); + return this.postPrivate('v2/private/order/cancel', params); } cancelAllActiveOrders(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.post('v2/private/order/cancelAll', params); + return this.postPrivate('v2/private/order/cancelAll', params); } replaceActiveOrder(params: { @@ -247,7 +236,7 @@ export class InverseClient extends BaseRestClient { tp_trigger_by?: string; sl_trigger_by?: string; }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/order/replace', params); + return this.postPrivate('v2/private/order/replace', params); } queryActiveOrder(params: { @@ -275,7 +264,7 @@ export class InverseClient extends BaseRestClient { close_on_trigger?: boolean; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/stop-order/create', params); + return this.postPrivate('v2/private/stop-order/create', params); } /** get conditional order list. This may see delays, use queryConditionalOrder() for real-time queries */ @@ -294,11 +283,11 @@ export class InverseClient extends BaseRestClient { stop_order_id?: string; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/stop-order/cancel', params); + return this.postPrivate('v2/private/stop-order/cancel', params); } cancelAllConditionalOrders(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.post('v2/private/stop-order/cancelAll', params); + return this.postPrivate('v2/private/stop-order/cancelAll', params); } replaceConditionalOrder(params: { @@ -309,7 +298,7 @@ export class InverseClient extends BaseRestClient { p_r_price?: string; p_r_trigger_price?: string; }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/stop-order/replace', params); + return this.postPrivate('v2/private/stop-order/replace', params); } queryConditionalOrder(params: { @@ -332,7 +321,7 @@ export class InverseClient extends BaseRestClient { symbol: string; margin: string; }): GenericAPIResponse { - return this.requestWrapper.post('position/change-position-margin', params); + return this.postPrivate('position/change-position-margin', params); } setTradingStop(params: { @@ -344,7 +333,7 @@ export class InverseClient extends BaseRestClient { sl_trigger_by?: string; new_trailing_active?: number; }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/position/trading-stop', params); + return this.postPrivate('v2/private/position/trading-stop', params); } setUserLeverage(params: { @@ -352,10 +341,7 @@ export class InverseClient extends BaseRestClient { leverage: number; leverage_only?: boolean; }): GenericAPIResponse { - return this.requestWrapper.post( - 'v2/private/position/leverage/save', - params - ); + return this.postPrivate('v2/private/position/leverage/save', params); } getTradeRecords(params: { @@ -384,7 +370,7 @@ export class InverseClient extends BaseRestClient { symbol: string; tp_sl_mode: 'Full' | 'Partial'; }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/tpsl/switch-mode', params); + return this.postPrivate('v2/private/tpsl/switch-mode', params); } setMarginType(params: { @@ -393,10 +379,7 @@ export class InverseClient extends BaseRestClient { buy_leverage: number; sell_leverage: number; }): GenericAPIResponse { - return this.requestWrapper.post( - 'v2/private/position/switch-isolated', - params - ); + return this.postPrivate('v2/private/position/switch-isolated', params); } /** @@ -411,7 +394,7 @@ export class InverseClient extends BaseRestClient { symbol: string; risk_id: string; }): GenericAPIResponse { - return this.requestWrapper.post('open-api/wallet/risk-limit', params); + return this.postPrivate('open-api/wallet/risk-limit', params); } /** diff --git a/src/inverse-futures-client.ts b/src/inverse-futures-client.ts index e4e1dc7..c835ffe 100644 --- a/src/inverse-futures-client.ts +++ b/src/inverse-futures-client.ts @@ -5,7 +5,6 @@ import { RestClientOptions, REST_CLIENT_TYPE_ENUM, } from './util/requestUtils'; -import RequestWrapper from './util/requestWrapper'; import { APIResponseWithTime, AssetExchangeRecordsReq, @@ -21,9 +20,6 @@ import { import BaseRestClient from './util/BaseRestClient'; export class InverseFuturesClient extends BaseRestClient { - /** @deprecated, */ - protected requestWrapper: RequestWrapper; - /** * @public Creates an instance of the inverse futures REST API client. * @@ -48,13 +44,6 @@ export class InverseFuturesClient extends BaseRestClient { requestOptions, REST_CLIENT_TYPE_ENUM.inverseFutures ); - this.requestWrapper = new RequestWrapper( - key, - secret, - getRestBaseUrl(useLivenet, restClientOptions), - { ...restClientOptions, disable_time_sync: true }, - requestOptions - ); return this; } @@ -212,10 +201,7 @@ export class InverseFuturesClient extends BaseRestClient { close_on_trigger?: boolean; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post( - 'futures/private/order/create', - orderRequest - ); + return this.postPrivate('futures/private/order/create', orderRequest); } getActiveOrderList(params: { @@ -233,11 +219,11 @@ export class InverseFuturesClient extends BaseRestClient { order_id?: string; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post('futures/private/order/cancel', params); + return this.postPrivate('futures/private/order/cancel', params); } cancelAllActiveOrders(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.post('futures/private/order/cancelAll', params); + return this.postPrivate('futures/private/order/cancelAll', params); } replaceActiveOrder(params: { @@ -247,7 +233,7 @@ export class InverseFuturesClient extends BaseRestClient { p_r_qty?: string; p_r_price?: string; }): GenericAPIResponse { - return this.requestWrapper.post('futures/private/order/replace', params); + return this.postPrivate('futures/private/order/replace', params); } queryActiveOrder(params: { @@ -275,10 +261,7 @@ export class InverseFuturesClient extends BaseRestClient { close_on_trigger?: boolean; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post( - 'futures/private/stop-order/create', - params - ); + return this.postPrivate('futures/private/stop-order/create', params); } getConditionalOrder(params: { @@ -296,17 +279,11 @@ export class InverseFuturesClient extends BaseRestClient { stop_order_id?: string; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post( - 'futures/private/stop-order/cancel', - params - ); + return this.postPrivate('futures/private/stop-order/cancel', params); } cancelAllConditionalOrders(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.post( - 'futures/private/stop-order/cancelAll', - params - ); + return this.postPrivate('futures/private/stop-order/cancelAll', params); } replaceConditionalOrder(params: { @@ -317,10 +294,7 @@ export class InverseFuturesClient extends BaseRestClient { p_r_price?: string; p_r_trigger_price?: string; }): GenericAPIResponse { - return this.requestWrapper.post( - 'futures/private/stop-order/replace', - params - ); + return this.postPrivate('futures/private/stop-order/replace', params); } queryConditionalOrder(params: { @@ -346,7 +320,7 @@ export class InverseFuturesClient extends BaseRestClient { symbol: string; margin: string; }): GenericAPIResponse { - return this.requestWrapper.post( + return this.postPrivate( 'futures/private/position/change-position-margin', params ); @@ -361,10 +335,7 @@ export class InverseFuturesClient extends BaseRestClient { sl_trigger_by?: string; new_trailing_active?: number; }): GenericAPIResponse { - return this.requestWrapper.post( - 'futures/private/position/trading-stop', - params - ); + return this.postPrivate('futures/private/position/trading-stop', params); } setUserLeverage(params: { @@ -372,10 +343,7 @@ export class InverseFuturesClient extends BaseRestClient { buy_leverage: number; sell_leverage: number; }): GenericAPIResponse { - return this.requestWrapper.post( - 'futures/private/position/leverage/save', - params - ); + return this.postPrivate('futures/private/position/leverage/save', params); } /** @@ -385,10 +353,7 @@ export class InverseFuturesClient extends BaseRestClient { symbol: string; mode: number; }): GenericAPIResponse { - return this.requestWrapper.post( - 'futures/private/position/switch-mode', - params - ); + return this.postPrivate('futures/private/position/switch-mode', params); } /** @@ -400,10 +365,7 @@ export class InverseFuturesClient extends BaseRestClient { buy_leverage: number; sell_leverage: number; }): GenericAPIResponse { - return this.requestWrapper.post( - 'futures/private/position/switch-isolated', - params - ); + return this.postPrivate('futures/private/position/switch-isolated', params); } getTradeRecords(params: { @@ -443,7 +405,7 @@ export class InverseFuturesClient extends BaseRestClient { symbol: string; risk_id: string; }): GenericAPIResponse { - return this.requestWrapper.post('open-api/wallet/risk-limit', params); + return this.postPrivate('open-api/wallet/risk-limit', params); } /** diff --git a/src/linear-client.ts b/src/linear-client.ts index 94d4ac3..15a6fa4 100644 --- a/src/linear-client.ts +++ b/src/linear-client.ts @@ -5,7 +5,6 @@ import { RestClientOptions, REST_CLIENT_TYPE_ENUM, } from './util/requestUtils'; -import RequestWrapper from './util/requestWrapper'; import { APIResponse, APIResponseWithTime, @@ -23,9 +22,6 @@ import { linearPositionModeEnum, positionTpSlModeEnum } from './constants/enum'; import BaseRestClient from './util/BaseRestClient'; export class LinearClient extends BaseRestClient { - /** @deprecated, */ - protected requestWrapper: RequestWrapper; - /** * @public Creates an instance of the linear (USD Perps) REST API client. * @@ -50,14 +46,6 @@ export class LinearClient extends BaseRestClient { requestOptions, REST_CLIENT_TYPE_ENUM.linear ); - - this.requestWrapper = new RequestWrapper( - key, - secret, - getRestBaseUrl(useLivenet, restClientOptions), - { ...restClientOptions, disable_time_sync: true }, - requestOptions - ); return this; } @@ -215,7 +203,7 @@ export class LinearClient extends BaseRestClient { order_link_id?: string; position_idx?: number; }): GenericAPIResponse { - return this.requestWrapper.post('private/linear/order/create', params); + return this.postPrivate('private/linear/order/create', params); } getActiveOrderList(params: { @@ -235,11 +223,11 @@ export class LinearClient extends BaseRestClient { order_id?: string; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post('private/linear/order/cancel', params); + return this.postPrivate('private/linear/order/cancel', params); } cancelAllActiveOrders(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.post('private/linear/order/cancel-all', params); + return this.postPrivate('private/linear/order/cancel-all', params); } replaceActiveOrder(params: { @@ -253,7 +241,7 @@ export class LinearClient extends BaseRestClient { tp_trigger_by?: string; sl_trigger_by?: string; }): GenericAPIResponse { - return this.requestWrapper.post('private/linear/order/replace', params); + return this.postPrivate('private/linear/order/replace', params); } queryActiveOrder(params: { @@ -286,7 +274,7 @@ export class LinearClient extends BaseRestClient { tp_trigger_by?: string; sl_trigger_by?: string; }): GenericAPIResponse { - return this.requestWrapper.post('private/linear/stop-order/create', params); + return this.postPrivate('private/linear/stop-order/create', params); } getConditionalOrder(params: { @@ -306,14 +294,11 @@ export class LinearClient extends BaseRestClient { stop_order_id?: string; order_link_id?: string; }): GenericAPIResponse { - return this.requestWrapper.post('private/linear/stop-order/cancel', params); + return this.postPrivate('private/linear/stop-order/cancel', params); } cancelAllConditionalOrders(params: SymbolParam): GenericAPIResponse { - return this.requestWrapper.post( - 'private/linear/stop-order/cancel-all', - params - ); + return this.postPrivate('private/linear/stop-order/cancel-all', params); } replaceConditionalOrder(params: { @@ -328,10 +313,7 @@ export class LinearClient extends BaseRestClient { tp_trigger_by?: string; sl_trigger_by?: string; }): GenericAPIResponse { - return this.requestWrapper.post( - 'private/linear/stop-order/replace', - params - ); + return this.postPrivate('private/linear/stop-order/replace', params); } queryConditionalOrder(params: { @@ -355,7 +337,7 @@ export class LinearClient extends BaseRestClient { side: string; auto_add_margin: boolean; }): GenericAPIResponse { - return this.requestWrapper.post( + return this.postPrivate( 'private/linear/position/set-auto-add-margin', params ); @@ -367,10 +349,7 @@ export class LinearClient extends BaseRestClient { buy_leverage: number; sell_leverage: number; }): GenericAPIResponse { - return this.requestWrapper.post( - 'private/linear/position/switch-isolated', - params - ); + return this.postPrivate('private/linear/position/switch-isolated', params); } /** @@ -380,10 +359,7 @@ export class LinearClient extends BaseRestClient { symbol: string; mode: typeof linearPositionModeEnum[keyof typeof linearPositionModeEnum]; }): GenericAPIResponse { - return this.requestWrapper.post( - 'private/linear/position/switch-mode', - params - ); + return this.postPrivate('private/linear/position/switch-mode', params); } /** @@ -394,7 +370,7 @@ export class LinearClient extends BaseRestClient { symbol: string; tp_sl_mode: typeof positionTpSlModeEnum[keyof typeof positionTpSlModeEnum]; }): GenericAPIResponse { - return this.requestWrapper.post('private/linear/tpsl/switch-mode', params); + return this.postPrivate('private/linear/tpsl/switch-mode', params); } setAddReduceMargin(params?: { @@ -402,10 +378,7 @@ export class LinearClient extends BaseRestClient { side: string; margin: number; }): GenericAPIResponse { - return this.requestWrapper.post( - 'private/linear/position/add-margin', - params - ); + return this.postPrivate('private/linear/position/add-margin', params); } setUserLeverage(params: { @@ -413,10 +386,7 @@ export class LinearClient extends BaseRestClient { buy_leverage: number; sell_leverage: number; }): GenericAPIResponse { - return this.requestWrapper.post( - 'private/linear/position/set-leverage', - params - ); + return this.postPrivate('private/linear/position/set-leverage', params); } setTradingStop(params: { @@ -430,10 +400,7 @@ export class LinearClient extends BaseRestClient { sl_size?: number; tp_size?: number; }): GenericAPIResponse { - return this.requestWrapper.post( - 'private/linear/position/trading-stop', - params - ); + return this.postPrivate('private/linear/position/trading-stop', params); } getTradeRecords(params: { @@ -471,7 +438,7 @@ export class LinearClient extends BaseRestClient { side: string; risk_id: number; }): GenericAPIResponse { - return this.requestWrapper.post('private/linear/position/set-risk', params); + return this.postPrivate('private/linear/position/set-risk', params); } /** diff --git a/src/util/requestWrapper.ts b/src/util/requestWrapper.ts deleted file mode 100644 index be0e9c2..0000000 --- a/src/util/requestWrapper.ts +++ /dev/null @@ -1,191 +0,0 @@ -import axios, { AxiosRequestConfig, AxiosResponse, Method } from 'axios'; - -import { signMessage } from './node-support'; -import { serializeParams, RestClientOptions, GenericAPIResponse, isPublicEndpoint } from './requestUtils'; - -export default class RequestUtil { - private timeOffset: number | null; - private syncTimePromise: null | Promise; - private options: RestClientOptions; - private baseUrl: string; - private globalRequestOptions: AxiosRequestConfig; - private key: string | undefined; - private secret: string | undefined; - - constructor( - key: string | undefined, - secret: string | undefined, - baseUrl: string, - options: RestClientOptions = {}, - requestOptions: AxiosRequestConfig = {} - ) { - this.timeOffset = null; - this.syncTimePromise = null; - - this.options = { - recv_window: 5000, - // how often to sync time drift with bybit servers - sync_interval_ms: 3600000, - // if true, we'll throw errors if any params are undefined - strict_param_validation: false, - ...options - }; - - this.globalRequestOptions = { - // in ms == 5 minutes by default - timeout: 1000 * 60 * 5, - // custom request options based on axios specs - see: https://github.com/axios/axios#request-config - ...requestOptions, - headers: { - 'x-referer': 'bybitapinode' - }, - }; - - this.baseUrl = baseUrl; - - if (key && !secret) { - throw new Error('API Key & Secret are both required for private enpoints') - } - - if (this.options.disable_time_sync !== true) { - this.syncTime(); - setInterval(this.syncTime.bind(this), +this.options.sync_interval_ms!); - } - - this.key = key; - this.secret = secret; - } - - get(endpoint: string, params?: any): Promise { - return this._call('GET', endpoint, params); - } - - post(endpoint: string, params?: any): Promise { - return this._call('POST', endpoint, params); - } - - /** - * @private Make a HTTP request to a specific endpoint. Private endpoints are automatically signed. - */ - async _call(method: Method, endpoint: string, params?: any): Promise { - if (!isPublicEndpoint(endpoint)) { - if (!this.key || !this.secret) { - throw new Error('Private endpoints require api and private keys set'); - } - - if (this.timeOffset === null) { - await this.syncTime(); - } - - params = await this.signRequest(params); - } - - const options = { - ...this.globalRequestOptions, - url: [this.baseUrl, endpoint].join('/'), - method: method, - json: true - }; - - if (method === 'GET') { - options.params = params; - } else { - options.data = params; - } - - return axios(options).then(response => { - if (response.status == 200) { - return response.data; - } - - throw response; - }).catch(e => this.parseException(e)); - } - - /** - * @private generic handler to parse request exceptions - */ - parseException(e: any): unknown { - if (this.options.parse_exceptions === false) { - throw e; - } - - // Something happened in setting up the request that triggered an Error - if (!e.response) { - if (!e.request) { - throw e.message; - } - - // request made but no response received - throw e; - } - - // The request was made and the server responded with a status code - // that falls out of the range of 2xx - const response: AxiosResponse = e.response; - throw { - code: response.status, - message: response.statusText, - body: response.data, - headers: response.headers, - requestOptions: this.options - }; - } - - /** - * @private sign request and set recv window - */ - async signRequest(data: any): Promise { - const params = { - ...data, - api_key: this.key, - timestamp: Date.now() + (this.timeOffset || 0) - }; - - // Optional, set to 5000 by default. Increase if timestamp/recv_window errors are seen. - if (this.options.recv_window && !params.recv_window) { - params.recv_window = this.options.recv_window; - } - - if (this.key && this.secret) { - const serializedParams = serializeParams(params, this.options.strict_param_validation); - params.sign = await signMessage(serializedParams, this.secret); - } - - return params; - } - - /** - * @private trigger time sync and store promise - */ - syncTime(): GenericAPIResponse { - if (this.options.disable_time_sync === true) { - return Promise.resolve(false); - } - - if (this.syncTimePromise !== null) { - return this.syncTimePromise; - } - - this.syncTimePromise = this.getTimeOffset().then(offset => { - this.timeOffset = offset; - this.syncTimePromise = null; - }); - - return this.syncTimePromise; - } - - /** - * @deprecated move this somewhere else, because v2/public/time shouldn't be hardcoded here - * - * @returns {Promise} - * @memberof RequestUtil - */ - async getTimeOffset(): Promise { - const start = Date.now(); - const result = await this.get('v2/public/time'); - const end = Date.now(); - - return Math.ceil((result.time_now * 1000) - end + ((end - start) / 2)); - } -}; From 326caac96a035317c6a4c865365f097bc7d120ab Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Wed, 11 May 2022 23:58:53 +0100 Subject: [PATCH 19/24] cleaning around api response types --- src/inverse-client.ts | 75 +++++++++++++++++++-------------- src/inverse-futures-client.ts | 77 +++++++++++++++++++--------------- src/linear-client.ts | 79 ++++++++++++++++++++--------------- src/spot-client.ts | 29 +++++++++---- src/util/BaseRestClient.ts | 32 +++++++------- src/util/requestUtils.ts | 2 - 6 files changed, 172 insertions(+), 122 deletions(-) diff --git a/src/inverse-client.ts b/src/inverse-client.ts index 8dbbbf9..9c8064b 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -1,6 +1,5 @@ import { AxiosRequestConfig } from 'axios'; import { - GenericAPIResponse, getRestBaseUrl, RestClientOptions, REST_CLIENT_TYPE_ENUM, @@ -133,7 +132,7 @@ export class InverseClient extends BaseRestClient { * */ - getApiKeyInfo(): GenericAPIResponse { + getApiKeyInfo(): Promise> { return this.getPrivate('v2/private/account/api-key'); } @@ -143,21 +142,27 @@ export class InverseClient extends BaseRestClient { * */ - getWalletBalance(params?: Partial): GenericAPIResponse { + getWalletBalance( + params?: Partial + ): Promise> { return this.getPrivate('v2/private/wallet/balance', params); } - getWalletFundRecords(params?: WalletFundRecordsReq): GenericAPIResponse { + getWalletFundRecords( + params?: WalletFundRecordsReq + ): Promise> { return this.getPrivate('v2/private/wallet/fund/records', params); } - getWithdrawRecords(params?: WithdrawRecordsReq): GenericAPIResponse { + getWithdrawRecords( + params?: WithdrawRecordsReq + ): Promise> { return this.getPrivate('v2/private/wallet/withdraw/list', params); } getAssetExchangeRecords( params?: AssetExchangeRecordsReq - ): GenericAPIResponse { + ): Promise> { return this.getPrivate('v2/private/exchange-order/list', params); } @@ -199,7 +204,7 @@ export class InverseClient extends BaseRestClient { sl_trigger_by?: 'LastPrice' | 'MarkPrice' | 'IndexPrice'; close_on_trigger?: boolean; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('v2/private/order/create', orderRequest); } @@ -209,7 +214,7 @@ export class InverseClient extends BaseRestClient { direction?: string; limit?: number; cursor?: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('v2/private/order/list', params); } @@ -217,11 +222,13 @@ export class InverseClient extends BaseRestClient { symbol: string; order_id?: string; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('v2/private/order/cancel', params); } - cancelAllActiveOrders(params: SymbolParam): GenericAPIResponse { + cancelAllActiveOrders( + params: SymbolParam + ): Promise> { return this.postPrivate('v2/private/order/cancelAll', params); } @@ -235,7 +242,7 @@ export class InverseClient extends BaseRestClient { stop_loss?: number; tp_trigger_by?: string; sl_trigger_by?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('v2/private/order/replace', params); } @@ -243,7 +250,7 @@ export class InverseClient extends BaseRestClient { order_id?: string; order_link_id?: string; symbol: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('v2/private/order', params); } @@ -263,7 +270,7 @@ export class InverseClient extends BaseRestClient { trigger_by?: string; close_on_trigger?: boolean; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('v2/private/stop-order/create', params); } @@ -274,7 +281,7 @@ export class InverseClient extends BaseRestClient { direction?: string; limit?: number; cursor?: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('v2/private/stop-order/list', params); } @@ -282,11 +289,13 @@ export class InverseClient extends BaseRestClient { symbol: string; stop_order_id?: string; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('v2/private/stop-order/cancel', params); } - cancelAllConditionalOrders(params: SymbolParam): GenericAPIResponse { + cancelAllConditionalOrders( + params: SymbolParam + ): Promise> { return this.postPrivate('v2/private/stop-order/cancelAll', params); } @@ -297,7 +306,7 @@ export class InverseClient extends BaseRestClient { p_r_qty?: number; p_r_price?: string; p_r_trigger_price?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('v2/private/stop-order/replace', params); } @@ -305,7 +314,7 @@ export class InverseClient extends BaseRestClient { symbol: string; stop_order_id?: string; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('v2/private/stop-order', params); } @@ -313,14 +322,16 @@ export class InverseClient extends BaseRestClient { * Position */ - getPosition(params?: Partial): GenericAPIResponse { + getPosition( + params?: Partial + ): Promise> { return this.getPrivate('v2/private/position/list', params); } changePositionMargin(params: { symbol: string; margin: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('position/change-position-margin', params); } @@ -332,7 +343,7 @@ export class InverseClient extends BaseRestClient { tp_trigger_by?: string; sl_trigger_by?: string; new_trailing_active?: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('v2/private/position/trading-stop', params); } @@ -340,7 +351,7 @@ export class InverseClient extends BaseRestClient { symbol: string; leverage: number; leverage_only?: boolean; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('v2/private/position/leverage/save', params); } @@ -351,7 +362,7 @@ export class InverseClient extends BaseRestClient { page?: number; limit?: number; order?: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('v2/private/execution/list', params); } @@ -362,14 +373,14 @@ export class InverseClient extends BaseRestClient { exec_type?: string; page?: number; limit?: number; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('v2/private/trade/closed-pnl/list', params); } setSlTpPositionMode(params: { symbol: string; tp_sl_mode: 'Full' | 'Partial'; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('v2/private/tpsl/switch-mode', params); } @@ -378,7 +389,7 @@ export class InverseClient extends BaseRestClient { is_isolated: boolean; buy_leverage: number; sell_leverage: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('v2/private/position/switch-isolated', params); } @@ -386,14 +397,14 @@ export class InverseClient extends BaseRestClient { * Risk Limit */ - getRiskLimitList(): GenericAPIResponse { + getRiskLimitList(): Promise> { return this.getPrivate('open-api/wallet/risk-limit/list'); } setRiskLimit(params: { symbol: string; risk_id: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('open-api/wallet/risk-limit', params); } @@ -401,15 +412,15 @@ export class InverseClient extends BaseRestClient { * Funding */ - getLastFundingRate(params: SymbolParam): GenericAPIResponse { + getLastFundingRate(params: SymbolParam): Promise> { return this.get('v2/public/funding/prev-funding-rate', params); } - getMyLastFundingFee(params: SymbolParam): GenericAPIResponse { + getMyLastFundingFee(params: SymbolParam): Promise> { return this.getPrivate('v2/private/funding/prev-funding', params); } - getPredictedFunding(params: SymbolParam): GenericAPIResponse { + getPredictedFunding(params: SymbolParam): Promise> { return this.getPrivate('v2/private/funding/predicted-funding', params); } @@ -417,7 +428,7 @@ export class InverseClient extends BaseRestClient { * LCP Info */ - getLcpInfo(params: SymbolParam): GenericAPIResponse { + getLcpInfo(params: SymbolParam): Promise> { return this.getPrivate('v2/private/account/lcp', params); } } diff --git a/src/inverse-futures-client.ts b/src/inverse-futures-client.ts index c835ffe..afe16ef 100644 --- a/src/inverse-futures-client.ts +++ b/src/inverse-futures-client.ts @@ -1,6 +1,5 @@ import { AxiosRequestConfig } from 'axios'; import { - GenericAPIResponse, getRestBaseUrl, RestClientOptions, REST_CLIENT_TYPE_ENUM, @@ -136,7 +135,7 @@ export class InverseFuturesClient extends BaseRestClient { * */ - getApiKeyInfo(): GenericAPIResponse { + getApiKeyInfo(): Promise> { return this.getPrivate('v2/private/account/api-key'); } @@ -146,21 +145,27 @@ export class InverseFuturesClient extends BaseRestClient { * */ - getWalletBalance(params?: Partial): GenericAPIResponse { + getWalletBalance( + params?: Partial + ): Promise> { return this.getPrivate('v2/private/wallet/balance', params); } - getWalletFundRecords(params?: WalletFundRecordsReq): GenericAPIResponse { + getWalletFundRecords( + params?: WalletFundRecordsReq + ): Promise> { return this.getPrivate('v2/private/wallet/fund/records', params); } - getWithdrawRecords(params?: WithdrawRecordsReq): GenericAPIResponse { + getWithdrawRecords( + params?: WithdrawRecordsReq + ): Promise> { return this.getPrivate('v2/private/wallet/withdraw/list', params); } getAssetExchangeRecords( params?: AssetExchangeRecordsReq - ): GenericAPIResponse { + ): Promise> { return this.getPrivate('v2/private/exchange-order/list', params); } @@ -174,7 +179,7 @@ export class InverseFuturesClient extends BaseRestClient { return this.get('v2/public/time'); } - getApiAnnouncements(): GenericAPIResponse { + getApiAnnouncements(): Promise> { return this.get('v2/public/announcement'); } @@ -200,7 +205,7 @@ export class InverseFuturesClient extends BaseRestClient { reduce_only?: boolean; close_on_trigger?: boolean; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('futures/private/order/create', orderRequest); } @@ -210,7 +215,7 @@ export class InverseFuturesClient extends BaseRestClient { direction?: string; limit?: number; cursor?: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('futures/private/order/list', params); } @@ -218,11 +223,13 @@ export class InverseFuturesClient extends BaseRestClient { symbol: string; order_id?: string; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('futures/private/order/cancel', params); } - cancelAllActiveOrders(params: SymbolParam): GenericAPIResponse { + cancelAllActiveOrders( + params: SymbolParam + ): Promise> { return this.postPrivate('futures/private/order/cancelAll', params); } @@ -232,7 +239,7 @@ export class InverseFuturesClient extends BaseRestClient { symbol: string; p_r_qty?: string; p_r_price?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('futures/private/order/replace', params); } @@ -240,7 +247,7 @@ export class InverseFuturesClient extends BaseRestClient { order_id?: string; order_link_id?: string; symbol: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('futures/private/order', params); } @@ -260,7 +267,7 @@ export class InverseFuturesClient extends BaseRestClient { trigger_by?: string; close_on_trigger?: boolean; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('futures/private/stop-order/create', params); } @@ -270,7 +277,7 @@ export class InverseFuturesClient extends BaseRestClient { direction?: string; limit?: number; cursor?: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('futures/private/stop-order/list', params); } @@ -278,11 +285,13 @@ export class InverseFuturesClient extends BaseRestClient { symbol: string; stop_order_id?: string; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('futures/private/stop-order/cancel', params); } - cancelAllConditionalOrders(params: SymbolParam): GenericAPIResponse { + cancelAllConditionalOrders( + params: SymbolParam + ): Promise> { return this.postPrivate('futures/private/stop-order/cancelAll', params); } @@ -293,7 +302,7 @@ export class InverseFuturesClient extends BaseRestClient { p_r_qty?: number; p_r_price?: string; p_r_trigger_price?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('futures/private/stop-order/replace', params); } @@ -301,7 +310,7 @@ export class InverseFuturesClient extends BaseRestClient { symbol: string; stop_order_id?: string; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('futures/private/stop-order', params); } @@ -312,14 +321,16 @@ export class InverseFuturesClient extends BaseRestClient { /** * Get position list */ - getPosition(params?: Partial): GenericAPIResponse { + getPosition( + params?: Partial + ): Promise> { return this.getPrivate('futures/private/position/list', params); } changePositionMargin(params: { symbol: string; margin: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate( 'futures/private/position/change-position-margin', params @@ -334,7 +345,7 @@ export class InverseFuturesClient extends BaseRestClient { tp_trigger_by?: string; sl_trigger_by?: string; new_trailing_active?: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('futures/private/position/trading-stop', params); } @@ -342,7 +353,7 @@ export class InverseFuturesClient extends BaseRestClient { symbol: string; buy_leverage: number; sell_leverage: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('futures/private/position/leverage/save', params); } @@ -352,7 +363,7 @@ export class InverseFuturesClient extends BaseRestClient { setPositionMode(params: { symbol: string; mode: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('futures/private/position/switch-mode', params); } @@ -364,7 +375,7 @@ export class InverseFuturesClient extends BaseRestClient { is_isolated: boolean; buy_leverage: number; sell_leverage: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('futures/private/position/switch-isolated', params); } @@ -375,7 +386,7 @@ export class InverseFuturesClient extends BaseRestClient { page?: number; limit?: number; order?: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('futures/private/execution/list', params); } @@ -386,7 +397,7 @@ export class InverseFuturesClient extends BaseRestClient { exec_type?: string; page?: number; limit?: number; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('futures/private/trade/closed-pnl/list', params); } @@ -397,14 +408,14 @@ export class InverseFuturesClient extends BaseRestClient { /** * Risk Limit */ - getRiskLimitList(): GenericAPIResponse { + getRiskLimitList(): Promise> { return this.getPrivate('open-api/wallet/risk-limit/list'); } setRiskLimit(params: { symbol: string; risk_id: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('open-api/wallet/risk-limit', params); } @@ -412,15 +423,15 @@ export class InverseFuturesClient extends BaseRestClient { * Funding */ - getLastFundingRate(params: SymbolParam): GenericAPIResponse { + getLastFundingRate(params: SymbolParam): Promise> { return this.get('v2/public/funding/prev-funding-rate', params); } - getMyLastFundingFee(params: SymbolParam): GenericAPIResponse { + getMyLastFundingFee(params: SymbolParam): Promise> { return this.getPrivate('v2/private/funding/prev-funding', params); } - getPredictedFunding(params: SymbolParam): GenericAPIResponse { + getPredictedFunding(params: SymbolParam): Promise> { return this.getPrivate('v2/private/funding/predicted-funding', params); } @@ -428,7 +439,7 @@ export class InverseFuturesClient extends BaseRestClient { * LCP Info */ - getLcpInfo(params: SymbolParam): GenericAPIResponse { + getLcpInfo(params: SymbolParam): Promise> { return this.getPrivate('v2/private/account/lcp', params); } } diff --git a/src/linear-client.ts b/src/linear-client.ts index 15a6fa4..dd34456 100644 --- a/src/linear-client.ts +++ b/src/linear-client.ts @@ -1,6 +1,5 @@ import { AxiosRequestConfig } from 'axios'; import { - GenericAPIResponse, getRestBaseUrl, RestClientOptions, REST_CLIENT_TYPE_ENUM, @@ -139,7 +138,7 @@ export class LinearClient extends BaseRestClient { * */ - getApiKeyInfo(): GenericAPIResponse { + getApiKeyInfo(): Promise> { return this.getPrivate('v2/private/account/api-key'); } @@ -149,21 +148,27 @@ export class LinearClient extends BaseRestClient { * */ - getWalletBalance(params?: Partial): GenericAPIResponse { + getWalletBalance( + params?: Partial + ): Promise> { return this.getPrivate('v2/private/wallet/balance', params); } - getWalletFundRecords(params?: WalletFundRecordsReq): GenericAPIResponse { + getWalletFundRecords( + params?: WalletFundRecordsReq + ): Promise> { return this.getPrivate('v2/private/wallet/fund/records', params); } - getWithdrawRecords(params?: WithdrawRecordsReq): GenericAPIResponse { + getWithdrawRecords( + params?: WithdrawRecordsReq + ): Promise> { return this.getPrivate('v2/private/wallet/withdraw/list', params); } getAssetExchangeRecords( params?: AssetExchangeRecordsReq - ): GenericAPIResponse { + ): Promise> { return this.getPrivate('v2/private/exchange-order/list', params); } @@ -177,7 +182,7 @@ export class LinearClient extends BaseRestClient { return this.get('v2/public/time'); } - getApiAnnouncements(): GenericAPIResponse { + getApiAnnouncements(): Promise> { return this.get('v2/public/announcement'); } @@ -202,7 +207,7 @@ export class LinearClient extends BaseRestClient { close_on_trigger: boolean; order_link_id?: string; position_idx?: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/order/create', params); } @@ -214,7 +219,7 @@ export class LinearClient extends BaseRestClient { page?: number; limit?: number; order_status?: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('private/linear/order/list', params); } @@ -222,11 +227,13 @@ export class LinearClient extends BaseRestClient { symbol: string; order_id?: string; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/order/cancel', params); } - cancelAllActiveOrders(params: SymbolParam): GenericAPIResponse { + cancelAllActiveOrders( + params: SymbolParam + ): Promise> { return this.postPrivate('private/linear/order/cancel-all', params); } @@ -240,7 +247,7 @@ export class LinearClient extends BaseRestClient { stop_loss?: number; tp_trigger_by?: string; sl_trigger_by?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/order/replace', params); } @@ -248,7 +255,7 @@ export class LinearClient extends BaseRestClient { order_id?: string; order_link_id?: string; symbol: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('private/linear/order/search', params); } @@ -273,7 +280,7 @@ export class LinearClient extends BaseRestClient { stop_loss?: number; tp_trigger_by?: string; sl_trigger_by?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/stop-order/create', params); } @@ -285,7 +292,7 @@ export class LinearClient extends BaseRestClient { order?: string; page?: number; limit?: number; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('private/linear/stop-order/list', params); } @@ -293,11 +300,13 @@ export class LinearClient extends BaseRestClient { symbol: string; stop_order_id?: string; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/stop-order/cancel', params); } - cancelAllConditionalOrders(params: SymbolParam): GenericAPIResponse { + cancelAllConditionalOrders( + params: SymbolParam + ): Promise> { return this.postPrivate('private/linear/stop-order/cancel-all', params); } @@ -312,7 +321,7 @@ export class LinearClient extends BaseRestClient { stop_loss?: number; tp_trigger_by?: string; sl_trigger_by?: string; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/stop-order/replace', params); } @@ -320,7 +329,7 @@ export class LinearClient extends BaseRestClient { symbol: string; stop_order_id?: string; order_link_id?: string; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('private/linear/stop-order/search', params); } @@ -328,7 +337,9 @@ export class LinearClient extends BaseRestClient { * Position */ - getPosition(params?: Partial): GenericAPIResponse { + getPosition( + params?: Partial + ): Promise> { return this.getPrivate('private/linear/position/list', params); } @@ -336,7 +347,7 @@ export class LinearClient extends BaseRestClient { symbol: string; side: string; auto_add_margin: boolean; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate( 'private/linear/position/set-auto-add-margin', params @@ -348,7 +359,7 @@ export class LinearClient extends BaseRestClient { is_isolated: boolean; buy_leverage: number; sell_leverage: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/position/switch-isolated', params); } @@ -358,7 +369,7 @@ export class LinearClient extends BaseRestClient { setPositionMode(params: { symbol: string; mode: typeof linearPositionModeEnum[keyof typeof linearPositionModeEnum]; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/position/switch-mode', params); } @@ -369,7 +380,7 @@ export class LinearClient extends BaseRestClient { setPositionTpSlMode(params: { symbol: string; tp_sl_mode: typeof positionTpSlModeEnum[keyof typeof positionTpSlModeEnum]; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/tpsl/switch-mode', params); } @@ -377,7 +388,7 @@ export class LinearClient extends BaseRestClient { symbol: string; side: string; margin: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/position/add-margin', params); } @@ -385,7 +396,7 @@ export class LinearClient extends BaseRestClient { symbol: string; buy_leverage: number; sell_leverage: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/position/set-leverage', params); } @@ -399,7 +410,7 @@ export class LinearClient extends BaseRestClient { sl_trigger_by?: string; sl_size?: number; tp_size?: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/position/trading-stop', params); } @@ -410,7 +421,7 @@ export class LinearClient extends BaseRestClient { exec_type?: string; page?: number; limit?: number; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('private/linear/trade/execution/list', params); } @@ -421,7 +432,7 @@ export class LinearClient extends BaseRestClient { exec_type?: string; page?: number; limit?: number; - }): GenericAPIResponse { + }): Promise> { return this.getPrivate('private/linear/trade/closed-pnl/list', params); } @@ -429,7 +440,7 @@ export class LinearClient extends BaseRestClient { * Risk Limit */ - getRiskLimitList(params: SymbolParam): GenericAPIResponse { + getRiskLimitList(params: SymbolParam): Promise> { return this.getPrivate('public/linear/risk-limit', params); } @@ -437,7 +448,7 @@ export class LinearClient extends BaseRestClient { symbol: string; side: string; risk_id: number; - }): GenericAPIResponse { + }): Promise> { return this.postPrivate('private/linear/position/set-risk', params); } @@ -445,11 +456,13 @@ export class LinearClient extends BaseRestClient { * Funding */ - getPredictedFundingFee(params: SymbolParam): GenericAPIResponse { + getPredictedFundingFee( + params: SymbolParam + ): Promise> { return this.getPrivate('private/linear/funding/predicted-funding', params); } - getLastFundingFee(params: SymbolParam): GenericAPIResponse { + getLastFundingFee(params: SymbolParam): Promise> { return this.getPrivate('private/linear/funding/prev-funding', params); } } diff --git a/src/spot-client.ts b/src/spot-client.ts index a4cb849..9b1b7a9 100644 --- a/src/spot-client.ts +++ b/src/spot-client.ts @@ -120,15 +120,15 @@ export class SpotClient extends BaseRestClient { * Account Data Endpoints */ - submitOrder(params: NewSpotOrder) { + submitOrder(params: NewSpotOrder): Promise> { return this.postPrivate('/spot/v1/order', params); } - getOrder(params: SpotOrderQueryById) { + getOrder(params: SpotOrderQueryById): Promise> { return this.getPrivate('/spot/v1/order', params); } - cancelOrder(params: SpotOrderQueryById) { + cancelOrder(params: SpotOrderQueryById): Promise> { return this.deletePrivate('/spot/v1/order', params); } @@ -136,7 +136,7 @@ export class SpotClient extends BaseRestClient { symbol: string; side?: OrderSide; orderTypes: OrderTypeSpot[]; - }) { + }): Promise> { const orderTypes = params.orderTypes ? params.orderTypes.join(',') : undefined; @@ -146,7 +146,11 @@ export class SpotClient extends BaseRestClient { }); } - getOpenOrders(symbol?: string, orderId?: string, limit?: number) { + getOpenOrders( + symbol?: string, + orderId?: string, + limit?: number + ): Promise> { return this.getPrivate('/spot/v1/open-orders', { symbol, orderId, @@ -154,7 +158,11 @@ export class SpotClient extends BaseRestClient { }); } - getPastOrders(symbol?: string, orderId?: string, limit?: number) { + getPastOrders( + symbol?: string, + orderId?: string, + limit?: number + ): Promise> { return this.getPrivate('/spot/v1/history-orders', { symbol, orderId, @@ -162,7 +170,12 @@ export class SpotClient extends BaseRestClient { }); } - getMyTrades(symbol?: string, limit?: number, fromId?: number, toId?: number) { + getMyTrades( + symbol?: string, + limit?: number, + fromId?: number, + toId?: number + ): Promise> { return this.getPrivate('/spot/v1/myTrades', { symbol, limit, @@ -175,7 +188,7 @@ export class SpotClient extends BaseRestClient { * Wallet Data Endpoints */ - getBalances() { + getBalances(): Promise> { return this.getPrivate('/spot/v1/account'); } } diff --git a/src/util/BaseRestClient.ts b/src/util/BaseRestClient.ts index e9296cc..a1a2562 100644 --- a/src/util/BaseRestClient.ts +++ b/src/util/BaseRestClient.ts @@ -1,19 +1,23 @@ -import axios, { - AxiosError, - AxiosRequestConfig, - AxiosResponse, - Method, -} from 'axios'; +import axios, { AxiosRequestConfig, AxiosResponse, Method } from 'axios'; +import { APIResponse, APIResponseWithTime } from '../types/shared'; import { signMessage } from './node-support'; import { RestClientOptions, - GenericAPIResponse, serializeParams, RestClientType, REST_CLIENT_TYPE_ENUM, } from './requestUtils'; +// axios.interceptors.request.use((request) => { +// console.log(new Date(), 'Starting Request', JSON.stringify(request, null, 2)); +// return request; +// }); + +// axios.interceptors.response.use((response) => { +// console.log(new Date(), 'Response:', JSON.stringify(response, null, 2)); +// return response; +// }); interface SignedRequestContext { timestamp: number; @@ -95,23 +99,23 @@ export default abstract class BaseRestClient { return this.clientType === REST_CLIENT_TYPE_ENUM.spot; } - get(endpoint: string, params?: any): GenericAPIResponse { + get(endpoint: string, params?: any) { return this._call('GET', endpoint, params, true); } - post(endpoint: string, params?: any): GenericAPIResponse { + post(endpoint: string, params?: any) { return this._call('POST', endpoint, params, true); } - getPrivate(endpoint: string, params?: any): GenericAPIResponse { + getPrivate(endpoint: string, params?: any) { return this._call('GET', endpoint, params, false); } - postPrivate(endpoint: string, params?: any): GenericAPIResponse { + postPrivate(endpoint: string, params?: any) { return this._call('POST', endpoint, params, false); } - deletePrivate(endpoint: string, params?: any): GenericAPIResponse { + deletePrivate(endpoint: string, params?: any) { return this._call('DELETE', endpoint, params, false); } @@ -142,7 +146,7 @@ export default abstract class BaseRestClient { endpoint: string, params?: any, isPublicApi?: boolean - ): GenericAPIResponse { + ): Promise { const options = { ...this.globalRequestOptions, url: [this.baseUrl, endpoint].join(endpoint.startsWith('/') ? '' : '/'), @@ -247,7 +251,7 @@ export default abstract class BaseRestClient { /** * Trigger time sync and store promise */ - private syncTime(): GenericAPIResponse { + private syncTime(): Promise { if (this.options.disable_time_sync === true) { return Promise.resolve(false); } diff --git a/src/util/requestUtils.ts b/src/util/requestUtils.ts index 08f5ecc..d2cf584 100644 --- a/src/util/requestUtils.ts +++ b/src/util/requestUtils.ts @@ -19,8 +19,6 @@ export interface RestClientOptions { parse_exceptions?: boolean; } -export type GenericAPIResponse = Promise; - export function serializeParams( params: object = {}, strict_validation = false From d1cb97176ac59cac981ded3802c47bb6844cb50c Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 12 May 2022 00:48:23 +0100 Subject: [PATCH 20/24] cleaning, fix and add spot post tests --- src/constants/enum.ts | 31 ++++++++++++ src/index.ts | 1 - src/spot-client.ts | 6 ++- src/util/BaseRestClient.ts | 8 +++- src/util/enum.ts | 27 ----------- src/util/requestUtils.ts | 2 + test/inverse-futures/private.write.test.ts | 3 +- test/inverse/private.write.test.ts | 4 +- test/linear/private.write.test.ts | 3 +- test/spot/private.write.test.ts | 56 ++++++++++++++++++++++ 10 files changed, 105 insertions(+), 36 deletions(-) delete mode 100644 src/util/enum.ts create mode 100644 test/spot/private.write.test.ts diff --git a/src/constants/enum.ts b/src/constants/enum.ts index 06aee36..eca2751 100644 --- a/src/constants/enum.ts +++ b/src/constants/enum.ts @@ -9,3 +9,34 @@ export const positionTpSlModeEnum = { /** Partial take profit/stop loss mode (multiple TP and SL orders can be placed, covering portions of the position) */ Partial: 'Partial', } as const; + +export const API_ERROR_CODE = { + BALANCE_INSUFFICIENT_SPOT: -1131, + ORDER_NOT_FOUND_OR_TOO_LATE_SPOT: -2013, + /** This could mean bad request, incorrect value types or even incorrect/missing values */ + PARAMS_MISSING_OR_WRONG: 10001, + ORDER_NOT_FOUND_OR_TOO_LATE: 20001, + POSITION_STATUS_NOT_NORMAL: 30013, + CANNOT_SET_TRADING_STOP_FOR_ZERO_POS: 30024, + /** Seen when placing an order */ + INSUFFICIENT_BALANCE_FOR_ORDER_COST: 30031, + POSITION_IDX_NOT_MATCH_POSITION_MODE: 30041, + /** Seen if a conditional order is too large */ + INSUFFICIENT_BALANCE: 30042, + /** E.g. trying to change position margin while on cross */ + POSITION_IS_CROSS_MARGIN: 30056, + POSITION_MODE_NOT_MODIFIED: 30083, + ISOLATED_NOT_MODIFIED: 30084, + RISK_LIMIT_NOT_EXISTS: 30090, + LEVERAGE_NOT_MODIFIED: 34036, + SAME_SLTP_MODE: 37002, + ORDER_NOT_FOUND_OR_TOO_LATE_LINEAR: 130010, + ORDER_COST_NOT_AVAILABLE: 130021, + CANNOT_SET_LINEAR_TRADING_STOP_FOR_ZERO_POS: 130024, + ISOLATED_NOT_MODIFIED_LINEAR: 130056, + POSITION_SIZE_IS_ZERO: 130057, + AUTO_ADD_MARGIN_NOT_MODIFIED: 130060, + INSUFFICIENT_BALANCE_FOR_ORDER_COST_LINEAR: 130080, + SAME_SLTP_MODE_LINEAR: 130150, + RISK_ID_NOT_MODIFIED: 134026, +} as const; diff --git a/src/index.ts b/src/index.ts index 941d3ea..75c64d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,5 +7,4 @@ export * from './logger'; export * from './types/shared'; export * from './types/spot'; export * from './util/WsStore'; -export * from './util/enum'; export * from './constants/enum'; diff --git a/src/spot-client.ts b/src/spot-client.ts index 9b1b7a9..9dff7c5 100644 --- a/src/spot-client.ts +++ b/src/spot-client.ts @@ -9,6 +9,7 @@ import { } from './types/spot'; import BaseRestClient from './util/BaseRestClient'; import { + agentSource, getRestBaseUrl, RestClientOptions, REST_CLIENT_TYPE_ENUM, @@ -121,7 +122,10 @@ export class SpotClient extends BaseRestClient { */ submitOrder(params: NewSpotOrder): Promise> { - return this.postPrivate('/spot/v1/order', params); + return this.postPrivate('/spot/v1/order', { + ...params, + agentSource, + }); } getOrder(params: SpotOrderQueryById): Promise> { diff --git a/src/util/BaseRestClient.ts b/src/util/BaseRestClient.ts index a1a2562..790c297 100644 --- a/src/util/BaseRestClient.ts +++ b/src/util/BaseRestClient.ts @@ -7,6 +7,7 @@ import { serializeParams, RestClientType, REST_CLIENT_TYPE_ENUM, + agentSource, } from './requestUtils'; // axios.interceptors.request.use((request) => { @@ -162,8 +163,13 @@ export default abstract class BaseRestClient { const signResult = await this.prepareSignParams(params, isPublicApi); - if (method === 'GET') { + if (method === 'GET' || this.isSpotClient()) { options.params = signResult.paramsWithSign; + if (options.params?.agentSource) { + options.data = { + agentSource: agentSource, + }; + } } else { options.data = signResult.paramsWithSign; } diff --git a/src/util/enum.ts b/src/util/enum.ts deleted file mode 100644 index fb36dc5..0000000 --- a/src/util/enum.ts +++ /dev/null @@ -1,27 +0,0 @@ -export const API_ERROR_CODE = { - PARAMS_MISSING_OR_WRONG: 10001, - ORDER_NOT_FOUND_OR_TOO_LATE: 20001, - POSITION_STATUS_NOT_NORMAL: 30013, - CANNOT_SET_TRADING_STOP_FOR_ZERO_POS: 30024, - /** Seen when placing an order */ - INSUFFICIENT_BALANCE_FOR_ORDER_COST: 30031, - POSITION_IDX_NOT_MATCH_POSITION_MODE: 30041, - /** Seen if a conditional order is too large */ - INSUFFICIENT_BALANCE: 30042, - /** E.g. trying to change position margin while on cross */ - POSITION_IS_CROSS_MARGIN: 30056, - POSITION_MODE_NOT_MODIFIED: 30083, - ISOLATED_NOT_MODIFIED: 30084, - RISK_LIMIT_NOT_EXISTS: 30090, - LEVERAGE_NOT_MODIFIED: 34036, - SAME_SLTP_MODE: 37002, - ORDER_NOT_FOUND_OR_TOO_LATE_LINEAR: 130010, - ORDER_COST_NOT_AVAILABLE: 130021, - CANNOT_SET_LINEAR_TRADING_STOP_FOR_ZERO_POS: 130024, - ISOLATED_NOT_MODIFIED_LINEAR: 130056, - POSITION_SIZE_IS_ZERO: 130057, - AUTO_ADD_MARGIN_NOT_MODIFIED: 130060, - INSUFFICIENT_BALANCE_FOR_ORDER_COST_LINEAR: 130080, - SAME_SLTP_MODE_LINEAR: 130150, - RISK_ID_NOT_MODIFIED: 134026, -} as const; diff --git a/src/util/requestUtils.ts b/src/util/requestUtils.ts index d2cf584..621fb3b 100644 --- a/src/util/requestUtils.ts +++ b/src/util/requestUtils.ts @@ -85,6 +85,8 @@ export function isWsPong(response: any) { ); } +export const agentSource = 'bybitapinode'; + export const REST_CLIENT_TYPE_ENUM = { inverse: 'inverse', inverseFutures: 'inverseFutures', diff --git a/test/inverse-futures/private.write.test.ts b/test/inverse-futures/private.write.test.ts index f79707c..a2b6965 100644 --- a/test/inverse-futures/private.write.test.ts +++ b/test/inverse-futures/private.write.test.ts @@ -1,5 +1,4 @@ -import { InverseFuturesClient } from '../../src'; -import { API_ERROR_CODE } from '../../src/util/enum'; +import { API_ERROR_CODE, InverseFuturesClient } from '../../src'; import { successResponseObject } from '../response.util'; describe('Private Inverse-Futures REST API POST Endpoints', () => { diff --git a/test/inverse/private.write.test.ts b/test/inverse/private.write.test.ts index 8577c3d..2153c33 100644 --- a/test/inverse/private.write.test.ts +++ b/test/inverse/private.write.test.ts @@ -1,6 +1,6 @@ +import { API_ERROR_CODE } from '../../src'; import { InverseClient } from '../../src/inverse-client'; -import { API_ERROR_CODE } from '../../src/util/enum'; -import { successResponseList, successResponseObject } from '../response.util'; +import { successResponseObject } from '../response.util'; describe('Private Inverse REST API Endpoints', () => { const useLivenet = true; diff --git a/test/linear/private.write.test.ts b/test/linear/private.write.test.ts index dec3a40..9a987ae 100644 --- a/test/linear/private.write.test.ts +++ b/test/linear/private.write.test.ts @@ -1,5 +1,4 @@ -import { LinearClient } from '../../src'; -import { API_ERROR_CODE } from '../../src/util/enum'; +import { API_ERROR_CODE, LinearClient } from '../../src'; import { successResponseObject } from '../response.util'; describe('Private Inverse-Futures REST API POST Endpoints', () => { diff --git a/test/spot/private.write.test.ts b/test/spot/private.write.test.ts new file mode 100644 index 0000000..811d9e4 --- /dev/null +++ b/test/spot/private.write.test.ts @@ -0,0 +1,56 @@ +import { API_ERROR_CODE, SpotClient } from '../../src'; +import { successResponseObject } from '../response.util'; + +describe('Private Inverse-Futures REST API POST Endpoints', () => { + const useLivenet = true; + const API_KEY = process.env.API_KEY_COM; + const API_SECRET = process.env.API_SECRET_COM; + + it('should have api credentials to test with', () => { + expect(API_KEY).toStrictEqual(expect.any(String)); + expect(API_SECRET).toStrictEqual(expect.any(String)); + }); + + const api = new SpotClient(API_KEY, API_SECRET, useLivenet, { + disable_time_sync: true, + }); + + // Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol! + const symbol = 'BTCUSDT'; + + // These tests are primarily check auth is working by expecting balance or order not found style errors + + it('submitOrder()', async () => { + expect( + await api.submitOrder({ + side: 'Buy', + symbol, + qty: 10000, + type: 'MARKET', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.BALANCE_INSUFFICIENT_SPOT, + ret_msg: 'Balance insufficient ', + }); + }); + + it('cancelOrder()', async () => { + expect( + await api.cancelOrder({ + orderId: '1231231', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE_SPOT, + ret_msg: 'Order does not exist.', + }); + }); + + it('cancelOrderBatch()', async () => { + expect( + await api.cancelOrderBatch({ + symbol, + orderTypes: ['LIMIT', 'LIMIT_MAKER'], + }) + ).toMatchObject(successResponseObject('')); + }); +}); From e306b7a3a084450014309a7d986419040ccc795e Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 12 May 2022 01:15:26 +0100 Subject: [PATCH 21/24] v2.2.0: extensive integration tests, revise base REST client, fix Spot REST client, type improvements --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7751980..4ee162d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bybit-api", - "version": "2.1.10", + "version": "2.2.0", "description": "Node.js connector for Bybit's REST APIs and WebSockets, with TypeScript & integration tests.", "main": "lib/index.js", "types": "lib/index.d.ts", From 1a6b4cc269f9c07d23c99a665f1ab08f4e725beb Mon Sep 17 00:00:00 2001 From: codefactor-io Date: Thu, 12 May 2022 00:19:44 +0000 Subject: [PATCH 22/24] [CodeFactor] Apply fixes --- src/util/BaseRestClient.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/util/BaseRestClient.ts b/src/util/BaseRestClient.ts index 790c297..cfef8d9 100644 --- a/src/util/BaseRestClient.ts +++ b/src/util/BaseRestClient.ts @@ -36,12 +36,19 @@ interface SignedRequest { export default abstract class BaseRestClient { private timeOffset: number | null; + private syncTimePromise: null | Promise; + private options: RestClientOptions; + private baseUrl: string; + private globalRequestOptions: AxiosRequestConfig; + private key: string | undefined; + private secret: string | undefined; + private clientType: RestClientType; /** Function that calls exchange API to query & resolve server time, used by time sync */ From f0088f32c2d1f721f0638439021bc082cd693c79 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Thu, 12 May 2022 01:23:49 +0100 Subject: [PATCH 23/24] run linter --- package-lock.json | 4 ++-- package.json | 2 +- src/logger.ts | 4 ++-- src/util/BaseRestClient.ts | 8 -------- src/util/browser-support.ts | 25 ++++++++++++++++--------- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3249949..23d7244 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "bybit-api", - "version": "2.1.10", + "version": "2.2.0-beta.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "bybit-api", - "version": "2.1.10", + "version": "2.2.0-beta.1", "license": "MIT", "dependencies": { "axios": "^0.21.0", diff --git a/package.json b/package.json index 4ee162d..931465d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bybit-api", - "version": "2.2.0", + "version": "2.2.0-beta.1", "description": "Node.js connector for Bybit's REST APIs and WebSockets, with TypeScript & integration tests.", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/logger.ts b/src/logger.ts index 0f5f29e..e74187c 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -18,5 +18,5 @@ export const DefaultLogger = { }, error: (...params: LogParams): void => { console.error(params); - } -}; \ No newline at end of file + }, +}; diff --git a/src/util/BaseRestClient.ts b/src/util/BaseRestClient.ts index cfef8d9..6e19922 100644 --- a/src/util/BaseRestClient.ts +++ b/src/util/BaseRestClient.ts @@ -1,5 +1,4 @@ import axios, { AxiosRequestConfig, AxiosResponse, Method } from 'axios'; -import { APIResponse, APIResponseWithTime } from '../types/shared'; import { signMessage } from './node-support'; import { @@ -36,19 +35,12 @@ interface SignedRequest { export default abstract class BaseRestClient { private timeOffset: number | null; - private syncTimePromise: null | Promise; - private options: RestClientOptions; - private baseUrl: string; - private globalRequestOptions: AxiosRequestConfig; - private key: string | undefined; - private secret: string | undefined; - private clientType: RestClientType; /** Function that calls exchange API to query & resolve server time, used by time sync */ diff --git a/src/util/browser-support.ts b/src/util/browser-support.ts index fcaa9ad..b470940 100644 --- a/src/util/browser-support.ts +++ b/src/util/browser-support.ts @@ -1,18 +1,25 @@ - -export async function signMessage(message: string, secret: string): Promise { +export async function signMessage( + message: string, + secret: string +): Promise { const encoder = new TextEncoder(); const key = await window.crypto.subtle.importKey( 'raw', encoder.encode(secret), - {name: 'HMAC', hash: {name: 'SHA-256'}}, + { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign'] ); - const signature = await window.crypto.subtle.sign('HMAC', key, encoder.encode(message)); + const signature = await window.crypto.subtle.sign( + 'HMAC', + key, + encoder.encode(message) + ); - return Array.prototype.map.call( - new Uint8Array(signature), - (x: any) => ('00'+x.toString(16)).slice(-2) - ).join(''); -}; + return Array.prototype.map + .call(new Uint8Array(signature), (x: any) => + ('00' + x.toString(16)).slice(-2) + ) + .join(''); +} From 5783a129a827cb9775a20d65d8f9f67575822109 Mon Sep 17 00:00:00 2001 From: Tiago Date: Sat, 21 May 2022 23:17:45 +0100 Subject: [PATCH 24/24] v2.2.0: Fix Spot REST client, extensive integration tests, revise base REST client, type improvements #150 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 931465d..4ee162d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bybit-api", - "version": "2.2.0-beta.1", + "version": "2.2.0", "description": "Node.js connector for Bybit's REST APIs and WebSockets, with TypeScript & integration tests.", "main": "lib/index.js", "types": "lib/index.d.ts",