From 064985174e34584af0eef27ce9d29bab630a7e34 Mon Sep 17 00:00:00 2001 From: Roger Qiu Date: Mon, 28 Mar 2022 16:04:42 +1100 Subject: [PATCH 001/137] fix: adding dependencies for `async-locks`, `db`, `resources` and `errors` Updating dependencies to bring in new libraries such as locks, resources and errors. Some domains have been updated to use this change. --- package-lock.json | 229 +++++++++------------------ package.json | 7 +- src/acl/ACL.ts | 157 +++++++++--------- src/locks/Locks.ts | 111 +++++++++++++ src/locks/index.ts | 1 + src/nodes/NodeConnectionManager.ts | 13 +- src/schema/Schema.ts | 16 +- src/types.ts | 6 + src/utils/context.ts | 75 --------- src/utils/index.ts | 2 - src/utils/locks.ts | 85 ---------- src/vaults/VaultInternal.ts | 8 +- src/vaults/VaultManager.ts | 23 ++- tests/utils.test.ts | 245 ----------------------------- 14 files changed, 304 insertions(+), 674 deletions(-) create mode 100644 src/locks/Locks.ts create mode 100644 src/locks/index.ts delete mode 100644 src/utils/context.ts delete mode 100644 src/utils/locks.ts diff --git a/package-lock.json b/package-lock.json index eca4f5a4d..18ea12929 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1592,34 +1592,49 @@ } } }, + "@matrixai/async-locks": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.0.0.tgz", + "integrity": "sha512-wpU6L5o/0BhBsjYt4BH2J3L0+yDhxotCi6cRF7QZbm03u/tdq8tgwyOzXe+MPArh+EZhsBrnBOCdUpUhgZNRZQ==", + "requires": { + "@matrixai/resources": "^1.0.0", + "async-mutex": "^0.3.2", + "ts-custom-error": "^3.2.0" + } + }, "@matrixai/db": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-1.1.5.tgz", - "integrity": "sha512-zPpP/J1A3TLRaQKaGa5smualzjW4Rin4K48cpU5/9ThyXfpVBBp/mrkbDfjL/O5z6YTcuGVf2+yLck8tF8kVUw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.2.0.tgz", + "integrity": "sha512-JfcpZ8zbNgdQK3mpHQisCY6TKGUO5+Issh5KDvR3zBtfdSKHJLgrqweDIyLtM9D0RT5jO5HOY+lthI/8Yfi/PA==", "requires": { "@matrixai/async-init": "^1.6.0", - "@matrixai/logger": "^2.0.1", - "@matrixai/workers": "^1.2.3", - "abstract-leveldown": "^7.0.0", - "async-mutex": "^0.3.1", + "@matrixai/errors": "^1.0.1", + "@matrixai/logger": "^2.1.0", + "@matrixai/resources": "^1.0.0", + "@matrixai/workers": "^1.2.5", + "@types/abstract-leveldown": "^7.2.0", "level": "7.0.1", - "levelup": "^5.0.1", - "sublevel-prefixer": "^1.0.0", - "subleveldown": "^5.0.1", - "threads": "^1.6.5", - "ts-custom-error": "^3.2.0" + "threads": "^1.6.5" }, "dependencies": { - "async-mutex": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", - "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", + "@matrixai/errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.0.1.tgz", + "integrity": "sha512-9NbIm3rPMkZz+Ma5tfKduVCWfvYzdHlO89u9mBap7FzJqXkl4yoENjMZm5Do6PvhtIYtRcm6+eTgWvHd6pkdGg==", "requires": { - "tslib": "^2.3.1" + "ts-custom-error": "^3.2.0" } } } }, + "@matrixai/errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.0.1.tgz", + "integrity": "sha512-9NbIm3rPMkZz+Ma5tfKduVCWfvYzdHlO89u9mBap7FzJqXkl4yoENjMZm5Do6PvhtIYtRcm6+eTgWvHd6pkdGg==", + "requires": { + "ts-custom-error": "^3.2.0" + } + }, "@matrixai/id": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/@matrixai/id/-/id-3.3.2.tgz", @@ -1634,6 +1649,11 @@ "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.1.0.tgz", "integrity": "sha512-UmLuXi2PJ03v0Scfl57217RPnjEZDRLlpfdIjIwCfju+kofnhhCI9P7OZu3/FgW147vbvSzWCrrtpwJiLROUUA==" }, + "@matrixai/resources": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@matrixai/resources/-/resources-1.0.0.tgz", + "integrity": "sha512-B1ZkySZwOZTIzhK+YTN4HifOTd1dk1ifDUV8/8WgGho2nUZzIMYms7iDmW/ZHUCkqvWupKY6AYvfwnKBOJJnWg==" + }, "@matrixai/workers": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@matrixai/workers/-/workers-1.2.5.tgz", @@ -1718,6 +1738,11 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, + "@types/abstract-leveldown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-q5veSX6zjUy/DlDhR4Y4cU0k2Ar+DT2LUraP00T19WLmTO6Se1djepCCaqU6nQrwcJ5Hyo/CWqxTzrrFg8eqbQ==" + }, "@types/babel__core": { "version": "7.1.16", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", @@ -2701,12 +2726,9 @@ } }, "catering": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.0.tgz", - "integrity": "sha512-M5imwzQn6y+ODBfgi+cfgZv2hIUI6oYU/0f35Mdb1ujGeqeoI5tOnl9Q13DTH7LW+7er+NYq8stNOKZD/Z3U/A==", - "requires": { - "queue-tick": "^1.0.0" - } + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==" }, "chalk": { "version": "2.4.2", @@ -3356,6 +3378,26 @@ "threads": "^1.6.5", "ts-custom-error": "^3.2.0", "util-callbackify": "^1.0.0" + }, + "dependencies": { + "@matrixai/db": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-1.2.1.tgz", + "integrity": "sha512-1W8TORmRX3q3NugZFn0FTgI0mo/n0nWBTXHKXwwPfxtdyNfi18JCj3HVCwWdToOo87ypnS/mqLDIUTSHbF7F3Q==", + "requires": { + "@matrixai/async-init": "^1.6.0", + "@matrixai/logger": "^2.1.0", + "@matrixai/workers": "^1.2.5", + "abstract-leveldown": "^7.2.0", + "async-mutex": "^0.3.1", + "level": "7.0.1", + "levelup": "^5.1.1", + "sublevel-prefixer": "^1.0.0", + "subleveldown": "^6.0.1", + "threads": "^1.6.5", + "ts-custom-error": "^3.2.0" + } + } } }, "end-of-stream": { @@ -4811,11 +4853,6 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" }, - "immediate": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", - "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" - }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -6506,9 +6543,9 @@ "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==" }, "leveldown": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.0.tgz", - "integrity": "sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.1.tgz", + "integrity": "sha512-88c+E+Eizn4CkQOBHwqlCJaTNEjGpaEIikn1S+cINc5E9HEvJ77bqY4JY/HxT5u0caWqsc3P3DcFIKBI1vHt+A==", "requires": { "abstract-leveldown": "^7.2.0", "napi-macros": "~2.0.0", @@ -7649,11 +7686,6 @@ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, - "queue-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.0.tgz", - "integrity": "sha512-ULWhjjE8BmiICGn3G8+1L9wFpERNxkf8ysxkAer4+TFdRefDaXOCV5m92aMB9FtBVmn/8sETXLXY6BfW7hyaWQ==" - }, "ramda": { "version": "0.27.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", @@ -8645,124 +8677,16 @@ "integrity": "sha1-TuRZ72Y6yFvyj8ZJ17eWX9ppEHM=" }, "subleveldown": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/subleveldown/-/subleveldown-5.0.1.tgz", - "integrity": "sha512-cVqd/URpp7si1HWu5YqQ3vqQkjuolAwHypY1B4itPlS71/lsf6TQPZ2Y0ijT22EYVkvH5ove9JFJf4u7VGPuZw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/subleveldown/-/subleveldown-6.0.1.tgz", + "integrity": "sha512-Cnf+cn2wISXU2xflY1SFIqfX4hG2d6lFk2P5F8RDQLmiqN9Ir4ExNfUFH6xnmizMseM/t+nMsDUKjN9Kw6ShFA==", "requires": { - "abstract-leveldown": "^6.3.0", - "encoding-down": "^6.2.0", + "abstract-leveldown": "^7.2.0", + "encoding-down": "^7.1.0", "inherits": "^2.0.3", "level-option-wrap": "^1.1.0", - "levelup": "^4.4.0", + "levelup": "^5.1.1", "reachdown": "^1.1.0" - }, - "dependencies": { - "abstract-leveldown": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz", - "integrity": "sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ==", - "requires": { - "buffer": "^5.5.0", - "immediate": "^3.2.3", - "level-concat-iterator": "~2.0.0", - "level-supports": "~1.0.0", - "xtend": "~4.0.0" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "deferred-leveldown": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz", - "integrity": "sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw==", - "requires": { - "abstract-leveldown": "~6.2.1", - "inherits": "^2.0.3" - }, - "dependencies": { - "abstract-leveldown": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz", - "integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==", - "requires": { - "buffer": "^5.5.0", - "immediate": "^3.2.3", - "level-concat-iterator": "~2.0.0", - "level-supports": "~1.0.0", - "xtend": "~4.0.0" - } - } - } - }, - "encoding-down": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-6.3.0.tgz", - "integrity": "sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw==", - "requires": { - "abstract-leveldown": "^6.2.1", - "inherits": "^2.0.3", - "level-codec": "^9.0.0", - "level-errors": "^2.0.0" - } - }, - "level-codec": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-9.0.2.tgz", - "integrity": "sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ==", - "requires": { - "buffer": "^5.6.0" - } - }, - "level-concat-iterator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz", - "integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==" - }, - "level-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-2.0.1.tgz", - "integrity": "sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw==", - "requires": { - "errno": "~0.1.1" - } - }, - "level-iterator-stream": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz", - "integrity": "sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.4.0", - "xtend": "^4.0.2" - } - }, - "level-supports": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", - "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", - "requires": { - "xtend": "^4.0.2" - } - }, - "levelup": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-4.4.0.tgz", - "integrity": "sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ==", - "requires": { - "deferred-leveldown": "~5.3.0", - "level-errors": "~2.0.0", - "level-iterator-stream": "~4.0.0", - "level-supports": "~1.0.0", - "xtend": "~4.0.0" - } - } } }, "supports-color": { @@ -9615,11 +9539,6 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index cf62e9042..64d3ae3c1 100644 --- a/package.json +++ b/package.json @@ -73,12 +73,14 @@ "dependencies": { "@grpc/grpc-js": "1.3.7", "@matrixai/async-init": "^1.6.0", - "@matrixai/db": "^1.1.5", + "@matrixai/async-locks": "^2.0.0", + "@matrixai/db": "^3.2.0", + "@matrixai/errors": "^1.0.1", "@matrixai/id": "^3.3.2", "@matrixai/logger": "^2.1.0", + "@matrixai/resources": "^1.0.0", "@matrixai/workers": "^1.2.5", "ajv": "^7.0.4", - "async-mutex": "^0.3.2", "bip39": "^3.0.3", "canonicalize": "^1.0.5", "cheerio": "^1.0.0-rc.5", @@ -100,7 +102,6 @@ "readable-stream": "^3.6.0", "resource-counter": "^1.2.4", "threads": "^1.6.5", - "ts-custom-error": "^3.2.0", "utp-native": "^2.5.3", "uuid": "^8.3.0" }, diff --git a/src/acl/ACL.ts b/src/acl/ACL.ts index 358663d51..2bff1d5f9 100644 --- a/src/acl/ACL.ts +++ b/src/acl/ACL.ts @@ -1,23 +1,32 @@ +import type { + DB, + DBTransaction, + KeyPath, + LevelPath +} from '@matrixai/db'; import type { PermissionId, PermissionIdString, Permission, VaultActions, } from './types'; -import type { DB, DBLevel, DBOp } from '@matrixai/db'; +import type { Locks } from '../locks'; import type { NodeId } from '../nodes/types'; import type { GestaltAction } from '../gestalts/types'; import type { VaultAction, VaultId } from '../vaults/types'; import type { Ref } from '../types'; -import { Mutex } from 'async-mutex'; + import Logger from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; +import { RWLockWriter } from '@matrixai/async-locks'; import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import * as aclUtils from './utils'; import * as aclErrors from './errors'; +import { utils as dbUtils } from '@matrixai/db'; +import { withF } from '@matrixai/resources'; interface ACL extends CreateDestroyStartStop {} @CreateDestroyStartStop( @@ -27,15 +36,17 @@ interface ACL extends CreateDestroyStartStop {} class ACL { static async createACL({ db, + locks, logger = new Logger(this.name), fresh = false, }: { db: DB; + locks: Locks; logger?: Logger; fresh?: boolean; }): Promise { logger.info(`Creating ${this.name}`); - const acl = new ACL({ db, logger }); + const acl = new ACL({ db, locks, logger }); await acl.start({ fresh }); logger.info(`Created ${this.name}`); return acl; @@ -43,24 +54,55 @@ class ACL { protected logger: Logger; protected db: DB; - protected aclDbDomain: string = this.constructor.name; - protected aclPermsDbDomain: Array = [this.aclDbDomain, 'perms']; - protected aclNodesDbDomain: Array = [this.aclDbDomain, 'nodes']; - protected aclVaultsDbDomain: Array = [this.aclDbDomain, 'vaults']; - protected aclDb: DBLevel; - protected aclPermsDb: DBLevel; - protected aclNodesDb: DBLevel; - protected aclVaultsDb: DBLevel; - protected lock: Mutex = new Mutex(); + protected locks: Locks; + + protected aclDbPath: LevelPath = [this.constructor.name]; + /** + * Perms stores PermissionId -> Ref + */ + protected aclPermsDbPath: LevelPath = [this.constructor.name, 'perms']; + /** + * Nodes stores NodeId -> PermissionId + */ + protected aclNodesDbPath: LevelPath = [this.constructor.name, 'nodes']; + /** + * Vaults stores VaultIdString -> Record + * note that the NodeId in each record must be in their own unique gestalt + * the NodeId in each record may be missing if it had been previously deleted + */ + protected aclVaultsDbPath: LevelPath = [this.constructor.name, 'vaults']; + + // lock across the usages of the DB + // it makes sense to use + // Symbol.for("key") + // symbol for is found in teh global registry, if it doesn't exist, it is added to the global registry and returned + // we can identify our locks by this + // to do this, we should have a global lock system in case we want to LOCK across multiple domains + // then other domains can also ensure those locks are being done as well + // and it is a like a PATH for a specific domain + // we can pass a keyPath + // and we can lock a level path + // well right now it can only be a keypath + // this.acquireLock(key: Buffer) + // and we identify our key buffer into a collection + // we can do a collection struce + // the symbols don't quite make sense, since we cannot attach a lock there anyway + // so we have to do this as well + // if it is not the DB problem we can just do this + // this.acquireLock() + + // KeyPath | string | Buffer + // locking an entire level is an interesting idea + // then you could have a very specific locking system + // No more single mutex + // protected lock: Mutex = new Mutex(); + protected generatePermId: () => PermissionId; - constructor({ db, logger }: { db: DB; logger: Logger }) { + constructor({ db, locks, logger }: { db: DB; locks: Locks; logger: Logger }) { this.logger = logger; this.db = db; - } - - get locked(): boolean { - return this.lock.isLocked(); + this.locks = locks; } public async start({ @@ -69,22 +111,9 @@ class ACL { fresh?: boolean; } = {}): Promise { this.logger.info(`Starting ${this.constructor.name}`); - const aclDb = await this.db.level(this.aclDbDomain); - // Perms stores PermissionId -> Ref - const aclPermsDb = await this.db.level(this.aclPermsDbDomain[1], aclDb); - // Nodes stores NodeId -> PermissionId - const aclNodesDb = await this.db.level(this.aclNodesDbDomain[1], aclDb); - // Vaults stores VaultIdString -> Record - // note that the NodeId in each array must be in their own unique gestalt - // the NodeId in each array may be missing if it had been previously deleted - const aclVaultsDb = await this.db.level(this.aclVaultsDbDomain[1], aclDb); if (fresh) { - await aclDb.clear(); + await this.db.clear(this.aclDbPath); } - this.aclDb = aclDb; - this.aclPermsDb = aclPermsDb; - this.aclNodesDb = aclNodesDb; - this.aclVaultsDb = aclVaultsDb; this.generatePermId = aclUtils.createPermIdGenerator(); this.logger.info(`Started ${this.constructor.name}`); } @@ -96,60 +125,36 @@ class ACL { public async destroy() { this.logger.info(`Destroying ${this.constructor.name}`); - const aclDb = await this.db.level(this.aclDbDomain); - await aclDb.clear(); + await this.db.clear(this.aclDbPath); this.logger.info(`Destroyed ${this.constructor.name}`); } - /** - * Run several operations within the same lock - * This does not ensure atomicity of the underlying database - * Database atomicity still depends on the underlying operation - */ - @ready(new aclErrors.ErrorACLNotRunning()) - public async transaction(f: (acl: ACL) => Promise): Promise { - const release = await this.lock.acquire(); - try { - return await f(this); - } finally { - release(); - } - } - - /** - * Transaction wrapper that will not lock if the operation was executed - * within a transaction context - */ - @ready(new aclErrors.ErrorACLNotRunning()) - public async _transaction(f: () => Promise): Promise { - if (this.lock.isLocked()) { - return await f(); - } else { - return await this.transaction(f); - } - } - @ready(new aclErrors.ErrorACLNotRunning()) public async sameNodePerm( nodeId1: NodeId, nodeId2: NodeId, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - const permId1 = await this.db.get( - this.aclNodesDbDomain, - nodeId1.toBuffer(), - true, - ); - const permId2 = await this.db.get( - this.aclNodesDbDomain, - nodeId2.toBuffer(), - true, + const nodeId1Path = [...this.aclNodesDbPath, nodeId1.toBuffer()] as unknown as KeyPath; + const nodeId2Path = [...this.aclNodesDbPath, nodeId2.toBuffer()] as unknown as KeyPath; + if (tran == null) { + return withF( + [ + this.db.transaction(), + this.locks.lockRead( + dbUtils.keyPathToKey(nodeId1Path).toString('binary'), + dbUtils.keyPathToKey(nodeId2Path).toString('binary') + ), + ], + async ([tran]) => this.sameNodePerm(nodeId1, nodeId2, tran) ); - if (permId1 != null && permId2 != null && permId1 === permId2) { - return true; - } - return false; - }); + } + const permId1 = await tran.get(nodeId1Path, true); + const permId2 = await tran.get(nodeId2Path, true); + if (permId1 != null && permId2 != null) { + return IdInternal.fromBuffer(permId1).equals(IdInternal.fromBuffer(permId2)); + } + return false; } @ready(new aclErrors.ErrorACLNotRunning()) diff --git a/src/locks/Locks.ts b/src/locks/Locks.ts new file mode 100644 index 000000000..a91ad1807 --- /dev/null +++ b/src/locks/Locks.ts @@ -0,0 +1,111 @@ +import type { ResourceAcquire, ResourceRelease } from '@matrixai/resources'; +import type { NonEmptyArray } from '@/types'; +import { RWLockWriter } from '@matrixai/async-locks'; + +/** + * Generic dynamic read-write lock collection + * This enables advisory-locking across all domains + */ +class Locks { + protected _locks: Map; + + get locks(): ReadonlyMap { + return this._locks; + } + + /** + * Read-lock a sequence of ids + * The ids will be sorted before locking to ensure lock-hierarchy + * in order to prevent deadlocks + */ + public lockRead(...ids: NonEmptyArray): ResourceAcquire> { + return async () => { + ids.sort(); + const locks: Array<[string, ResourceRelease, RWLockWriter]> = []; + for (const id of ids) { + let lock = this._locks.get(id); + if (lock == null) { + lock = new RWLockWriter(); + this._locks.set(id, lock); + } + let lockRelease: ResourceRelease; + try { + [lockRelease] = await lock.acquireRead(); + } catch (e) { + // Release all intermediate locks in reverse order + locks.reverse(); + for (const [id, lockRelease, lock] of locks) { + await lockRelease(); + if (!lock!.isLocked()) { + this._locks.delete(id); + } + } + throw e; + } + locks.push([id, lockRelease, lock]); + } + return [ + async () => { + // Release all locks in reverse order + locks.reverse(); + for (const [id, lockRelease, lock] of locks) { + await lockRelease(); + if (!lock!.isLocked()) { + this._locks.delete(id); + } + } + }, + locks.map(([,,lock]) => lock) as NonEmptyArray + ]; + }; + } + + /** + * Write-lock a sequence of ids + * The ids will be sorted before locking to ensure lock-hierarchy + * in order to prevent deadlocks + */ + public lockWrite(...ids: NonEmptyArray): ResourceAcquire> { + return async () => { + ids.sort(); + const locks: Array<[string, ResourceRelease, RWLockWriter]> = []; + for (const id of ids) { + let lock = this._locks.get(id); + if (lock == null) { + lock = new RWLockWriter(); + this._locks.set(id, lock); + } + let lockRelease: ResourceRelease; + try { + [lockRelease] = await lock.acquireWrite(); + } catch (e) { + // Release all intermediate locks in reverse order + locks.reverse(); + for (const [id, lockRelease, lock] of locks) { + await lockRelease(); + if (!lock!.isLocked()) { + this._locks.delete(id); + } + } + throw e; + } + locks.push([id, lockRelease, lock]); + } + return [ + async () => { + // Release all locks in reverse order + locks.reverse(); + for (const [id, lockRelease, lock] of locks) { + await lockRelease(); + if (!lock!.isLocked()) { + this._locks.delete(id); + } + } + }, + locks.map(([,,lock]) => lock) as NonEmptyArray + ]; + }; + } +} + +export default Locks; diff --git a/src/locks/index.ts b/src/locks/index.ts new file mode 100644 index 000000000..fe97431ee --- /dev/null +++ b/src/locks/index.ts @@ -0,0 +1 @@ +export { default as Locks } from './Locks'; diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 6160aa60a..5338e0058 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -1,7 +1,7 @@ +import type { ResourceAcquire } from '@matrixai/resources'; import type KeyManager from '../keys/KeyManager'; import type Proxy from '../network/Proxy'; import type { Host, Hostname, Port } from '../network/types'; -import type { ResourceAcquire } from '../utils'; import type { Timer } from '../types'; import type NodeGraph from './NodeGraph'; import type { @@ -24,12 +24,13 @@ import * as networkUtils from '../network/utils'; import * as agentErrors from '../agent/errors'; import * as grpcErrors from '../grpc/errors'; import * as nodesPB from '../proto/js/polykey/v1/nodes/nodes_pb'; -import { RWLock, withF } from '../utils'; +import { withF } from '@matrixai/resources'; +import { RWLockWriter } from '@matrixai/async-locks'; type ConnectionAndLock = { connection?: NodeConnection; timer?: NodeJS.Timer; - lock: RWLock; + lock: RWLockWriter; }; interface NodeConnectionManager extends StartStop {} @@ -231,7 +232,7 @@ class NodeConnectionManager { `Getting connection to ${nodesUtils.encodeNodeId(targetNodeId)}`, ); let connection: NodeConnection | undefined; - let lock: RWLock; + let lock: RWLockWriter; let connAndLock = this.connections.get( targetNodeId.toString() as NodeIdString, ); @@ -260,7 +261,7 @@ class NodeConnectionManager { return await this.establishNodeConnection(targetNodeId, lock); }); } else { - lock = new RWLock(); + lock = new RWLockWriter(); connAndLock = { lock }; this.connections.set( targetNodeId.toString() as NodeIdString, @@ -290,7 +291,7 @@ class NodeConnectionManager { */ protected async establishNodeConnection( targetNodeId: NodeId, - lock: RWLock, + lock: RWLockWriter, ): Promise { const targetAddress = await this.findNode(targetNodeId); // If the stored host is not a valid host (IP address), then we assume it to diff --git a/src/schema/Schema.ts b/src/schema/Schema.ts index 546d81956..33c50fa45 100644 --- a/src/schema/Schema.ts +++ b/src/schema/Schema.ts @@ -1,9 +1,9 @@ import type { StateVersion } from './types'; import type { FileSystem } from '../types'; - import path from 'path'; import Logger from '@matrixai/logger'; import { CreateDestroyStartStop } from '@matrixai/async-init/dist/CreateDestroyStartStop'; +import { RWLockWriter } from '@matrixai/async-locks'; import * as schemaErrors from './errors'; import * as utils from '../utils'; import config from '../config'; @@ -17,14 +17,12 @@ class Schema { public static async createSchema({ statePath, stateVersion = config.stateVersion as StateVersion, - lock = new utils.RWLock(), fs = require('fs'), logger = new Logger(this.name), fresh = false, }: { statePath: string; stateVersion?: StateVersion; - lock?: utils.RWLock; fs?: FileSystem; logger?: Logger; fresh?: boolean; @@ -33,7 +31,6 @@ class Schema { const schema = new Schema({ statePath, stateVersion, - lock, fs, logger, }); @@ -45,20 +42,18 @@ class Schema { public readonly statePath: string; public readonly stateVersionPath: string; public readonly stateVersion: StateVersion; - protected lock: utils.RWLock; + protected lock: RWLockWriter = new RWLockWriter(); protected fs: FileSystem; protected logger: Logger; public constructor({ statePath, stateVersion = config.stateVersion as StateVersion, - lock = new utils.RWLock(), fs = require('fs'), logger, }: { statePath: string; stateVersion?: StateVersion; - lock?: utils.RWLock; fs?: FileSystem; logger?: Logger; }) { @@ -69,7 +64,6 @@ class Schema { config.defaults.stateVersionBase, ); this.stateVersion = stateVersion; - this.lock = lock; this.fs = fs; } @@ -142,7 +136,7 @@ class Schema { } public async readVersion(): Promise { - return await this.lock.withRead(async () => { + return await this.lock.withReadF(async () => { let stateVersionData: string; try { stateVersionData = await this.fs.promises.readFile( @@ -169,7 +163,7 @@ class Schema { } protected async writeVersion(stateVersion: StateVersion): Promise { - return await this.lock.withWrite(async () => { + return await this.lock.withWriteF(async () => { try { await this.fs.promises.writeFile( this.stateVersionPath, @@ -191,7 +185,7 @@ class Schema { * This is only called when the version is older. */ protected async upgradeVersion(_stateVersion: StateVersion): Promise { - return await this.lock.withWrite(async () => { + return await this.lock.withWriteF(async () => { // TODO: to be implemented throw new schemaErrors.ErrorSchemaVersionTooOld(); }); diff --git a/src/types.ts b/src/types.ts index b09954b32..8fba1fc08 100644 --- a/src/types.ts +++ b/src/types.ts @@ -12,6 +12,11 @@ type POJO = { [key: string]: any }; */ type Opaque = T & { __TYPE__: K }; +/** + * Non-empty array + */ +type NonEmptyArray = [T, ...T[]]; + /** * Allows extension of constructors that use POJOs */ @@ -75,6 +80,7 @@ type FileHandle = fs.promises.FileHandle; export type { POJO, Opaque, + NonEmptyArray, AbstractConstructorParameters, Initial, InitialParameters, diff --git a/src/utils/context.ts b/src/utils/context.ts deleted file mode 100644 index d4102debc..000000000 --- a/src/utils/context.ts +++ /dev/null @@ -1,75 +0,0 @@ -type ResourceAcquire = () => Promise< - readonly [ResourceRelease, Resource?] ->; - -type ResourceRelease = () => Promise; - -type Resources[]> = { - [K in keyof T]: T[K] extends ResourceAcquire ? R : never; -}; - -/** - * Make sure to explicitly declare or cast `acquires` as a tuple using `[ResourceAcquire...]` or `as const` - */ -async function withF< - ResourceAcquires extends - | readonly [ResourceAcquire] - | readonly ResourceAcquire[], - T, ->( - acquires: ResourceAcquires, - f: (resources: Resources) => Promise, -): Promise { - const releases: Array = []; - const resources: Array = []; - try { - for (const acquire of acquires) { - const [release, resource] = await acquire(); - releases.push(release); - resources.push(resource); - } - return await f(resources as unknown as Resources); - } finally { - releases.reverse(); - for (const release of releases) { - await release(); - } - } -} - -/** - * Make sure to explicitly declare or cast `acquires` as a tuple using `[ResourceAcquire...]` or `as const` - */ -async function* withG< - ResourceAcquires extends - | readonly [ResourceAcquire] - | readonly ResourceAcquire[], - T = unknown, - TReturn = any, - TNext = unknown, ->( - acquires: ResourceAcquires, - g: ( - resources: Resources, - ) => AsyncGenerator, -): AsyncGenerator { - const releases: Array = []; - const resources: Array = []; - try { - for (const acquire of acquires) { - const [release, resource] = await acquire(); - releases.push(release); - resources.push(resource); - } - return yield* g(resources as unknown as Resources); - } finally { - releases.reverse(); - for (const release of releases) { - await release(); - } - } -} - -export { withF, withG }; - -export type { ResourceAcquire, ResourceRelease }; diff --git a/src/utils/index.ts b/src/utils/index.ts index cbb38a8be..f50908aca 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,6 +1,4 @@ export { default as sysexits } from './sysexits'; -export * from './locks'; -export * from './context'; export * from './utils'; export * from './matchers'; export * from './binary'; diff --git a/src/utils/locks.ts b/src/utils/locks.ts deleted file mode 100644 index eb6f95245..000000000 --- a/src/utils/locks.ts +++ /dev/null @@ -1,85 +0,0 @@ -import type { MutexInterface } from 'async-mutex'; -import { Mutex } from 'async-mutex'; - -/** - * Single threaded write-preferring read write lock - */ -class RWLock { - protected readersLock: Mutex = new Mutex(); - protected writersLock: Mutex = new Mutex(); - protected readersRelease: MutexInterface.Releaser; - protected readerCountBlocked: number = 0; - protected _readerCount: number = 0; - protected _writerCount: number = 0; - - public get readerCount(): number { - return this._readerCount + this.readerCountBlocked; - } - - public get writerCount(): number { - return this._writerCount; - } - - public async withRead(f: () => Promise): Promise { - const release = await this.acquireRead(); - try { - return await f(); - } finally { - release(); - } - } - - public async withWrite(f: () => Promise): Promise { - const release = await this.acquireWrite(); - try { - return await f(); - } finally { - release(); - } - } - - public async acquireRead(): Promise<() => void> { - if (this._writerCount > 0) { - ++this.readerCountBlocked; - await this.writersLock.waitForUnlock(); - --this.readerCountBlocked; - } - const readerCount = ++this._readerCount; - // The first reader locks - if (readerCount === 1) { - this.readersRelease = await this.readersLock.acquire(); - } - return () => { - const readerCount = --this._readerCount; - // The last reader unlocks - if (readerCount === 0) { - this.readersRelease(); - } - }; - } - - public async acquireWrite(): Promise<() => void> { - ++this._writerCount; - const writersRelease = await this.writersLock.acquire(); - this.readersRelease = await this.readersLock.acquire(); - return () => { - this.readersRelease(); - writersRelease(); - --this._writerCount; - }; - } - - public isLocked(): boolean { - return this.readersLock.isLocked() || this.writersLock.isLocked(); - } - - public async waitForUnlock(): Promise { - await Promise.all([ - this.readersLock.waitForUnlock(), - this.writersLock.waitForUnlock(), - ]); - return; - } -} - -export { RWLock }; diff --git a/src/vaults/VaultInternal.ts b/src/vaults/VaultInternal.ts index 63611b1a8..76f87e13b 100644 --- a/src/vaults/VaultInternal.ts +++ b/src/vaults/VaultInternal.ts @@ -1,6 +1,7 @@ import type { ReadCommitResult } from 'isomorphic-git'; import type { EncryptedFS } from 'encryptedfs'; import type { DB, DBDomain, DBLevel } from '@matrixai/db'; +import type { ResourceAcquire } from '@matrixai/resources'; import type { CommitId, CommitLog, @@ -15,7 +16,6 @@ import type { import type KeyManager from '../keys/KeyManager'; import type { NodeId, NodeIdEncoded } from '../nodes/types'; import type NodeConnectionManager from '../nodes/NodeConnectionManager'; -import type { ResourceAcquire } from '../utils/context'; import type GRPCClientAgent from '../agent/GRPCClientAgent'; import type { POJO } from '../types'; import path from 'path'; @@ -26,13 +26,13 @@ import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; +import { withF, withG } from '@matrixai/resources'; +import { RWLockWriter } from '@matrixai/async-locks'; import * as vaultsErrors from './errors'; import * as vaultsUtils from './utils'; import { tagLast } from './types'; import * as nodesUtils from '../nodes/utils'; import * as validationUtils from '../validation/utils'; -import { withF, withG } from '../utils/context'; -import { RWLock } from '../utils/locks'; import * as vaultsPB from '../proto/js/polykey/v1/vaults/vaults_pb'; import { never } from '../utils/utils'; @@ -190,7 +190,7 @@ class VaultInternal { protected vaultsNamesDomain: DBDomain; protected efs: EncryptedFS; protected efsVault: EncryptedFS; - protected lock: RWLock = new RWLock(); + protected lock: RWLockWriter = new RWLockWriter(); public readLock: ResourceAcquire = async () => { const release = await this.lock.acquireRead(); diff --git a/src/vaults/VaultManager.ts b/src/vaults/VaultManager.ts index ed65478f5..71699d1ae 100644 --- a/src/vaults/VaultManager.ts +++ b/src/vaults/VaultManager.ts @@ -1,4 +1,5 @@ import type { DB, DBDomain, DBLevel } from '@matrixai/db'; +import type { ResourceAcquire } from '@matrixai/resources'; import type { VaultId, VaultName, @@ -15,9 +16,7 @@ import type NodeConnectionManager from '../nodes/NodeConnectionManager'; import type GestaltGraph from '../gestalts/GestaltGraph'; import type NotificationsManager from '../notifications/NotificationsManager'; import type ACL from '../acl/ACL'; - import type { RemoteInfo } from './VaultInternal'; -import type { ResourceAcquire } from '../utils/context'; import type { VaultAction } from './types'; import path from 'path'; import { PassThrough } from 'readable-stream'; @@ -28,6 +27,8 @@ import { ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { IdInternal } from '@matrixai/id'; +import { withF, withG } from '@matrixai/resources'; +import { RWLockWriter } from '@matrixai/async-locks'; import VaultInternal from './VaultInternal'; import * as vaultsUtils from '../vaults/utils'; import * as vaultsErrors from '../vaults/errors'; @@ -37,8 +38,6 @@ import * as nodesUtils from '../nodes/utils'; import * as keysUtils from '../keys/utils'; import config from '../config'; import { mkdirExists } from '../utils/utils'; -import { RWLock } from '../utils/locks'; -import { withF, withG } from '../utils/context'; import * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb'; /** @@ -48,7 +47,7 @@ type VaultMap = Map< VaultIdString, { vault?: VaultInternal; - lock: RWLock; + lock: RWLockWriter; } >; @@ -125,7 +124,7 @@ class VaultManager { protected vaultsDb: DBLevel; protected vaultsNamesDbDomain: DBDomain = [...this.vaultsDbDomain, 'names']; protected vaultsNamesDb: DBLevel; - protected vaultsNamesLock: RWLock = new RWLock(); + protected vaultsNamesLock: RWLockWriter = new RWLockWriter(); // VaultId -> VaultMetadata protected vaultMap: VaultMap = new Map(); protected vaultKey: Buffer; @@ -261,11 +260,11 @@ class VaultManager { this.efs.unsetWorkerManager(); } - protected getLock(vaultId: VaultId): RWLock { + protected getLock(vaultId: VaultId): RWLockWriter { const vaultIdString = vaultId.toString() as VaultIdString; const vaultAndLock = this.vaultMap.get(vaultIdString); if (vaultAndLock != null) return vaultAndLock.lock; - const lock = new RWLock(); + const lock = new RWLockWriter(); this.vaultMap.set(vaultIdString, { lock }); return lock; } @@ -314,7 +313,7 @@ class VaultManager { true, ); }); - const lock = new RWLock(); + const lock = new RWLockWriter(); const vaultIdString = vaultId.toString() as VaultIdString; this.vaultMap.set(vaultIdString, { lock }); return await withF([this.getWriteLock(vaultId)], async () => { @@ -556,7 +555,7 @@ class VaultManager { vaultNameOrId: VaultId | VaultName, ): Promise { const vaultId = await this.generateVaultId(); - const lock = new RWLock(); + const lock = new RWLockWriter(); const vaultIdString = vaultId.toString() as VaultIdString; this.vaultMap.set(vaultIdString, { lock }); this.logger.info( @@ -802,7 +801,7 @@ class VaultManager { @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) protected async getVault(vaultId: VaultId): Promise { let vault: VaultInternal | undefined; - let lock: RWLock; + let lock: RWLockWriter; const vaultIdString = vaultId.toString() as VaultIdString; let vaultAndLock = this.vaultMap.get(vaultIdString); if (vaultAndLock != null) { @@ -842,7 +841,7 @@ class VaultManager { } } else { // Neither vault nor lock exists - lock = new RWLock(); + lock = new RWLockWriter(); vaultAndLock = { lock }; this.vaultMap.set(vaultIdString, vaultAndLock); let release; diff --git a/tests/utils.test.ts b/tests/utils.test.ts index 5f6ee891e..1896fbedc 100644 --- a/tests/utils.test.ts +++ b/tests/utils.test.ts @@ -1,6 +1,4 @@ -import type { ResourceAcquire } from '@/utils'; import os from 'os'; -import { Mutex } from 'async-mutex'; import * as utils from '@/utils'; describe('utils', () => { @@ -15,247 +13,4 @@ describe('utils', () => { expect(p).toBe(`${homeDir}/AppData/Local/polykey`); } }); - test('withF resource context', async () => { - // No resources - const result1 = await utils.withF([], async () => { - return 'bar'; - }); - expect(result1).toBe('bar'); - // Noop resource - const result2 = await utils.withF( - [ - async () => { - return [async () => {}]; - }, - ], - async () => { - return 'foo'; - }, - ); - expect(result2).toBe('foo'); - // Counter resource - let counter = 1; - const result3 = await utils.withF( - [ - async () => { - counter++; - return [ - async () => { - counter--; - }, - counter, - ]; - }, - ], - async ([c]) => { - expect(c).toBe(2); - return c / 2; - }, - ); - expect(result3).toBe(1); - expect(counter).toBe(1); - // Multiple resources - const result4 = await utils.withF( - [ - async () => { - return [async () => {}, 123]; - }, - async () => { - return [async () => {}]; - }, - async () => { - return [async () => {}, 'hello world']; - }, - ], - async ([n, u, s]) => { - expect(u).toBe(undefined); - return [n, s]; - }, - ); - expect(result4).toStrictEqual([123, 'hello world']); - // Multiple resources, but only take the first - const result5 = await utils.withF( - [ - async () => { - return [async () => {}, 123]; - }, - async () => { - return [async () => {}]; - }, - async () => { - return [async () => {}, 'hello world']; - }, - ], - async ([n]) => { - return n; - }, - ); - expect(result5).toBe(123); - // Multiple resources outside requires type declaration - const resourceAcquires6: [ - ResourceAcquire, - ResourceAcquire, - ResourceAcquire, - ] = [ - async () => { - return [async () => {}, 123]; - }, - async () => { - return [async () => {}]; - }, - async () => { - return [async () => {}, 'hello world']; - }, - ]; - const result6 = await utils.withF(resourceAcquires6, async ([n, u, s]) => { - expect(u).toBe(undefined); - return [n, s]; - }); - expect(result6).toStrictEqual([123, 'hello world']); - // Multiple resources outside can also use const - const resourceAcquires7 = [ - async () => { - return [async () => {}, 123] as const; - }, - async () => { - return [async () => {}] as const; - }, - async () => { - return [async () => {}, 'hello world'] as const; - }, - ] as const; - const result7 = await utils.withF(resourceAcquires7, async ([n, u, s]) => { - expect(u).toBe(undefined); - return [n, s]; - }); - expect(result7).toStrictEqual([123, 'hello world']); - // It must be given a explicit type, or `as const` can be used internally - const acquire8: ResourceAcquire = async () => { - return [async () => {}, 123]; - }; - const result8 = await utils.withF([acquire8], async () => { - return 'done'; - }); - expect(result8).toBe('done'); - const acquire9 = async () => { - return [async () => {}, 123] as const; - }; - const result9 = await utils.withF([acquire9], async () => { - return 'done'; - }); - expect(result9).toBe('done'); - // Order of acquisition is left to right - // Order of release is right ot left - const lock1 = new Mutex(); - const lock2 = new Mutex(); - const acquireOrder: Array = []; - const releaseOrder: Array = []; - await utils.withF( - [ - async () => { - const release = await lock1.acquire(); - acquireOrder.push(lock1); - return [ - async () => { - releaseOrder.push(lock1); - release(); - }, - lock1, - ]; - }, - async () => { - const release = await lock2.acquire(); - acquireOrder.push(lock2); - return [ - async () => { - releaseOrder.push(lock2); - release(); - }, - lock2, - ]; - }, - ], - async ([l1, l2]) => { - expect(l1.isLocked()).toBe(true); - expect(l2.isLocked()).toBe(true); - }, - ); - expect(acquireOrder).toStrictEqual([lock1, lock2]); - expect(releaseOrder).toStrictEqual([lock2, lock1]); - }); - test('withG resource context', async () => { - // No resources - const g1 = utils.withG([], async function* () { - yield 'first'; - yield 'second'; - return 'last'; - }); - expect(await g1.next()).toStrictEqual({ value: 'first', done: false }); - expect(await g1.next()).toStrictEqual({ value: 'second', done: false }); - expect(await g1.next()).toStrictEqual({ value: 'last', done: true }); - // Noop resource - const g2 = await utils.withG( - [ - async () => { - return [async () => {}]; - }, - ], - async function* () { - yield 'first'; - return 'last'; - }, - ); - expect(await g2.next()).toStrictEqual({ value: 'first', done: false }); - expect(await g2.next()).toStrictEqual({ value: 'last', done: true }); - // Order of acquisition is left to right - // Order of release is right ot left - const lock1 = new Mutex(); - const lock2 = new Mutex(); - const acquireOrder: Array = []; - const releaseOrder: Array = []; - const g3 = utils.withG( - [ - async () => { - const release = await lock1.acquire(); - acquireOrder.push(lock1); - return [ - async () => { - releaseOrder.push(lock1); - release(); - }, - lock1, - ]; - }, - async () => { - const release = await lock2.acquire(); - acquireOrder.push(lock2); - return [ - async () => { - releaseOrder.push(lock2); - release(); - }, - lock2, - ]; - }, - ], - async function* ([l1, l2]) { - expect(l1.isLocked()).toBe(true); - expect(l2.isLocked()).toBe(true); - yield 'first'; - yield 'second'; - return 'last'; - }, - ); - expect(await g3.next()).toStrictEqual({ value: 'first', done: false }); - expect(lock1.isLocked()).toBe(true); - expect(lock2.isLocked()).toBe(true); - expect(await g3.next()).toStrictEqual({ value: 'second', done: false }); - expect(lock1.isLocked()).toBe(true); - expect(lock2.isLocked()).toBe(true); - expect(await g3.next()).toStrictEqual({ value: 'last', done: true }); - expect(lock1.isLocked()).toBe(false); - expect(lock2.isLocked()).toBe(false); - expect(acquireOrder).toStrictEqual([lock1, lock2]); - expect(releaseOrder).toStrictEqual([lock2, lock1]); - }); }); From b8598ede520251e671f6eabd8909de9b0f337f02 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 26 Apr 2022 12:03:46 +1000 Subject: [PATCH 002/137] build: upgrade to Node v16 Updated pkgs.nix to a5774e76bb8c3145eac524be62375c937143b80c Updated node2nix to 1.11.0 and loading directly from GitHub Updated pkg to 5.6.0 and using pkg-fetch 3.3 base binaries Updated to TypeScript 4.5+ Updated @types/node to 16.11.7 Updated node-gyp-build to 4.4.0 Updated typedoc to 0.22.15, the .nojekyll generation is automatic Changed to target ES2021 as node 16 supports it Bin executable duct-tape in default.nix because node2nix no longer generates bin executables Updated pkg builds hashes to v16.14.2 and specified target node range --- .eslintrc | 2 +- default.nix | 25 +- package-lock.json | 12931 +++++++++++++++++++++++++++++++++++++++++++- package.json | 12 +- pkgs.nix | 4 +- release.nix | 6 +- shell.nix | 2 +- tsconfig.json | 2 +- utils.nix | 38 +- 9 files changed, 12819 insertions(+), 203 deletions(-) diff --git a/.eslintrc b/.eslintrc index f66c592e8..d53f180f4 100644 --- a/.eslintrc +++ b/.eslintrc @@ -20,7 +20,7 @@ "parserOptions": { "project": "tsconfig.json", "sourceType": "module", - "ecmaVersion": 2020 + "ecmaVersion": 2021 }, "rules": { "linebreak-style": ["error", "unix"], diff --git a/default.nix b/default.nix index 79e7317a4..183bc8b27 100644 --- a/default.nix +++ b/default.nix @@ -1,5 +1,6 @@ { runCommandNoCC , callPackage +, jq }: let @@ -20,11 +21,25 @@ let if [ -d "${utils.node2nixProd}/lib/node_modules" ]; then cp -r ${utils.node2nixProd}/lib/node_modules $out/lib/node_modules/${utils.node2nixDev.packageName}/ fi - # create symlink to the deployed executable folder, if applicable - if [ -d "${utils.node2nixDev}/lib/node_modules/.bin" ]; then - cp -r ${utils.node2nixDev}/lib/node_modules/.bin $out/lib/node_modules/ - ln -s $out/lib/node_modules/.bin $out/bin + # symlink bin executables + if [ \ + "$(${jq}/bin/jq 'has("bin")' "$out/lib/node_modules/${utils.node2nixDev.packageName}/package.json")" \ + == \ + "true" \ + ]; then + mkdir -p "$out/bin" + while IFS= read -r bin_name && IFS= read -r bin_path; do + # make files executable + chmod a+x "$out/lib/node_modules/${utils.node2nixDev.packageName}/$bin_path" + # create the symlink + ln -s \ + "../lib/node_modules/${utils.node2nixDev.packageName}/$bin_path" \ + "$out/bin/$bin_name" + done < <( + ${jq}/bin/jq -r 'select(.bin != null) | .bin | to_entries[] | (.key, .value)' \ + "$out/lib/node_modules/${utils.node2nixDev.packageName}/package.json" + ) fi - ''; + ''; in drv diff --git a/package-lock.json b/package-lock.json index 18ea12929..e34a3abe0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,12606 @@ { "name": "@matrixai/polykey", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@matrixai/polykey", + "version": "1.0.0", + "license": "GPL-3.0", + "dependencies": { + "@grpc/grpc-js": "1.3.7", + "@matrixai/async-init": "^1.6.0", + "@matrixai/async-locks": "^2.0.0", + "@matrixai/db": "^3.2.0", + "@matrixai/errors": "^1.0.1", + "@matrixai/id": "^3.3.2", + "@matrixai/logger": "^2.1.0", + "@matrixai/resources": "^1.0.0", + "@matrixai/workers": "^1.2.5", + "ajv": "^7.0.4", + "bip39": "^3.0.3", + "canonicalize": "^1.0.5", + "cheerio": "^1.0.0-rc.5", + "commander": "^8.3.0", + "cross-fetch": "^3.0.6", + "cross-spawn": "^7.0.3", + "encryptedfs": "^3.4.3", + "fast-fuzzy": "^1.10.8", + "fd-lock": "^1.2.0", + "google-protobuf": "^3.14.0", + "ip-num": "^1.3.3-0", + "isomorphic-git": "^1.8.1", + "jose": "^4.3.6", + "lexicographic-integer": "^1.1.0", + "multiformats": "^9.4.8", + "node-forge": "^0.10.0", + "pako": "^1.0.11", + "prompts": "^2.4.1", + "readable-stream": "^3.6.0", + "resource-counter": "^1.2.4", + "threads": "^1.6.5", + "utp-native": "^2.5.3", + "uuid": "^8.3.0" + }, + "bin": { + "pk": "dist/bin/polykey.js", + "polykey": "dist/bin/polykey.js" + }, + "devDependencies": { + "@babel/preset-env": "^7.13.10", + "@types/cross-spawn": "^6.0.2", + "@types/google-protobuf": "^3.7.4", + "@types/jest": "^26.0.20", + "@types/nexpect": "^0.4.31", + "@types/node": "^16.11.7", + "@types/node-forge": "^0.9.7", + "@types/pako": "^1.0.2", + "@types/prompts": "^2.0.13", + "@types/readable-stream": "^2.3.11", + "@types/uuid": "^8.3.0", + "@typescript-eslint/eslint-plugin": "^5.4.0", + "@typescript-eslint/parser": "^5.4.0", + "babel-jest": "^26.6.3", + "eslint": "^7.17.0", + "eslint-config-prettier": "^7.1.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-prettier": "^3.3.1", + "grpc_tools_node_protoc_ts": "^5.1.3", + "jest": "^26.6.3", + "jest-mock-process": "^1.4.1", + "jest-mock-props": "^1.9.0", + "mocked-env": "^1.3.5", + "nexpect": "^0.6.0", + "node-gyp-build": "4.4.0", + "pkg": "5.6.0", + "prettier": "^2.2.1", + "ts-jest": "^26.4.4", + "ts-node": "^10.4.0", + "tsconfig-paths": "^3.9.0", + "typedoc": "^0.22.15", + "typescript": "^4.5.2", + "typescript-cached-transpile": "0.0.6" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", + "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", + "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.15.8", + "@babel/generator": "^7.15.8", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.8", + "@babel/helpers": "^7.15.4", + "@babel/parser": "^7.15.8", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6", + "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/generator": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", + "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.6", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz", + "integrity": "sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.15.4.tgz", + "integrity": "sha512-P8o7JP2Mzi0SdC6eWr1zF+AEYvrsZa7GSY1lTayjF5XJhVH0kjLYUZPvTMflP7tBgZoe9gIhTa60QwFpqh/E0Q==", + "dev": true, + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.15.4", + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", + "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.15.0", + "@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-create-class-features-plugin": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.4.tgz", + "integrity": "sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-member-expression-to-functions": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", + "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "regexpu-core": "^4.7.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz", + "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.15.4.tgz", + "integrity": "sha512-J14f/vq8+hdC2KoWLIQSsGrC9EFBKE4NFts8pfMpymfApds+fPqR30AOUWc4tyr56h9l/GA1Sxv2q3dLZWbQ/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", + "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", + "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", + "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", + "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", + "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", + "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.15.4", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/helper-validator-identifier": "^7.15.7", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", + "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.4" + }, + "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-remap-async-to-generator": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz", + "integrity": "sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.15.4", + "@babel/helper-wrap-function": "^7.15.4", + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", + "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", + "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.15.4.tgz", + "integrity": "sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", + "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "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/helper-wrap-function": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.15.4.tgz", + "integrity": "sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", + "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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/parser": { + "version": "7.16.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", + "integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.15.4.tgz", + "integrity": "sha512-eBnpsl9tlhPhpI10kU06JHnrYXwg3+V6CaP2idsCXNef0aeslpqyITXQ74Vfk5uHgY7IG7XP0yIH8b42KSzHog==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4", + "@babel/plugin-proposal-optional-chaining": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.8.tgz", + "integrity": "sha512-2Z5F2R2ibINTc63mY7FLqGfEbmofrHU9FitJW1Q7aPaKFhiPvSq6QEt/BoWN5oME3GVyjcRuNNSRbb9LC0CSWA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.15.4", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz", + "integrity": "sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.15.4.tgz", + "integrity": "sha512-M682XWrrLNk3chXCjoPUQWOyYsB93B9z3mRyjtqqYJWDf2mfCdIYgDrA11cgNVhAQieaq6F2fn2f3wI0U4aTjA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz", + "integrity": "sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz", + "integrity": "sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz", + "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz", + "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz", + "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz", + "integrity": "sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.15.6.tgz", + "integrity": "sha512-qtOHo7A1Vt+O23qEAX+GdBpqaIuD3i9VRrWgCJeq7WO6H2d14EK3q11urj5Te2MAeK97nMiIdRpwd/ST4JFbNg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.15.0", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", + "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz", + "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz", + "integrity": "sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.15.4.tgz", + "integrity": "sha512-X0UTixkLf0PCCffxgu5/1RQyGGbgZuKoI+vXP4iSbJSYwPb7hu06omsFGBvQ9lJEvwgrxHdS8B5nbfcd8GyUNA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.15.4", + "@babel/helper-create-class-features-plugin": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz", + "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.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-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "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-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "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-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "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-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-transform-arrow-functions": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", + "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", + "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-transform-async-to-generator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", + "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", + "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", + "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-transform-block-scoping": { + "version": "7.15.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz", + "integrity": "sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q==", + "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-transform-classes": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.15.4.tgz", + "integrity": "sha512-Yjvhex8GzBmmPQUvpXRPWQ9WnxXgAFuZSrqOK/eJlOGIXwvv8H3UEdUigl1gb/bnjTrln+e8bkZUYCBt/xYlBg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", + "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", + "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-transform-destructuring": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", + "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", + "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-transform-dotall-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz", + "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz", + "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", + "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-transform-exponentiation-operator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", + "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.15.4.tgz", + "integrity": "sha512-DRTY9fA751AFBDh2oxydvVm4SYevs5ILTWLs6xKXps4Re/KG5nfUkr+TdHCrRWB8C69TlzVgA9b3RmGWmgN9LA==", + "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-transform-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz", + "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", + "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", + "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-transform-member-expression-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz", + "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", + "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-transform-modules-amd": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz", + "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.4.tgz", + "integrity": "sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-simple-access": "^7.15.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.15.4.tgz", + "integrity": "sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.9", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz", + "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz", + "integrity": "sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz", + "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", + "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-transform-object-super": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", + "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.15.4.tgz", + "integrity": "sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ==", + "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-transform-property-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", + "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", + "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-transform-regenerator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", + "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", + "dev": true, + "dependencies": { + "regenerator-transform": "^0.14.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz", + "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", + "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-transform-shorthand-properties": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", + "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", + "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-transform-spread": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.15.8.tgz", + "integrity": "sha512-/daZ8s2tNaRekl9YJa9X4bzjpeRZLt122cpgFnQPLGUe61PH8zMEBmYqKkW5xF5JUEh5buEGXJoQpqBmIbpmEQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", + "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", + "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-transform-template-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", + "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", + "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-transform-typeof-symbol": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", + "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", + "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-transform-unicode-escapes": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz", + "integrity": "sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==", + "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-transform-unicode-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", + "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.8.tgz", + "integrity": "sha512-rCC0wH8husJgY4FPbHsiYyiLxSY8oMDJH7Rl6RQMknbN9oDDHhM9RDFvnGM2MgkbUJzSQB4gtuwygY5mCqGSsA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.15.0", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.15.4", + "@babel/plugin-proposal-async-generator-functions": "^7.15.8", + "@babel/plugin-proposal-class-properties": "^7.14.5", + "@babel/plugin-proposal-class-static-block": "^7.15.4", + "@babel/plugin-proposal-dynamic-import": "^7.14.5", + "@babel/plugin-proposal-export-namespace-from": "^7.14.5", + "@babel/plugin-proposal-json-strings": "^7.14.5", + "@babel/plugin-proposal-logical-assignment-operators": "^7.14.5", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", + "@babel/plugin-proposal-numeric-separator": "^7.14.5", + "@babel/plugin-proposal-object-rest-spread": "^7.15.6", + "@babel/plugin-proposal-optional-catch-binding": "^7.14.5", + "@babel/plugin-proposal-optional-chaining": "^7.14.5", + "@babel/plugin-proposal-private-methods": "^7.14.5", + "@babel/plugin-proposal-private-property-in-object": "^7.15.4", + "@babel/plugin-proposal-unicode-property-regex": "^7.14.5", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@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-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.14.5", + "@babel/plugin-transform-async-to-generator": "^7.14.5", + "@babel/plugin-transform-block-scoped-functions": "^7.14.5", + "@babel/plugin-transform-block-scoping": "^7.15.3", + "@babel/plugin-transform-classes": "^7.15.4", + "@babel/plugin-transform-computed-properties": "^7.14.5", + "@babel/plugin-transform-destructuring": "^7.14.7", + "@babel/plugin-transform-dotall-regex": "^7.14.5", + "@babel/plugin-transform-duplicate-keys": "^7.14.5", + "@babel/plugin-transform-exponentiation-operator": "^7.14.5", + "@babel/plugin-transform-for-of": "^7.15.4", + "@babel/plugin-transform-function-name": "^7.14.5", + "@babel/plugin-transform-literals": "^7.14.5", + "@babel/plugin-transform-member-expression-literals": "^7.14.5", + "@babel/plugin-transform-modules-amd": "^7.14.5", + "@babel/plugin-transform-modules-commonjs": "^7.15.4", + "@babel/plugin-transform-modules-systemjs": "^7.15.4", + "@babel/plugin-transform-modules-umd": "^7.14.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.9", + "@babel/plugin-transform-new-target": "^7.14.5", + "@babel/plugin-transform-object-super": "^7.14.5", + "@babel/plugin-transform-parameters": "^7.15.4", + "@babel/plugin-transform-property-literals": "^7.14.5", + "@babel/plugin-transform-regenerator": "^7.14.5", + "@babel/plugin-transform-reserved-words": "^7.14.5", + "@babel/plugin-transform-shorthand-properties": "^7.14.5", + "@babel/plugin-transform-spread": "^7.15.8", + "@babel/plugin-transform-sticky-regex": "^7.14.5", + "@babel/plugin-transform-template-literals": "^7.14.5", + "@babel/plugin-transform-typeof-symbol": "^7.14.5", + "@babel/plugin-transform-unicode-escapes": "^7.14.5", + "@babel/plugin-transform-unicode-regex": "^7.14.5", + "@babel/preset-modules": "^0.1.4", + "@babel/types": "^7.15.6", + "babel-plugin-polyfill-corejs2": "^0.2.2", + "babel-plugin-polyfill-corejs3": "^0.2.5", + "babel-plugin-polyfill-regenerator": "^0.2.2", + "core-js-compat": "^3.16.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", + "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "node_modules/@babel/template": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", + "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", + "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", + "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.15.7", + "to-fast-properties": "^2.0.0" + }, + "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/@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "dev": true, + "dependencies": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + }, + "bin": { + "watch": "cli.js" + }, + "engines": { + "node": ">=0.1.95" + } + }, + "node_modules/@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", + "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-consumer": "0.8.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/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/@grpc/grpc-js": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.3.7.tgz", + "integrity": "sha512-CKQVuwuSPh40tgOkR7c0ZisxYRiN05PcKPW72mQL5y++qd7CwBRoaJZvU5xfXnCJDFBmS3qZGQ71Frx6Ofo2XA==", + "dependencies": { + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "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/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": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", + "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^26.6.2", + "jest-util": "^26.6.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/@jest/console/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/console/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/core": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", + "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "dev": true, + "dependencies": { + "@jest/console": "^26.6.2", + "@jest/reporters": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^26.6.2", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-resolve-dependencies": "^26.6.3", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "jest-watcher": "^26.6.2", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/@jest/core/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/core/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/environment": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", + "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/fake-timers": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", + "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@sinonjs/fake-timers": "^6.0.1", + "@types/node": "*", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/globals": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", + "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "dev": true, + "dependencies": { + "@jest/environment": "^26.6.2", + "@jest/types": "^26.6.2", + "expect": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/reporters": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", + "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.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": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^7.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "optionalDependencies": { + "node-notifier": "^8.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/@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/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/@jest/reporters/node_modules/node-notifier": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", + "dev": true, + "optional": true, + "dependencies": { + "growly": "^1.3.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.2", + "shellwords": "^0.1.1", + "uuid": "^8.3.0", + "which": "^2.0.2" + } + }, + "node_modules/@jest/reporters/node_modules/node-notifier/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/reporters/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/@jest/reporters/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/source-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", + "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/source-map/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/@jest/test-result": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", + "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "dev": true, + "dependencies": { + "@jest/console": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", + "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/transform": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", + "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^26.6.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": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-util": "^26.6.2", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/@jest/transform/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/transform/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/@jest/transform/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/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/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/@jest/types/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/types/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/@matrixai/async-init": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.6.0.tgz", + "integrity": "sha512-I24u6McZnSH2yX1l5e2H3O/Lu8IVb2fM/sVbDeRYrzejV2XLv/9g/goz2fglSrXgJ877BBFJNW2GMxVzvvyA5A==", + "dependencies": { + "async-mutex": "^0.3.2", + "ts-custom-error": "^3.2.0" + } + }, + "node_modules/@matrixai/async-init/node_modules/async-mutex": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", + "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@matrixai/async-locks": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.0.0.tgz", + "integrity": "sha512-wpU6L5o/0BhBsjYt4BH2J3L0+yDhxotCi6cRF7QZbm03u/tdq8tgwyOzXe+MPArh+EZhsBrnBOCdUpUhgZNRZQ==", + "dependencies": { + "@matrixai/resources": "^1.0.0", + "async-mutex": "^0.3.2", + "ts-custom-error": "^3.2.0" + } + }, + "node_modules/@matrixai/db": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.2.0.tgz", + "integrity": "sha512-JfcpZ8zbNgdQK3mpHQisCY6TKGUO5+Issh5KDvR3zBtfdSKHJLgrqweDIyLtM9D0RT5jO5HOY+lthI/8Yfi/PA==", + "dependencies": { + "@matrixai/async-init": "^1.6.0", + "@matrixai/errors": "^1.0.1", + "@matrixai/logger": "^2.1.0", + "@matrixai/resources": "^1.0.0", + "@matrixai/workers": "^1.2.5", + "@types/abstract-leveldown": "^7.2.0", + "level": "7.0.1", + "threads": "^1.6.5" + } + }, + "node_modules/@matrixai/db/node_modules/@matrixai/errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.0.1.tgz", + "integrity": "sha512-9NbIm3rPMkZz+Ma5tfKduVCWfvYzdHlO89u9mBap7FzJqXkl4yoENjMZm5Do6PvhtIYtRcm6+eTgWvHd6pkdGg==", + "dependencies": { + "ts-custom-error": "^3.2.0" + } + }, + "node_modules/@matrixai/errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.0.1.tgz", + "integrity": "sha512-9NbIm3rPMkZz+Ma5tfKduVCWfvYzdHlO89u9mBap7FzJqXkl4yoENjMZm5Do6PvhtIYtRcm6+eTgWvHd6pkdGg==", + "dependencies": { + "ts-custom-error": "^3.2.0" + } + }, + "node_modules/@matrixai/id": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@matrixai/id/-/id-3.3.2.tgz", + "integrity": "sha512-gpW56P7jZILPc0oxyNQvZBkEBn30JPGpslOHIcDoKnCZR8VGZXEKX485xy1WE4MBiQHXdGeiYF8A2CluqTnu3w==", + "dependencies": { + "multiformats": "^9.4.8", + "uuid": "^8.3.2" + } + }, + "node_modules/@matrixai/logger": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.1.0.tgz", + "integrity": "sha512-UmLuXi2PJ03v0Scfl57217RPnjEZDRLlpfdIjIwCfju+kofnhhCI9P7OZu3/FgW147vbvSzWCrrtpwJiLROUUA==" + }, + "node_modules/@matrixai/resources": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@matrixai/resources/-/resources-1.0.0.tgz", + "integrity": "sha512-B1ZkySZwOZTIzhK+YTN4HifOTd1dk1ifDUV8/8WgGho2nUZzIMYms7iDmW/ZHUCkqvWupKY6AYvfwnKBOJJnWg==" + }, + "node_modules/@matrixai/workers": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@matrixai/workers/-/workers-1.2.5.tgz", + "integrity": "sha512-ikI4K6RGKQbG68it7TXJJ5wX2csW+WpokUehTnz5r66d7o6FC3PkojE46LPLCDSwk3NVCGoQ743OZS2nuA8SRA==", + "dependencies": { + "@matrixai/logger": "^2.1.0", + "threads": "^1.6.5", + "ts-custom-error": "^3.2.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "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": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "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/@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "node_modules/@types/abstract-leveldown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-q5veSX6zjUy/DlDhR4Y4cU0k2Ar+DT2LUraP00T19WLmTO6Se1djepCCaqU6nQrwcJ5Hyo/CWqxTzrrFg8eqbQ==" + }, + "node_modules/@types/babel__core": { + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", + "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", + "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.3", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", + "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/cross-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.2.tgz", + "integrity": "sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/google-protobuf": { + "version": "3.15.5", + "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.5.tgz", + "integrity": "sha512-6bgv24B+A2bo9AfzReeg5StdiijKzwwnRflA8RLd1V4Yv995LeTmo0z69/MPbBDFSiZWdZHQygLo/ccXhMEDgw==", + "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.24", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", + "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", + "dev": true, + "dependencies": { + "jest-diff": "^26.0.0", + "pretty-format": "^26.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "node_modules/@types/nexpect": { + "version": "0.4.31", + "resolved": "https://registry.npmjs.org/@types/nexpect/-/nexpect-0.4.31.tgz", + "integrity": "sha512-Plh9Dlj2AKdsblgF1Pv7s2BjlojqW93d1zIUtK5xVVrUjkZQezyWIOAq0Xfwp0e0SDQ70YmaDqzhoJru2kqVPA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "16.11.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.29.tgz", + "integrity": "sha512-9dDdonLyPJQJ/kdOlDxAah+bTI+u2ccF3k62FErhquDuggoCX6piWez7j7o6yNE+rP2IRcZVQ6Tw4N0P38+rWA==" + }, + "node_modules/@types/node-forge": { + "version": "0.9.10", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-0.9.10.tgz", + "integrity": "sha512-+BbPlhZeYs/WETWftQi2LeRx9VviWSwawNo+Pid5qNrSZHb60loYjpph3OrbwXMMseadu9rE9NeK34r4BHT+QQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/pako": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.2.tgz", + "integrity": "sha512-8UJl2MjkqqS6ncpLZqRZ5LmGiFBkbYxocD4e4jmBqGvfRG1RS23gKsBQbdtV9O9GvRyjFTiRHRByjSlKCLlmZw==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", + "dev": true + }, + "node_modules/@types/prompts": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.14.tgz", + "integrity": "sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/readable-stream": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.11.tgz", + "integrity": "sha512-0z+/apYJwKFz/RHp6mOMxz/y7xOvWPYPevuCEyAY3gXsjtaac02E26RvxA+I96rfvmVH/dEMGXNvyJfViR1FSQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "safe-buffer": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/uuid": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.4.0.tgz", + "integrity": "sha512-9/yPSBlwzsetCsGEn9j24D8vGQgJkOTr4oMLas/w886ZtzKIs1iyoqFrwsX2fqYEeUwsdBpC21gcjRGo57u0eg==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "5.4.0", + "@typescript-eslint/scope-manager": "5.4.0", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.4.0.tgz", + "integrity": "sha512-Nz2JDIQUdmIGd6p33A+naQmwfkU5KVTLb/5lTk+tLVTDacZKoGQisj8UCxk7onJcrgjIvr8xWqkYI+DbI3TfXg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.4.0", + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/typescript-estree": "5.4.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.4.0.tgz", + "integrity": "sha512-JoB41EmxiYpaEsRwpZEYAJ9XQURPFer8hpkIW9GiaspVLX8oqbqNM8P4EP8HOZg96yaALiLEVWllA2E8vwsIKw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.4.0", + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/typescript-estree": "5.4.0", + "debug": "^4.3.2" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.4.0.tgz", + "integrity": "sha512-pRxFjYwoi8R+n+sibjgF9iUiAELU9ihPBtHzocyW8v8D8G8KeQvXTsW7+CBYIyTYsmhtNk50QPGLE3vrvhM5KA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/visitor-keys": "5.4.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.4.0.tgz", + "integrity": "sha512-GjXNpmn+n1LvnttarX+sPD6+S7giO+9LxDIGlRl4wK3a7qMWALOHYuVSZpPTfEIklYjaWuMtfKdeByx0AcaThA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.4.0.tgz", + "integrity": "sha512-nhlNoBdhKuwiLMx6GrybPT3SFILm5Gij2YBdPEPFlYNFAXUJWX6QRgvi/lwVoadaQEFsizohs6aFRMqsXI2ewA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/visitor-keys": "5.4.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.4.0.tgz", + "integrity": "sha512-PVbax7MeE7tdLfW5SA0fs8NGVVr+buMPrcj+CWYWPXsZCH8qZ1THufDzbXm1xrZ2b2PA1iENJ0sRq5fuUtvsJg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.4.0", + "eslint-visitor-keys": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", + "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "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/abstract-leveldown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.0.0", + "is-buffer": "^2.0.5", + "level-concat-iterator": "^3.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=10" + } + }, + "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-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "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/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": "7.2.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.4.tgz", + "integrity": "sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "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": "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/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/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/are-we-there-yet/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/are-we-there-yet/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/are-we-there-yet/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/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "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/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", + "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async-lock": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.3.0.tgz", + "integrity": "sha512-8A7SkiisnEgME2zEedtDYPxUPzdv3x//E7n5IFktPAtMYSEAV7eNJF0rMwrVyUFj6d/8rgajLantbjcNRQYXIg==" + }, + "node_modules/async-mutex": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", + "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "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/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/babel-jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", + "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "dev": true, + "dependencies": { + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/babel__core": "^7.1.7", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/babel-jest/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/babel-jest/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/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "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": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", + "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "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.14.2" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", + "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.2.2", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz", + "integrity": "sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.2.2", + "core-js-compat": "^3.16.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz", + "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.2.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.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": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", + "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^26.6.2", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/big-integer": { + "version": "1.6.50", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.50.tgz", + "integrity": "sha512-+O2uoQWFRo8ysZNo/rjtri2jIwjr3XfeAgRjAUADRqGG+ZITvyn8J1kvXLTaKVr3hhGXk+f23tKfdzmklVM9vQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bip39": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz", + "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==", + "dependencies": { + "@types/node": "11.11.6", + "create-hash": "^1.1.0", + "pbkdf2": "^3.0.9", + "randombytes": "^2.0.1" + } + }, + "node_modules/bip39/node_modules/@types/node": { + "version": "11.11.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", + "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" + }, + "node_modules/bitset": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bitset/-/bitset-5.1.1.tgz", + "integrity": "sha512-oKaRp6mzXedJ1Npo86PKhWfDelI6HxxJo+it9nAcBB0HLVvYVp+5i6yj6DT5hfFgo+TS5T57MRWtw8zhwdTs3g==", + "engines": { + "node": "*" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "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.17.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", + "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001265", + "electron-to-chromium": "^1.3.867", + "escalade": "^3.1.1", + "node-releases": "^2.0.0", + "picocolors": "^1.0.0" + }, + "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/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": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "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/caniuse-lite": { + "version": "1.0.30001269", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001269.tgz", + "integrity": "sha512-UOy8okEVs48MyHYgV+RdW1Oiudl1H6KolybD6ZquD0VcrPSgj25omXO1S7rDydjpqaISCwA8Pyx+jUQKZwWO5w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/canonicalize": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-1.0.5.tgz", + "integrity": "sha512-mAjKJPIyP0xqqv6IAkvso07StOmz6cmGtNDg3pXCSzXVZOqka7StIkAhJl/zHOi4M2CgpYfD6aeRWbnrmtvBEA==" + }, + "node_modules/capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "dependencies": { + "rsvp": "^4.8.4" + }, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "engines": { + "node": ">=6" + } + }, + "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/chalk/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/chalk/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/chalk/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/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/check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", + "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "dependencies": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", + "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", + "dependencies": { + "css-select": "^4.1.3", + "css-what": "^5.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0", + "domutils": "^2.7.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/cjs-module-lexer": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", + "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", + "dev": true + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-git-ref": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", + "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==" + }, + "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/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/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.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/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/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/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": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "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/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "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/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.", + "hasInstallScript": true + }, + "node_modules/core-js-compat": { + "version": "3.18.3", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.18.3.tgz", + "integrity": "sha512-4zP6/y0a2RTHN5bRGT7PTq9lVt3WzvffTNjqnTKsXhkAYNDTkdCLOIfAdOLcQ/7TDdyRj3c+NeHe1NmF1eDScw==", + "dev": true, + "dependencies": { + "browserslist": "^4.17.3", + "semver": "7.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/crc-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", + "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", + "dependencies": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + }, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-fetch": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", + "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", + "dependencies": { + "node-fetch": "2.6.1" + } + }, + "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==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", + "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "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/deferred-leveldown": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-7.0.0.tgz", + "integrity": "sha512-QKN8NtuS3BC6m0B8vAnBls44tX1WXAFATUsJlruyAYbZpysWV3siH6o/i3g9DCHauzodksO60bdj5NazNbjCmg==", + "dependencies": { + "abstract-leveldown": "^7.2.0", + "inherits": "^2.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defined": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", + "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=" + }, + "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/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "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": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/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/diff3": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha1-1OXDpM305f4SEatC5pP8tDIVgPw=" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "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/domhandler": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", + "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.3.871", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.871.tgz", + "integrity": "sha512-qcLvDUPf8DSIMWarHT2ptgcqrYg62n3vPA7vhrOF24d8UNzbUBaHu2CySiENR3nEDzYgaN60071t0F6KLYMQ7Q==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", + "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "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/encoding-down": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-7.1.0.tgz", + "integrity": "sha512-ky47X5jP84ryk5EQmvedQzELwVJPjCgXDQZGeb9F6r4PdChByCGHTBrVcF3h8ynKVJ1wVbkxTsDC8zBROPypgQ==", + "dependencies": { + "abstract-leveldown": "^7.2.0", + "inherits": "^2.0.3", + "level-codec": "^10.0.0", + "level-errors": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/encryptedfs": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/encryptedfs/-/encryptedfs-3.4.3.tgz", + "integrity": "sha512-OQqsGw3eNrMdFpiYRX17nMq1NKKebaA0KXyM9IRY9aPOxpaeOwcdvWnOcvvO9wCxZFNxgy/A2SOZdxnhCe3paA==", + "dependencies": { + "@matrixai/async-init": "^1.6.0", + "@matrixai/db": "^1.1.5", + "@matrixai/logger": "^2.1.0", + "@matrixai/workers": "^1.2.5", + "async-mutex": "^0.3.2", + "errno": "^0.1.7", + "lexicographic-integer": "^1.1.0", + "node-forge": "^0.10.0", + "readable-stream": "^3.6.0", + "resource-counter": "^1.2.4", + "threads": "^1.6.5", + "ts-custom-error": "^3.2.0", + "util-callbackify": "^1.0.0" + } + }, + "node_modules/encryptedfs/node_modules/@matrixai/db": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-1.2.1.tgz", + "integrity": "sha512-1W8TORmRX3q3NugZFn0FTgI0mo/n0nWBTXHKXwwPfxtdyNfi18JCj3HVCwWdToOo87ypnS/mqLDIUTSHbF7F3Q==", + "dependencies": { + "@matrixai/async-init": "^1.6.0", + "@matrixai/logger": "^2.1.0", + "@matrixai/workers": "^1.2.5", + "abstract-leveldown": "^7.2.0", + "async-mutex": "^0.3.1", + "level": "7.0.1", + "levelup": "^5.1.1", + "sublevel-prefixer": "^1.0.0", + "subleveldown": "^6.0.1", + "threads": "^1.6.5", + "ts-custom-error": "^3.2.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.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/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "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==", + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/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, + "optional": true, + "engines": { + "node": ">=0.10.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.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "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", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.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.merge": "^4.6.2", + "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": "^6.0.9", + "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-config-prettier": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", + "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", + "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "find-up": "^2.1.0", + "pkg-dir": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.25.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", + "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.1", + "has": "^1.0.3", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-plugin-prettier": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", + "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=5.0.0", + "prettier": ">=1.13.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/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/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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/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/node_modules/globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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/eslint/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/eslint/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/eslint/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/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/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "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.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "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/exec-sh": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", + "dev": true + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/execa/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/execa/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "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/exit-on-epipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", + "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/expect": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.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==" + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-fuzzy": { + "version": "1.10.10", + "resolved": "https://registry.npmjs.org/fast-fuzzy/-/fast-fuzzy-1.10.10.tgz", + "integrity": "sha512-TkXYYQcLyZ5tbDpg3kj5gq7PNl6vQQQEW99/sBpmYYRPcuCaZElm3FpoOOqwL51+1prhjrzsnGAjWgNCG7iVOA==", + "dependencies": { + "graphemesplit": "^2.4.1" + } + }, + "node_modules/fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "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/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "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/fd-lock": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fd-lock/-/fd-lock-1.2.0.tgz", + "integrity": "sha512-Lk/pKH2DldLpG4Yh/sOOY84k5VqNzxHPffGwf1+yYI+/qMXzTPp9KJMX+Wh6n4xqGSA1Mu7JPmaDArfJGw2O/A==", + "hasInstallScript": true, + "dependencies": { + "napi-macros": "^2.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "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": "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/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.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "dev": true + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/from2/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/from2/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/from2/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/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-extra/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "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==" + }, + "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/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "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/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/globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-protobuf": { + "version": "3.18.1", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.18.1.tgz", + "integrity": "sha512-cDqSamZ8rGs+pOzhIsBte7wpezUKg/sggeptDWN5odhnRY/eDLa5VWLeNeQvcfiqjS3yUwgM+6OePCJMB7aWZA==" + }, + "node_modules/graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true + }, + "node_modules/graphemesplit": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/graphemesplit/-/graphemesplit-2.4.4.tgz", + "integrity": "sha512-lKrpp1mk1NH26USxC/Asw4OHbhSQf5XfrWZ+CDv/dFVvd1j17kFgMotdJvOesmHkbFX9P9sBfpH8VogxOWLg8w==", + "dependencies": { + "js-base64": "^3.6.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true, + "optional": true + }, + "node_modules/grpc_tools_node_protoc_ts": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/grpc_tools_node_protoc_ts/-/grpc_tools_node_protoc_ts-5.3.2.tgz", + "integrity": "sha512-7xPSeu8bwjcird3i9R5+9O4BF2Lhv9fMBdeobfUc2Bys9tSVtm/VB3WjTpKV78WlLYJyD94+wL/8hJqaMZ53Hw==", + "dev": true, + "dependencies": { + "google-protobuf": "3.15.8", + "handlebars": "4.7.7" + }, + "bin": { + "protoc-gen-ts": "bin/protoc-gen-ts" + } + }, + "node_modules/grpc_tools_node_protoc_ts/node_modules/google-protobuf": { + "version": "3.15.8", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.15.8.tgz", + "integrity": "sha512-2jtfdqTaSxk0cuBJBtTTWsot4WtR9RVr2rXg7x7OoqiuOKopPrwXpM1G4dXIkLcUNRh3RKzz76C8IOkksZSeOw==", + "dev": true + }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/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/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "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/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "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": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "engines": { + "node": ">=8.12.0" + } + }, + "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/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/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/import-local": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", + "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "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/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==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/into-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", + "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", + "dev": true, + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ip-num": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/ip-num/-/ip-num-1.3.3.tgz", + "integrity": "sha512-1QsiMKglDaemuIktincG1ntr3DvVTV/pU++eyG7vIm4xd+gvtJ9eoB34RRbI9YTqn1U5og16n7+1RgwLhv4RmA==", + "dependencies": { + "big-integer": "^1.6.48" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "optional": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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": "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/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.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-observable": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-2.1.0.tgz", + "integrity": "sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.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-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/is-weakref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", + "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "dependencies": { + "call-bind": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "optional": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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=" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isomorphic-git": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.10.1.tgz", + "integrity": "sha512-abbPpKkykIVDJ92rtYoD4AOuT5/7PABHR2fDBrsm7H0r2ZT+MGpPL/FynrEJM6nTcFSieaIDxnHNGhfHO/v+bA==", + "dependencies": { + "async-lock": "^1.1.0", + "clean-git-ref": "^2.0.1", + "crc-32": "^1.2.0", + "diff3": "0.0.3", + "ignore": "^5.1.4", + "minimisted": "^2.0.0", + "pako": "^1.0.10", + "pify": "^4.0.1", + "readable-stream": "^3.4.0", + "sha.js": "^2.4.9", + "simple-get": "^3.0.2" + }, + "bin": { + "isogit": "cli.cjs" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.1.0.tgz", + "integrity": "sha512-OFSPP1Csv3GxruycNA1iRJPnc5pon+N4Q89EUz8KYOFbdsqCoHRh0J8jwRdna5thveVcMTdgY27kUl/lZuAWdw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.0.4.tgz", + "integrity": "sha512-W6jJF9rLGEISGoCyXRqa/JCGQGmmxPO10TMu7izaUTynxvBvTjqzAIIGCK9USBmIbQAaSWD6XJPrM9Pv5INknw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/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/istanbul-reports": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", + "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", + "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", + "dev": true, + "dependencies": { + "@jest/core": "^26.6.3", + "import-local": "^3.0.2", + "jest-cli": "^26.6.3" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-changed-files": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", + "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "execa": "^4.0.0", + "throat": "^5.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-changed-files/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/jest-changed-files/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/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/jest-config": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", + "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^26.6.3", + "@jest/types": "^26.6.2", + "babel-jest": "^26.6.3", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-environment-jsdom": "^26.6.2", + "jest-environment-node": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-jasmine2": "^26.6.3", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-config/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-config/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-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-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-diff/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-diff/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-docblock": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", + "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-each": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", + "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-each/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-each/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-environment-jsdom": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", + "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "dev": true, + "dependencies": { + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2", + "jsdom": "^16.4.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-environment-node": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", + "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "dev": true, + "dependencies": { + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "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": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", + "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.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": "^26.0.0", + "jest-serializer": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7" + }, + "engines": { + "node": ">= 10.14.2" + }, + "optionalDependencies": { + "fsevents": "^2.1.2" + } + }, + "node_modules/jest-jasmine2": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", + "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^26.6.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2", + "throat": "^5.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-jasmine2/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-jasmine2/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-jasmine2/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-leak-detector": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", + "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", + "dev": true, + "dependencies": { + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-matcher-utils": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-matcher-utils/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-matcher-utils/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-message-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-message-util/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-message-util/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-mock": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", + "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@types/node": "*" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-mock-process": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jest-mock-process/-/jest-mock-process-1.4.1.tgz", + "integrity": "sha512-ZZUKRlEBizutngoO4KngzN30YoeAYP3nnwimk4cpi9WqLxQUf6SlAPK5p1D9usEpxDS3Uif2MIez3Bq0vGYR+g==", + "dev": true, + "peerDependencies": { + "jest": ">=23.4 <28" + } + }, + "node_modules/jest-mock-props": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/jest-mock-props/-/jest-mock-props-1.9.0.tgz", + "integrity": "sha512-8IlIiZRvovnRuvqcvWZyDv4CyhrUGTbEW/1eKurHr2JY4VhIWQIPlbpt9lqL2nxdGnco+OcgpPBwGYCEeDb2+A==", + "dev": true, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "jest": ">=24.0.0" + } + }, + "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": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "dev": true, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", + "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-snapshot": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-resolve/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-resolve/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-runner": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", + "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", + "dev": true, + "dependencies": { + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.7.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-docblock": "^26.0.0", + "jest-haste-map": "^26.6.2", + "jest-leak-detector": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "source-map-support": "^0.5.6", + "throat": "^5.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/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/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-runtime": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", + "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", + "dev": true, + "dependencies": { + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/globals": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^0.6.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^15.4.1" + }, + "bin": { + "jest-runtime": "bin/jest-runtime.js" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-runtime/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/jest-runtime/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-runtime/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-runtime/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-serializer": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", + "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-snapshot": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", + "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.0.0", + "chalk": "^4.0.0", + "expect": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-haste-map": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "natural-compare": "^1.4.0", + "pretty-format": "^26.6.2", + "semver": "^7.3.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-snapshot/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-snapshot/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/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-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", + "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^2.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-util/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-util/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-validate": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", + "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "camelcase": "^6.0.0", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "leven": "^3.1.0", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "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/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-validate/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-validate/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-watcher": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", + "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^26.6.2", + "string-length": "^4.0.1" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest-watcher/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-watcher/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-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/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/jest/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/jest/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/node_modules/jest-cli": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", + "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", + "dev": true, + "dependencies": { + "@jest/core": "^26.6.3", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "is-ci": "^2.0.0", + "jest-config": "^26.6.3", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "prompts": "^2.0.1", + "yargs": "^15.4.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest/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/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/jest/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jose": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.3.6.tgz", + "integrity": "sha512-A/JgZGUerqG2IMuxkUDBtZ4aTxg/l1Y+pt/QAAYiRAR3EFlxIE0Su0xdpB8tQcPZK5eudB7g1PHCZ5uHatbY+g==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-base64": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.2.tgz", + "integrity": "sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==" + }, + "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.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "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.6", + "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.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "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-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "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.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonfile/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", + "dev": true, + "engines": { + "node": "> 0.8" + } + }, + "node_modules/level": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/level/-/level-7.0.1.tgz", + "integrity": "sha512-w3E64+ALx2eZf8RV5JL4kIcE0BFAvQscRYd1yU4YVqZN9RGTQxXSvH202xvK15yZwFFxRXe60f13LJjcJ//I4Q==", + "dependencies": { + "level-js": "^6.1.0", + "level-packager": "^6.0.1", + "leveldown": "^6.1.0" + }, + "engines": { + "node": ">=10.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" + } + }, + "node_modules/level-codec": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-10.0.0.tgz", + "integrity": "sha512-QW3VteVNAp6c/LuV6nDjg7XDXx9XHK4abmQarxZmlRSDyXYk20UdaJTSX6yzVvQ4i0JyWSB7jert0DsyD/kk6g==", + "dependencies": { + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/level-concat-iterator": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", + "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", + "dependencies": { + "catering": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/level-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-3.0.1.tgz", + "integrity": "sha512-tqTL2DxzPDzpwl0iV5+rBCv65HWbHp6eutluHNcVIftKZlQN//b6GEnZDM2CvGZvzGYMwyPtYppYnydBQd2SMQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/level-iterator-stream": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-5.0.0.tgz", + "integrity": "sha512-wnb1+o+CVFUDdiSMR/ZymE2prPs3cjVLlXuDeSq9Zb8o032XrabGEXcTCsBxprAtseO3qvFeGzh6406z9sOTRA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/level-js": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/level-js/-/level-js-6.1.0.tgz", + "integrity": "sha512-i7mPtkZm68aewfv0FnIUWvFUFfoyzIvVKnUmuQGrelEkP72vSPTaA1SGneWWoCV5KZJG4wlzbJLp1WxVNGuc6A==", + "dependencies": { + "abstract-leveldown": "^7.2.0", + "buffer": "^6.0.3", + "inherits": "^2.0.3", + "ltgt": "^2.1.2", + "run-parallel-limit": "^1.1.0" + } + }, + "node_modules/level-option-wrap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/level-option-wrap/-/level-option-wrap-1.1.0.tgz", + "integrity": "sha1-rSDmjZ88IsiJdTHMaqevWWse0Sk=", + "dependencies": { + "defined": "~0.0.0" + } + }, + "node_modules/level-packager": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-6.0.1.tgz", + "integrity": "sha512-8Ezr0XM6hmAwqX9uu8IGzGNkWz/9doyPA8Oo9/D7qcMI6meJC+XhIbNYHukJhIn8OGdlzQs/JPcL9B8lA2F6EQ==", + "dependencies": { + "encoding-down": "^7.1.0", + "levelup": "^5.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/level-supports": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", + "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/leveldown": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.1.tgz", + "integrity": "sha512-88c+E+Eizn4CkQOBHwqlCJaTNEjGpaEIikn1S+cINc5E9HEvJ77bqY4JY/HxT5u0caWqsc3P3DcFIKBI1vHt+A==", + "hasInstallScript": true, + "dependencies": { + "abstract-leveldown": "^7.2.0", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/levelup": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-5.1.1.tgz", + "integrity": "sha512-0mFCcHcEebOwsQuk00WJwjLI6oCjbBuEYdh/RaRqhjnyVlzqf41T1NnDtCedumZ56qyIh8euLFDqV1KfzTAVhg==", + "dependencies": { + "catering": "^2.0.0", + "deferred-leveldown": "^7.0.0", + "level-errors": "^3.0.1", + "level-iterator-stream": "^5.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=10" + } + }, + "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/lexicographic-integer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/lexicographic-integer/-/lexicographic-integer-1.1.0.tgz", + "integrity": "sha1-UsptmYpXLmMitRX1uA45bGBD6bg=" + }, + "node_modules/lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "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/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "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/ltgt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", + "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=" + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, + "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-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/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/marked": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.14.tgz", + "integrity": "sha512-HL5sSPE/LP6U9qKgngIIPTthuxC0jrfxpYMZ3LdGDD3vTnLs59m2Z7r6+LNDR3ToqEQdkKd6YaaEfJhodJmijQ==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "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/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "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/mime-db": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", + "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", + "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "dev": true, + "dependencies": { + "mime-db": "1.50.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/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/minimisted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", + "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", + "dependencies": { + "minimist": "^1.2.5" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node_modules/mocked-env": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/mocked-env/-/mocked-env-1.3.5.tgz", + "integrity": "sha512-GyYY6ynVOdEoRlaGpaq8UYwdWkvrsU2xRme9B+WPSuJcNjh17+3QIxSYU6zwee0SbehhV6f06VZ4ahjG+9zdrA==", + "dev": true, + "dependencies": { + "check-more-types": "2.24.0", + "debug": "4.3.2", + "lazy-ass": "1.6.0", + "ramda": "0.27.1" + }, + "engines": { + "node": ">=6" + } + }, + "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==" + }, + "node_modules/multiformats": { + "version": "9.4.9", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.4.9.tgz", + "integrity": "sha512-zA84TTJcRfRMpjvYqy63piBbSEdqlIGqNNSpP6kspqtougqjo60PRhIFo+oAxrjkof14WMCImvr7acK6rPpXLw==" + }, + "node_modules/multistream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", + "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", + "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" + } + ], + "dependencies": { + "once": "^1.4.0", + "readable-stream": "^3.6.0" + } + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, + "node_modules/napi-macros": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", + "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" + }, + "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/nexpect": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/nexpect/-/nexpect-0.6.0.tgz", + "integrity": "sha512-gG4cO0zoNG+kaPesw516hPVEKLW3YizGU8UWMr5lpkHKOgoTWcu4sPQN7rWVAIL4Ck87zM4N8immPUhYPdDz3g==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.5" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/nexpect/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/nexpect/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nexpect/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nexpect/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nexpect/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nexpect/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-abi": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", + "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", + "dev": true, + "dependencies": { + "semver": "^5.4.1" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "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/node-notifier": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-10.0.1.tgz", + "integrity": "sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "growly": "^1.3.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.5", + "shellwords": "^0.1.1", + "uuid": "^8.3.2", + "which": "^2.0.2" + } + }, + "node_modules/node-notifier/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-releases": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", + "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "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": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", + "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/observable-fns": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/observable-fns/-/observable-fns-0.6.1.tgz", + "integrity": "sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "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/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-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/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/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/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "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/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "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/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "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/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "engines": { + "node": ">=6" + } + }, + "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": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.6.0.tgz", + "integrity": "sha512-mHrAVSQWmHA41RnUmRpC7pK9lNnMfdA16CF3cqOI22a8LZxOQzF7M8YWtA2nfs+d7I0MTDXOtkDsAsFXeCpYjg==", + "dev": true, + "dependencies": { + "@babel/parser": "7.16.2", + "@babel/types": "7.16.0", + "chalk": "^4.1.2", + "escodegen": "^2.0.0", + "fs-extra": "^9.1.0", + "globby": "^11.0.4", + "into-stream": "^6.0.0", + "minimist": "^1.2.5", + "multistream": "^4.1.0", + "pkg-fetch": "3.3.0", + "prebuild-install": "6.1.4", + "progress": "^2.0.3", + "resolve": "^1.20.0", + "stream-meter": "^1.0.4", + "tslib": "2.3.1" + }, + "bin": { + "pkg": "lib-es5/bin.js" + }, + "peerDependencies": { + "node-notifier": ">=9.0.1" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "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/pkg-fetch": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.3.0.tgz", + "integrity": "sha512-xJnIZ1KP+8rNN+VLafwu4tEeV4m8IkFBDdCFqmAJz9K1aiXEtbARmdbEe6HlXWGSVuShSHjFXpfkKRkDBQ5kiA==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "fs-extra": "^9.1.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.6", + "progress": "^2.0.3", + "semver": "^7.3.5", + "tar-fs": "^2.1.1", + "yargs": "^16.2.0" + }, + "bin": { + "pkg-fetch": "lib-es5/bin.js" + } + }, + "node_modules/pkg-fetch/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/pkg-fetch/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/pkg-fetch/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/pkg-fetch/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pkg-fetch/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/pkg-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "node_modules/pkg-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "node_modules/pkg-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/pkg/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/pkg/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/pkg/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/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prebuild-install": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", + "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", + "dev": true, + "dependencies": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.21.0", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=6" + } + }, + "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/prettier": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.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/printj": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", + "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==", + "bin": { + "printj": "bin/printj.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "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=" + }, + "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/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "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==", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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/ramda": { + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", + "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", + "dev": true + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reachdown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reachdown/-/reachdown-1.1.0.tgz", + "integrity": "sha512-6LsdRe4cZyOjw4NnvbhUd/rGG7WQ9HMopPr+kyL018Uci4kijtxcGR5kVb5Ln13k4PEE+fEFQbjfOvNw7cnXmA==", + "engines": { + "node": ">=6" + } + }, + "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/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/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/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", + "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "node_modules/regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", + "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^9.0.0", + "regjsgen": "^0.5.2", + "regjsparser": "^0.7.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", + "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "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/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "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/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-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-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true + }, + "node_modules/resource-counter": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/resource-counter/-/resource-counter-1.2.4.tgz", + "integrity": "sha512-DGJChvE5r4smqPE+xYNv9r1u/I9cCfRR5yfm7D6EQckdKqMyVpJ5z0s40yn0EM0puFxHg6mPORrQLQdEbJ/RnQ==", + "dependencies": { + "babel-runtime": "^6.26.0", + "bitset": "^5.0.3" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "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/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true, + "engines": { + "node": "6.* || >= 7.*" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "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" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "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==", + "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/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "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/sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "deprecated": "some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added", + "dev": true, + "dependencies": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "bin": { + "sane": "src/cli.js" + }, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/sane/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/sane/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/sane/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/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/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "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==", + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true, + "optional": true + }, + "node_modules/shiki": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", + "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.0.0", + "vscode-oniguruma": "^1.6.1", + "vscode-textmate": "5.2.0" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", + "dev": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "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/simple-get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "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/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/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-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", + "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==", + "dev": true + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.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.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "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/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stream-meter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", + "integrity": "sha1-Uq+Vql6nYKJJFxZwTb/5D3Ov3R0=", + "dev": true, + "dependencies": { + "readable-stream": "^2.1.4" + } + }, + "node_modules/stream-meter/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/stream-meter/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/stream-meter/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/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "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": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "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-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/sublevel-prefixer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sublevel-prefixer/-/sublevel-prefixer-1.0.0.tgz", + "integrity": "sha1-TuRZ72Y6yFvyj8ZJ17eWX9ppEHM=" + }, + "node_modules/subleveldown": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/subleveldown/-/subleveldown-6.0.1.tgz", + "integrity": "sha512-Cnf+cn2wISXU2xflY1SFIqfX4hG2d6lFk2P5F8RDQLmiqN9Ir4ExNfUFH6xnmizMseM/t+nMsDUKjN9Kw6ShFA==", + "dependencies": { + "abstract-leveldown": "^7.2.0", + "encoding-down": "^7.1.0", + "inherits": "^2.0.3", + "level-option-wrap": "^1.1.0", + "levelup": "^5.1.1", + "reachdown": "^1.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "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": "6.7.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", + "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "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/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/threads": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/threads/-/threads-1.7.0.tgz", + "integrity": "sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ==", + "dependencies": { + "callsites": "^3.1.0", + "debug": "^4.2.0", + "is-observable": "^2.1.0", + "observable-fns": "^0.6.1" + }, + "funding": { + "url": "https://github.com/andywer/threads.js?sponsor=1" + }, + "optionalDependencies": { + "tiny-worker": ">= 2" + } + }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "dev": true + }, + "node_modules/timeout-refresh": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-1.0.3.tgz", + "integrity": "sha512-Mz0CX4vBGM5lj8ttbIFt7o4ZMxk/9rgudJRh76EvB7xXZMur7T/cjRiH2w4Fmkq0zxf2QpM8IFvOSRn8FEu3gA==" + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + }, + "node_modules/tiny-worker": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tiny-worker/-/tiny-worker-2.3.0.tgz", + "integrity": "sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==", + "optional": true, + "dependencies": { + "esm": "^3.2.25" + } + }, + "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-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/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-custom-error": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.2.0.tgz", + "integrity": "sha512-cBvC2QjtvJ9JfWLvstVnI45Y46Y5dMxIaG1TDMGAD/R87hpvqFL+7LhvUDhnRCfOnx/xitollFWWvUKKKhbN0A==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/ts-jest": { + "version": "26.5.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz", + "integrity": "sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "buffer-from": "1.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^26.1.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" + }, + "peerDependencies": { + "jest": ">=26 <27", + "typescript": ">=3.8 <5.0" + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", + "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "0.7.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", + "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/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/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "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.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/typedoc": { + "version": "0.22.15", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.15.tgz", + "integrity": "sha512-CMd1lrqQbFvbx6S9G6fL4HKp3GoIuhujJReWqlIvSb2T26vGai+8Os3Mde7Pn832pXYemd9BMuuYWhFpL5st0Q==", + "dev": true, + "dependencies": { + "glob": "^7.2.0", + "lunr": "^2.3.9", + "marked": "^4.0.12", + "minimatch": "^5.0.1", + "shiki": "^0.10.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 12.10.0" + }, + "peerDependencies": { + "typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typescript": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typescript-cached-transpile": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typescript-cached-transpile/-/typescript-cached-transpile-0.0.6.tgz", + "integrity": "sha512-bfPc7YUW0PrVkQHU0xN0ANRuxdPgoYYXtZEW6PNkH5a97/AOM+kPPxSTMZbpWA3BG1do22JUkfC60KoCKJ9VZQ==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.7", + "fs-extra": "^8.1.0", + "tslib": "^1.10.0" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/typescript-cached-transpile/node_modules/@types/node": { + "version": "12.20.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.37.tgz", + "integrity": "sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA==", + "dev": true + }, + "node_modules/typescript-cached-transpile/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/typescript-cached-transpile/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/typescript-cached-transpile/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/uglify-js": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz", + "integrity": "sha512-rtPMlmcO4agTUfz10CbgJ1k6UAoXM2gWb3GoMPPZB/+/Ackf8lNWk11K4rYi2D0apgoFRLtQOZhb+/iGNJq26A==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.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/unordered-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", + "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==" + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-callbackify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util-callbackify/-/util-callbackify-1.0.0.tgz", + "integrity": "sha512-5vEPPSM6DCHlCpq9FZryeIkY5FQMUqXLUz4yHtU369Z/abWUVdgInPVeINjWJV3Bk9DZhCr+JzGarEByPLsxBQ==", + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/utp-native": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/utp-native/-/utp-native-2.5.3.tgz", + "integrity": "sha512-sWTrWYXPhhWJh+cS2baPzhaZc89zwlWCfwSthUjGhLkZztyPhcQllo+XVVCbNGi7dhyRlxkWxN4NKU6FbA9Y8w==", + "hasInstallScript": true, + "dependencies": { + "napi-macros": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.0.2", + "timeout-refresh": "^1.0.0", + "unordered-set": "^2.0.1" + }, + "bin": { + "ucat": "ucat.js" + }, + "engines": { + "node": ">=8.12" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", + "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.10.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/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", + "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", + "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", + "dev": true + }, + "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/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/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-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.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "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==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "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/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "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.5.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", + "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", + "dev": true, + "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/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.15.8", @@ -308,9 +12906,9 @@ } }, "@babel/parser": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", - "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", + "version": "7.16.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", + "integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", "dev": true }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { @@ -1078,12 +13676,12 @@ } }, "@babel/types": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", - "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", + "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.15.7", "to-fast-properties": "^2.0.0" } }, @@ -1416,6 +14014,33 @@ "semver": "^6.3.0" } }, + "node-notifier": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", + "dev": true, + "optional": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.2", + "shellwords": "^0.1.1", + "uuid": "^8.3.0", + "which": "^2.0.2" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -1864,9 +14489,9 @@ } }, "@types/node": { - "version": "14.17.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.27.tgz", - "integrity": "sha512-94+Ahf9IcaDuJTle/2b+wzvjmutxXAEXU6O81JHblYXUg2BDG+dnBy7VxIPHKAyEEDHzCMQydTJuWvrE+Aanzw==" + "version": "16.11.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.29.tgz", + "integrity": "sha512-9dDdonLyPJQJ/kdOlDxAah+bTI+u2ccF3k62FErhquDuggoCX6piWez7j7o6yNE+rP2IRcZVQ6Tw4N0P38+rWA==" }, "@types/node-forge": { "version": "0.9.10", @@ -2093,7 +14718,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "acorn-walk": { "version": "7.2.0", @@ -3709,7 +16335,8 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", - "dev": true + "dev": true, + "requires": {} }, "eslint-import-resolver-node": { "version": "0.3.6", @@ -4278,13 +16905,6 @@ "requires": { "napi-macros": "^2.0.0", "node-gyp-build": "^4.2.2" - }, - "dependencies": { - "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" - } } }, "file-entry-cache": { @@ -5850,19 +18470,22 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/jest-mock-process/-/jest-mock-process-1.4.1.tgz", "integrity": "sha512-ZZUKRlEBizutngoO4KngzN30YoeAYP3nnwimk4cpi9WqLxQUf6SlAPK5p1D9usEpxDS3Uif2MIez3Bq0vGYR+g==", - "dev": true + "dev": true, + "requires": {} }, "jest-mock-props": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/jest-mock-props/-/jest-mock-props-1.9.0.tgz", "integrity": "sha512-8IlIiZRvovnRuvqcvWZyDv4CyhrUGTbEW/1eKurHr2JY4VhIWQIPlbpt9lqL2nxdGnco+OcgpPBwGYCEeDb2+A==", - "dev": true + "dev": true, + "requires": {} }, "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 + "dev": true, + "requires": {} }, "jest-regex-util": { "version": "26.0.0", @@ -6550,13 +19173,6 @@ "abstract-leveldown": "^7.2.0", "napi-macros": "~2.0.0", "node-gyp-build": "^4.3.0" - }, - "dependencies": { - "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" - } } }, "levelup": { @@ -6698,9 +19314,9 @@ } }, "marked": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.7.tgz", - "integrity": "sha512-ctKqbnLuNbsHbI26cfMyOlKgXGfl1orOv1AvWWDX7AkgfMOwCWvmuYc+mVLeWhQ9W6hdWVBynOs96VkcscKo0Q==", + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.14.tgz", + "integrity": "sha512-HL5sSPE/LP6U9qKgngIIPTthuxC0jrfxpYMZ3LdGDD3vTnLs59m2Z7r6+LNDR3ToqEQdkKd6YaaEfJhodJmijQ==", "dev": true }, "md5.js": { @@ -6984,10 +19600,9 @@ "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" }, "node-gyp-build": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", - "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==", - "dev": true + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==" }, "node-int64": { "version": "0.4.0", @@ -7002,17 +19617,18 @@ "dev": true }, "node-notifier": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", - "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-10.0.1.tgz", + "integrity": "sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==", "dev": true, "optional": true, + "peer": true, "requires": { "growly": "^1.3.0", "is-wsl": "^2.2.0", - "semver": "^7.3.2", + "semver": "^7.3.5", "shellwords": "^0.1.1", - "uuid": "^8.3.0", + "uuid": "^8.3.2", "which": "^2.0.2" }, "dependencies": { @@ -7022,6 +19638,7 @@ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "optional": true, + "peer": true, "requires": { "lru-cache": "^6.0.0" } @@ -7034,12 +19651,6 @@ "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", "dev": true }, - "noop-logger": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", - "dev": true - }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -7240,32 +19851,6 @@ "mimic-fn": "^2.1.0" } }, - "onigasm": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/onigasm/-/onigasm-2.2.5.tgz", - "integrity": "sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA==", - "dev": true, - "requires": { - "lru-cache": "^5.1.1" - }, - "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } - } - }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -7435,45 +20020,28 @@ } }, "pkg": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.3.0.tgz", - "integrity": "sha512-/DGG+QcSPraMAIxaoGCNqb2A6Xkm2jBQMsj2mjb4ag236ByTY9Xhpikvj5ixwlSQV0euuJw4fphKCd5YHRPS8w==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.6.0.tgz", + "integrity": "sha512-mHrAVSQWmHA41RnUmRpC7pK9lNnMfdA16CF3cqOI22a8LZxOQzF7M8YWtA2nfs+d7I0MTDXOtkDsAsFXeCpYjg==", "dev": true, "requires": { - "@babel/parser": "7.13.13", - "@babel/types": "7.13.12", - "chalk": "^4.1.0", + "@babel/parser": "7.16.2", + "@babel/types": "7.16.0", + "chalk": "^4.1.2", "escodegen": "^2.0.0", "fs-extra": "^9.1.0", - "globby": "^11.0.3", + "globby": "^11.0.4", "into-stream": "^6.0.0", "minimist": "^1.2.5", "multistream": "^4.1.0", - "pkg-fetch": "3.1.1", - "prebuild-install": "6.0.1", + "pkg-fetch": "3.3.0", + "prebuild-install": "6.1.4", "progress": "^2.0.3", "resolve": "^1.20.0", "stream-meter": "^1.0.4", - "tslib": "2.1.0" + "tslib": "2.3.1" }, "dependencies": { - "@babel/parser": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz", - "integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.12.tgz", - "integrity": "sha512-K4nY2xFN4QMvQwkQ+zmBDp6ANMbVNw6BbxWmYA4qNjhR9W+Lj/8ky5MEY2Me5r+B2c6/v6F53oMndG+f9s3IiA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -7498,12 +20066,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", - "dev": true } } }, @@ -7517,17 +20079,18 @@ } }, "pkg-fetch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.1.1.tgz", - "integrity": "sha512-3GfpNwbwoTxge2TrVp6Oyz/FZJOoxF1r0+1YikOhnBXa2Di/VOJKtUObFHap76BFnyFo1fwh5vARWFR9TzLKUg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.3.0.tgz", + "integrity": "sha512-xJnIZ1KP+8rNN+VLafwu4tEeV4m8IkFBDdCFqmAJz9K1aiXEtbARmdbEe6HlXWGSVuShSHjFXpfkKRkDBQ5kiA==", "dev": true, "requires": { - "chalk": "^4.1.0", + "chalk": "^4.1.2", "fs-extra": "^9.1.0", "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", + "node-fetch": "^2.6.6", "progress": "^2.0.3", "semver": "^7.3.5", + "tar-fs": "^2.1.1", "yargs": "^16.2.0" }, "dependencies": { @@ -7547,10 +20110,19 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -7564,6 +20136,28 @@ "requires": { "has-flag": "^4.0.0" } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } } } }, @@ -7574,9 +20168,9 @@ "dev": true }, "prebuild-install": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.0.1.tgz", - "integrity": "sha512-7GOJrLuow8yeiyv75rmvZyeMGzl8mdEX5gY69d6a6bHWmiPevwqFw+tQavhK0EYMaSg3/KD24cWqeQv1EWsqDQ==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", + "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", "dev": true, "requires": { "detect-libc": "^1.0.3", @@ -7585,15 +20179,13 @@ "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^1.0.1", - "node-abi": "^2.7.0", - "noop-logger": "^0.1.1", + "node-abi": "^2.21.0", "npmlog": "^4.0.1", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^3.0.3", "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0", - "which-pm-runs": "^1.0.0" + "tunnel-agent": "^0.6.0" } }, "prelude-ls": { @@ -8231,13 +20823,13 @@ "optional": true }, "shiki": { - "version": "0.9.12", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.12.tgz", - "integrity": "sha512-VXcROdldv0/Qu0w2XvzU4IrvTeBNs/Kj/FCmtcEXGz7Tic/veQzliJj6tEiAgoKianhQstpYmbPDStHU5Opqcw==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", + "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", "dev": true, "requires": { "jsonc-parser": "^3.0.0", - "onigasm": "^2.2.5", + "vscode-oniguruma": "^1.6.1", "vscode-textmate": "5.2.0" } }, @@ -8591,6 +21183,14 @@ } } }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -8630,14 +21230,6 @@ "define-properties": "^1.1.3" } }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -9086,31 +21678,42 @@ } }, "typedoc": { - "version": "0.21.9", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.21.9.tgz", - "integrity": "sha512-VRo7aII4bnYaBBM1lhw4bQFmUcDQV8m8tqgjtc7oXl87jc1Slbhfw2X5MccfcR2YnEClHDWgsiQGgNB8KJXocA==", + "version": "0.22.15", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.15.tgz", + "integrity": "sha512-CMd1lrqQbFvbx6S9G6fL4HKp3GoIuhujJReWqlIvSb2T26vGai+8Os3Mde7Pn832pXYemd9BMuuYWhFpL5st0Q==", "dev": true, "requires": { - "glob": "^7.1.7", - "handlebars": "^4.7.7", + "glob": "^7.2.0", "lunr": "^2.3.9", - "marked": "^3.0.2", - "minimatch": "^3.0.0", - "progress": "^2.0.3", - "shiki": "^0.9.8", - "typedoc-default-themes": "^0.12.10" + "marked": "^4.0.12", + "minimatch": "^5.0.1", + "shiki": "^0.10.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, - "typedoc-default-themes": { - "version": "0.12.10", - "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.12.10.tgz", - "integrity": "sha512-fIS001cAYHkyQPidWXmHuhs8usjP5XVJjWB8oZGqkTowZaz3v7g3KDZeeqE82FBrmkAnIBOY3jgy7lnPnqATbA==", - "dev": true - }, "typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", "dev": true }, "typescript-cached-transpile": { @@ -9326,13 +21929,6 @@ "readable-stream": "^3.0.2", "timeout-refresh": "^1.0.0", "unordered-set": "^2.0.1" - }, - "dependencies": { - "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" - } } }, "uuid": { @@ -9375,6 +21971,12 @@ "spdx-expression-parse": "^3.0.0" } }, + "vscode-oniguruma": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", + "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", + "dev": true + }, "vscode-textmate": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", @@ -9466,12 +22068,6 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "which-pm-runs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", - "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", - "dev": true - }, "wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -9525,7 +22121,8 @@ "version": "7.5.5", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", - "dev": true + "dev": true, + "requires": {} }, "xml-name-validator": { "version": "3.0.0", diff --git a/package.json b/package.json index 64d3ae3c1..378296407 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "test": "jest", "lint": "eslint '{src,tests}/**/*.{js,ts}'", "lintfix": "eslint '{src,tests}/**/*.{js,ts}' --fix", - "docs": "rm -r ./docs || true; typedoc --gitRevision master --tsconfig ./tsconfig.build.json --out ./docs src && touch ./docs/.nojekyll", + "docs": "rm -r ./docs || true; typedoc --gitRevision master --tsconfig ./tsconfig.build.json --out ./docs src", "bench": "rm -r ./benches/results || true; ts-node --require tsconfig-paths/register --compiler typescript-cached-transpile --transpile-only ./benches", "proto-generate": "scripts/proto-generate.sh", "polykey": "ts-node --require tsconfig-paths/register --compiler typescript-cached-transpile --transpile-only src/bin/polykey.ts" @@ -111,7 +111,7 @@ "@types/google-protobuf": "^3.7.4", "@types/jest": "^26.0.20", "@types/nexpect": "^0.4.31", - "@types/node": "^14.14.35", + "@types/node": "^16.11.7", "@types/node-forge": "^0.9.7", "@types/pako": "^1.0.2", "@types/prompts": "^2.0.13", @@ -130,14 +130,14 @@ "jest-mock-props": "^1.9.0", "mocked-env": "^1.3.5", "nexpect": "^0.6.0", - "node-gyp-build": "4.2.3", - "pkg": "5.3.0", + "node-gyp-build": "4.4.0", + "pkg": "5.6.0", "prettier": "^2.2.1", "ts-jest": "^26.4.4", "ts-node": "^10.4.0", "tsconfig-paths": "^3.9.0", - "typedoc": "^0.21.5", - "typescript": "^4.1.3", + "typedoc": "^0.22.15", + "typescript": "^4.5.2", "typescript-cached-transpile": "0.0.6" } } diff --git a/pkgs.nix b/pkgs.nix index 4b5b0c11b..6fe22a5b7 100644 --- a/pkgs.nix +++ b/pkgs.nix @@ -1,4 +1,4 @@ import ( - let rev = "53caacaf56640d04180775aee016d2f16d6f083c"; in - fetchTarball "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz" + let rev = "a5774e76bb8c3145eac524be62375c937143b80c"; in + builtins.fetchTarball "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz" ) diff --git a/release.nix b/release.nix index c806c1fc5..e778a0073 100644 --- a/release.nix +++ b/release.nix @@ -18,7 +18,7 @@ let buildPhase = '' cp ${./package.json} package.json pkg . \ - --targets linux-${arch} \ + --targets node${utils.nodeVersion}-linux-${arch} \ --no-bytecode \ --public \ --public-packages "*" \ @@ -44,7 +44,7 @@ let buildPhase = '' cp ${./package.json} package.json pkg . \ - --targets win-${arch} \ + --targets node${utils.nodeVersion}-win-${arch} \ --no-bytecode \ --public \ --public-packages "*" \ @@ -70,7 +70,7 @@ let buildPhase = '' cp ${./package.json} package.json pkg . \ - --targets macos-${arch} \ + --targets node${utils.nodeVersion}-macos-${arch} \ --no-bytecode \ --public \ --public-packages "*" \ diff --git a/shell.nix b/shell.nix index 318d807aa..10f435f98 100644 --- a/shell.nix +++ b/shell.nix @@ -7,7 +7,7 @@ in pkgs.mkShell { nativeBuildInputs = [ nodejs - nodePackages.node2nix + utils.node2nix grpc-tools grpcurl utils.pkg diff --git a/tsconfig.json b/tsconfig.json index d4abc0d16..8e4424ab2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,7 @@ "resolveJsonModule": true, "moduleResolution": "node", "module": "CommonJS", - "target": "ES2020", + "target": "ES2021", "baseUrl": "./src", "paths": { "@": ["index"], diff --git a/utils.nix b/utils.nix index fe376455a..e63e463df 100644 --- a/utils.nix +++ b/utils.nix @@ -6,6 +6,7 @@ , pkgs , lib , fetchurl +, fetchFromGitHub }: rec { @@ -13,9 +14,17 @@ rec { basename = builtins.baseNameOf node2nixDev.packageName; src = nix-gitignore.gitignoreSource [".git"] ./.; nodeVersion = builtins.elemAt (lib.versions.splitVersion nodejs.version) 0; + # custom node2nix directly from GitHub + node2nixSrc = fetchFromGitHub { + owner = "svanderburg"; + repo = "node2nix"; + rev = "68f5735f9a56737e3fedceb182705985e3ab8799"; + sha256 = "1f791vikig65ly5vcw6zjd0nv2qb8l5w5lr3xy343iq6746s1bil"; + }; + node2nix = (import "${node2nixSrc}/release.nix" {}).package.x86_64-linux; node2nixDrv = dev: runCommandNoCC "node2nix" {} '' mkdir $out - ${nodePackages.node2nix}/bin/node2nix \ + ${node2nix}/bin/node2nix \ ${lib.optionalString dev "--development"} \ --input ${src}/package.json \ --lock ${src}/package-lock.json \ @@ -36,35 +45,30 @@ rec { buildInputs = attrs.buildInputs ++ [ nodePackages.node-gyp-build ]; dontNpmInstall = true; postInstall = '' - # The dependencies were prepared in the install phase - # See `node2nix` generated `node-env.nix` for details. + # The dependencies were prepared in the installphase + # See `node2nix` generated `node-env.nix` for details npm run build - - # This call does not actually install packages. The dependencies - # are present in `node_modules` already. It creates symlinks in - # $out/lib/node_modules/.bin according to `bin` section in `package.json`. - npm install ''; }); pkgBuilds = { - "3.1" = { + "3.3" = { "linux-x64" = fetchurl { - url = "https://github.com/vercel/pkg-fetch/releases/download/v3.1/node-v14.17.0-linux-x64"; - sha256 = "11vk7vfxa1327mr71gys8fhglrpscjaxrpnbk1jbnj5llyzcx52l"; + url = "https://github.com/vercel/pkg-fetch/releases/download/v3.3/node-v16.14.2-linux-x64"; + sha256 = "1g5sljbb7zqqbfvl3n1hzfy6fd97ch06bbjfxnd7bz6ncmjk3rcg"; }; "win32-x64" = fetchurl { - url = "https://github.com/vercel/pkg-fetch/releases/download/v3.1/node-v14.17.0-win-x64"; - sha256 = "08wf9ldy33sac1vmhd575zf2fhrbci3wz88a9nwdbccsxrkbgklc"; + url = "https://github.com/vercel/pkg-fetch/releases/download/v3.3/node-v16.14.2-win-x64"; + sha256 = "1c1fr8fvrfm49qgn0dibbr5givz2qccb91qrwilxlhj289ba0sgm"; }; "macos-x64" = fetchurl { - url = "https://github.com/vercel/pkg-fetch/releases/download/v3.1/node-v14.17.0-macos-x64"; - sha256 = "0lwa6s66wy7qmj4wbpa65hv996vxzznrscqgwrk3q2zzpsra24q7"; + url = "https://github.com/vercel/pkg-fetch/releases/download/v3.3/node-v16.14.2-macos-x64"; + sha256 = "1hq7v40vzc2bfr29y71lm0snaxcc8rys5w0da7pi5nmx4pyybc2v"; }; }; }; pkgCachePath = let - pkgBuild = pkgBuilds."3.1"; + pkgBuild = pkgBuilds."3.3"; fetchedName = n: builtins.replaceStrings ["node"] ["fetched"] n; in linkFarm "pkg-cache" @@ -82,7 +86,7 @@ rec { path = pkgBuild.macos-x64; } ]; - pkg = pkgs.nodePackages.pkg.override { + pkg = nodePackages.pkg.override { postFixup = '' patch -p0 < ${./nix/leveldown.patch} ''; From 69d42f95966654f80f366542393f4d57af4d5cf3 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 26 Apr 2022 15:09:11 +1000 Subject: [PATCH 003/137] build: updating core libraries Updated js-async-init from 1.6.0 to 1.7.1 Updated js-async-locks from 2.0.0 to 2.2.0 Updated js-db from 3.2.0 to 3.2.3 Updating js-workers from 1.2.5 to 1.3.1 --- package-lock.json | 126 +++++++++++++++++----------------------------- package.json | 8 +-- 2 files changed, 50 insertions(+), 84 deletions(-) diff --git a/package-lock.json b/package-lock.json index e34a3abe0..4ca87586d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,14 +10,14 @@ "license": "GPL-3.0", "dependencies": { "@grpc/grpc-js": "1.3.7", - "@matrixai/async-init": "^1.6.0", - "@matrixai/async-locks": "^2.0.0", - "@matrixai/db": "^3.2.0", + "@matrixai/async-init": "^1.7.1", + "@matrixai/async-locks": "^2.2.0", + "@matrixai/db": "^3.2.3", "@matrixai/errors": "^1.0.1", "@matrixai/id": "^3.3.2", "@matrixai/logger": "^2.1.0", "@matrixai/resources": "^1.0.0", - "@matrixai/workers": "^1.2.5", + "@matrixai/workers": "^1.3.1", "ajv": "^7.0.4", "bip39": "^3.0.3", "canonicalize": "^1.0.5", @@ -2287,55 +2287,39 @@ } }, "node_modules/@matrixai/async-init": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.6.0.tgz", - "integrity": "sha512-I24u6McZnSH2yX1l5e2H3O/Lu8IVb2fM/sVbDeRYrzejV2XLv/9g/goz2fglSrXgJ877BBFJNW2GMxVzvvyA5A==", - "dependencies": { - "async-mutex": "^0.3.2", - "ts-custom-error": "^3.2.0" - } - }, - "node_modules/@matrixai/async-init/node_modules/async-mutex": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", - "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.7.1.tgz", + "integrity": "sha512-3ELRuEn6AoC3e0b4QccA+NxZl0LilyjYeu6a3Pf9VUVB89EepnNKsk/Afb9qa+B5LvLQwmgHtg4r9VwRpQpnQA==", "dependencies": { - "tslib": "^2.3.1" + "@matrixai/async-locks": "^2.2.0", + "@matrixai/errors": "^1.0.1" } }, "node_modules/@matrixai/async-locks": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.0.0.tgz", - "integrity": "sha512-wpU6L5o/0BhBsjYt4BH2J3L0+yDhxotCi6cRF7QZbm03u/tdq8tgwyOzXe+MPArh+EZhsBrnBOCdUpUhgZNRZQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.2.0.tgz", + "integrity": "sha512-i0a551EUMhD1WKpaAyhBUt83ckbOxPB4MlOH8VDzeDyPMAtLI9egCqf3HWOvhN0rSjoH97EmzmfxyAeAgiQzTw==", "dependencies": { + "@matrixai/errors": "^1.0.1", "@matrixai/resources": "^1.0.0", - "async-mutex": "^0.3.2", - "ts-custom-error": "^3.2.0" + "async-mutex": "^0.3.2" } }, "node_modules/@matrixai/db": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.2.0.tgz", - "integrity": "sha512-JfcpZ8zbNgdQK3mpHQisCY6TKGUO5+Issh5KDvR3zBtfdSKHJLgrqweDIyLtM9D0RT5jO5HOY+lthI/8Yfi/PA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.3.1.tgz", + "integrity": "sha512-EQulm82sBhw1WRhOzzWMoij1SwpjAQHgyokxleTwFHoAnDPMi4WVy4AIxd2lJMPOhhzEFQxCqQmmMYhZWwYAPg==", "dependencies": { - "@matrixai/async-init": "^1.6.0", + "@matrixai/async-init": "^1.7.0", "@matrixai/errors": "^1.0.1", "@matrixai/logger": "^2.1.0", "@matrixai/resources": "^1.0.0", - "@matrixai/workers": "^1.2.5", + "@matrixai/workers": "^1.3.0", "@types/abstract-leveldown": "^7.2.0", "level": "7.0.1", "threads": "^1.6.5" } }, - "node_modules/@matrixai/db/node_modules/@matrixai/errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.0.1.tgz", - "integrity": "sha512-9NbIm3rPMkZz+Ma5tfKduVCWfvYzdHlO89u9mBap7FzJqXkl4yoENjMZm5Do6PvhtIYtRcm6+eTgWvHd6pkdGg==", - "dependencies": { - "ts-custom-error": "^3.2.0" - } - }, "node_modules/@matrixai/errors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.0.1.tgz", @@ -2364,13 +2348,14 @@ "integrity": "sha512-B1ZkySZwOZTIzhK+YTN4HifOTd1dk1ifDUV8/8WgGho2nUZzIMYms7iDmW/ZHUCkqvWupKY6AYvfwnKBOJJnWg==" }, "node_modules/@matrixai/workers": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@matrixai/workers/-/workers-1.2.5.tgz", - "integrity": "sha512-ikI4K6RGKQbG68it7TXJJ5wX2csW+WpokUehTnz5r66d7o6FC3PkojE46LPLCDSwk3NVCGoQ743OZS2nuA8SRA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@matrixai/workers/-/workers-1.3.1.tgz", + "integrity": "sha512-AXI37aZ7gSqS5PpUCG7/yfNcnWNYiQUp4yFBY1Z9lKk0zrkQzND1zPjDuJ2E7t6E1a4rwa8vtysj5TVeMCA8jw==", "dependencies": { + "@matrixai/async-init": "^1.7.0", + "@matrixai/errors": "^1.0.1", "@matrixai/logger": "^2.1.0", - "threads": "^1.6.5", - "ts-custom-error": "^3.2.0" + "threads": "^1.6.5" } }, "node_modules/@nodelib/fs.scandir": { @@ -14199,57 +14184,37 @@ } }, "@matrixai/async-init": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.6.0.tgz", - "integrity": "sha512-I24u6McZnSH2yX1l5e2H3O/Lu8IVb2fM/sVbDeRYrzejV2XLv/9g/goz2fglSrXgJ877BBFJNW2GMxVzvvyA5A==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.7.1.tgz", + "integrity": "sha512-3ELRuEn6AoC3e0b4QccA+NxZl0LilyjYeu6a3Pf9VUVB89EepnNKsk/Afb9qa+B5LvLQwmgHtg4r9VwRpQpnQA==", "requires": { - "async-mutex": "^0.3.2", - "ts-custom-error": "^3.2.0" - }, - "dependencies": { - "async-mutex": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", - "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", - "requires": { - "tslib": "^2.3.1" - } - } + "@matrixai/async-locks": "^2.2.0", + "@matrixai/errors": "^1.0.1" } }, "@matrixai/async-locks": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.0.0.tgz", - "integrity": "sha512-wpU6L5o/0BhBsjYt4BH2J3L0+yDhxotCi6cRF7QZbm03u/tdq8tgwyOzXe+MPArh+EZhsBrnBOCdUpUhgZNRZQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.2.0.tgz", + "integrity": "sha512-i0a551EUMhD1WKpaAyhBUt83ckbOxPB4MlOH8VDzeDyPMAtLI9egCqf3HWOvhN0rSjoH97EmzmfxyAeAgiQzTw==", "requires": { + "@matrixai/errors": "^1.0.1", "@matrixai/resources": "^1.0.0", - "async-mutex": "^0.3.2", - "ts-custom-error": "^3.2.0" + "async-mutex": "^0.3.2" } }, "@matrixai/db": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.2.0.tgz", - "integrity": "sha512-JfcpZ8zbNgdQK3mpHQisCY6TKGUO5+Issh5KDvR3zBtfdSKHJLgrqweDIyLtM9D0RT5jO5HOY+lthI/8Yfi/PA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.3.1.tgz", + "integrity": "sha512-EQulm82sBhw1WRhOzzWMoij1SwpjAQHgyokxleTwFHoAnDPMi4WVy4AIxd2lJMPOhhzEFQxCqQmmMYhZWwYAPg==", "requires": { - "@matrixai/async-init": "^1.6.0", + "@matrixai/async-init": "^1.7.0", "@matrixai/errors": "^1.0.1", "@matrixai/logger": "^2.1.0", "@matrixai/resources": "^1.0.0", - "@matrixai/workers": "^1.2.5", + "@matrixai/workers": "^1.3.0", "@types/abstract-leveldown": "^7.2.0", "level": "7.0.1", "threads": "^1.6.5" - }, - "dependencies": { - "@matrixai/errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.0.1.tgz", - "integrity": "sha512-9NbIm3rPMkZz+Ma5tfKduVCWfvYzdHlO89u9mBap7FzJqXkl4yoENjMZm5Do6PvhtIYtRcm6+eTgWvHd6pkdGg==", - "requires": { - "ts-custom-error": "^3.2.0" - } - } } }, "@matrixai/errors": { @@ -14280,13 +14245,14 @@ "integrity": "sha512-B1ZkySZwOZTIzhK+YTN4HifOTd1dk1ifDUV8/8WgGho2nUZzIMYms7iDmW/ZHUCkqvWupKY6AYvfwnKBOJJnWg==" }, "@matrixai/workers": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@matrixai/workers/-/workers-1.2.5.tgz", - "integrity": "sha512-ikI4K6RGKQbG68it7TXJJ5wX2csW+WpokUehTnz5r66d7o6FC3PkojE46LPLCDSwk3NVCGoQ743OZS2nuA8SRA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@matrixai/workers/-/workers-1.3.1.tgz", + "integrity": "sha512-AXI37aZ7gSqS5PpUCG7/yfNcnWNYiQUp4yFBY1Z9lKk0zrkQzND1zPjDuJ2E7t6E1a4rwa8vtysj5TVeMCA8jw==", "requires": { + "@matrixai/async-init": "^1.7.0", + "@matrixai/errors": "^1.0.1", "@matrixai/logger": "^2.1.0", - "threads": "^1.6.5", - "ts-custom-error": "^3.2.0" + "threads": "^1.6.5" } }, "@nodelib/fs.scandir": { diff --git a/package.json b/package.json index 378296407..78eeae9a9 100644 --- a/package.json +++ b/package.json @@ -72,14 +72,14 @@ }, "dependencies": { "@grpc/grpc-js": "1.3.7", - "@matrixai/async-init": "^1.6.0", - "@matrixai/async-locks": "^2.0.0", - "@matrixai/db": "^3.2.0", + "@matrixai/async-init": "^1.7.1", + "@matrixai/async-locks": "^2.2.0", + "@matrixai/db": "^3.2.3", "@matrixai/errors": "^1.0.1", "@matrixai/id": "^3.3.2", "@matrixai/logger": "^2.1.0", "@matrixai/resources": "^1.0.0", - "@matrixai/workers": "^1.2.5", + "@matrixai/workers": "^1.3.1", "ajv": "^7.0.4", "bip39": "^3.0.3", "canonicalize": "^1.0.5", From b45be1075e871ce41e10f7c6753e442b37a1b52d Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 26 Apr 2022 15:12:52 +1000 Subject: [PATCH 004/137] feat: static descriptions and exit codes for all errors The `data` POJO that was originally supplied in the constructor as the second parameter is now part of the `options` parameter and most places in the code have been updated to match this. #304 --- src/ErrorPolykey.ts | 14 +-- src/acl/ACL.ts | 39 ++++---- src/acl/errors.ts | 48 ++++++--- src/agent/errors.ts | 21 ++-- src/bin/agent/CommandStart.ts | 6 +- src/bin/errors.ts | 42 ++++---- src/bin/keys/CommandDecrypt.ts | 10 +- src/bin/keys/CommandEncrypt.ts | 10 +- src/bin/keys/CommandSign.ts | 10 +- src/bin/keys/CommandVerify.ts | 10 +- src/bin/polykey-agent.ts | 2 +- src/bin/secrets/CommandCreate.ts | 10 +- src/bin/secrets/CommandEdit.ts | 10 +- src/bin/secrets/CommandUpdate.ts | 10 +- src/bin/utils/processors.ts | 40 +++++--- src/bootstrap/errors.ts | 6 +- src/claims/errors.ts | 95 +++++++++++++----- src/client/errors.ts | 18 ++-- src/discovery/errors.ts | 19 +++- src/errors.ts | 38 ++++++-- src/gestalts/errors.ts | 29 ++++-- src/git/errors.ts | 28 ++++-- src/grpc/errors.ts | 49 +++++++--- src/grpc/utils/utils.ts | 16 +-- src/identities/errors.ts | 69 +++++++++---- src/keys/KeyManager.ts | 150 +++++++++++++++++------------ src/keys/errors.ts | 84 ++++++++++++---- src/locks/Locks.ts | 14 ++- src/network/ConnectionForward.ts | 8 +- src/network/ConnectionReverse.ts | 16 +-- src/network/errors.ts | 98 ++++++++++--------- src/network/utils.ts | 86 ++++++++++------- src/nodes/NodeConnectionManager.ts | 4 +- src/nodes/errors.ts | 54 +++++------ src/notifications/errors.ts | 66 +++++++++---- src/schema/Schema.ts | 50 ++++++---- src/schema/errors.ts | 58 ++++++++--- src/sessions/errors.ts | 48 ++++++--- src/sigchain/errors.ts | 46 ++++++--- src/status/Status.ts | 64 +++++++----- src/status/errors.ts | 31 +++--- src/utils/errors.ts | 14 +-- src/validation/errors.ts | 23 +++-- src/vaults/VaultManager.ts | 20 ++-- src/vaults/errors.ts | 91 ++++++++--------- 45 files changed, 1052 insertions(+), 622 deletions(-) diff --git a/src/ErrorPolykey.ts b/src/ErrorPolykey.ts index 414b95732..17a65d04a 100644 --- a/src/ErrorPolykey.ts +++ b/src/ErrorPolykey.ts @@ -1,22 +1,18 @@ -import type { POJO } from './types'; -import { CustomError } from 'ts-custom-error'; +import { AbstractError } from '@matrixai/errors'; import sysexits from './utils/sysexits'; -class ErrorPolykey extends CustomError { - data: POJO; - description: string = 'Polykey error'; +class ErrorPolykey extends AbstractError { + static description: string = 'Polykey error'; exitCode: number = sysexits.GENERAL; - constructor(message: string = '', data: POJO = {}) { - super(message); - this.data = data; - } toJSON(): string { return JSON.stringify({ name: this.name, description: this.description, message: this.message, exitCode: this.exitCode, + timestamp: this.timestamp, data: this.data, + cause: this.cause, stack: this.stack, }); } diff --git a/src/acl/ACL.ts b/src/acl/ACL.ts index 2bff1d5f9..02b2868ff 100644 --- a/src/acl/ACL.ts +++ b/src/acl/ACL.ts @@ -1,9 +1,4 @@ -import type { - DB, - DBTransaction, - KeyPath, - LevelPath -} from '@matrixai/db'; +import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; import type { PermissionId, PermissionIdString, @@ -18,15 +13,14 @@ import type { Ref } from '../types'; import Logger from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; -import { RWLockWriter } from '@matrixai/async-locks'; import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; -import * as aclUtils from './utils'; -import * as aclErrors from './errors'; import { utils as dbUtils } from '@matrixai/db'; import { withF } from '@matrixai/resources'; +import * as aclUtils from './utils'; +import * as aclErrors from './errors'; interface ACL extends CreateDestroyStartStop {} @CreateDestroyStartStop( @@ -36,17 +30,15 @@ interface ACL extends CreateDestroyStartStop {} class ACL { static async createACL({ db, - locks, logger = new Logger(this.name), fresh = false, }: { db: DB; - locks: Locks; logger?: Logger; fresh?: boolean; }): Promise { logger.info(`Creating ${this.name}`); - const acl = new ACL({ db, locks, logger }); + const acl = new ACL({ db, logger }); await acl.start({ fresh }); logger.info(`Created ${this.name}`); return acl; @@ -72,7 +64,7 @@ class ACL { */ protected aclVaultsDbPath: LevelPath = [this.constructor.name, 'vaults']; - // lock across the usages of the DB + // Lock across the usages of the DB // it makes sense to use // Symbol.for("key") // symbol for is found in teh global registry, if it doesn't exist, it is added to the global registry and returned @@ -99,10 +91,9 @@ class ACL { protected generatePermId: () => PermissionId; - constructor({ db, locks, logger }: { db: DB; locks: Locks; logger: Logger }) { + constructor({ db, logger }: { db: DB; logger: Logger }) { this.logger = logger; this.db = db; - this.locks = locks; } public async start({ @@ -135,24 +126,32 @@ class ACL { nodeId2: NodeId, tran?: DBTransaction, ): Promise { - const nodeId1Path = [...this.aclNodesDbPath, nodeId1.toBuffer()] as unknown as KeyPath; - const nodeId2Path = [...this.aclNodesDbPath, nodeId2.toBuffer()] as unknown as KeyPath; + const nodeId1Path = [ + ...this.aclNodesDbPath, + nodeId1.toBuffer(), + ] as unknown as KeyPath; + const nodeId2Path = [ + ...this.aclNodesDbPath, + nodeId2.toBuffer(), + ] as unknown as KeyPath; if (tran == null) { return withF( [ this.db.transaction(), this.locks.lockRead( dbUtils.keyPathToKey(nodeId1Path).toString('binary'), - dbUtils.keyPathToKey(nodeId2Path).toString('binary') + dbUtils.keyPathToKey(nodeId2Path).toString('binary'), ), ], - async ([tran]) => this.sameNodePerm(nodeId1, nodeId2, tran) + async ([tran]) => this.sameNodePerm(nodeId1, nodeId2, tran), ); } const permId1 = await tran.get(nodeId1Path, true); const permId2 = await tran.get(nodeId2Path, true); if (permId1 != null && permId2 != null) { - return IdInternal.fromBuffer(permId1).equals(IdInternal.fromBuffer(permId2)); + return IdInternal.fromBuffer(permId1).equals( + IdInternal.fromBuffer(permId2), + ); } return false; } diff --git a/src/acl/errors.ts b/src/acl/errors.ts index f22044397..508513759 100644 --- a/src/acl/errors.ts +++ b/src/acl/errors.ts @@ -1,18 +1,36 @@ -import { ErrorPolykey } from '../errors'; - -class ErrorACL extends ErrorPolykey {} - -class ErrorACLRunning extends ErrorACL {} - -class ErrorACLNotRunning extends ErrorACL {} - -class ErrorACLDestroyed extends ErrorACL {} - -class ErrorACLNodeIdMissing extends ErrorACL {} - -class ErrorACLVaultIdMissing extends ErrorACL {} - -class ErrorACLNodeIdExists extends ErrorACL {} +import { ErrorPolykey, sysexits } from '../errors'; + +class ErrorACL extends ErrorPolykey {} + +class ErrorACLRunning extends ErrorACL { + static description = 'ACL is running'; + exitCode = sysexits.USAGE; +} + +class ErrorACLNotRunning extends ErrorACL { + static description = 'ACL is not running'; + exitCode = sysexits.USAGE; +} + +class ErrorACLDestroyed extends ErrorACL { + static description = 'ACL is destroyed'; + exitCode = sysexits.USAGE; +} + +class ErrorACLNodeIdMissing extends ErrorACL { + static description = 'Could not find NodeId'; + exitCode = sysexits.NOUSER; +} + +class ErrorACLVaultIdMissing extends ErrorACL { + static description = 'Could not find VaultId'; + exitCode = sysexits.DATAERR; +} + +class ErrorACLNodeIdExists extends ErrorACL { + static description = 'NodeId already exists'; + exitCode = sysexits.DATAERR; +} export { ErrorACL, diff --git a/src/agent/errors.ts b/src/agent/errors.ts index e4db4293c..b0460055c 100644 --- a/src/agent/errors.ts +++ b/src/agent/errors.ts @@ -1,15 +1,24 @@ import { ErrorPolykey, sysexits } from '../errors'; -class ErrorAgent extends ErrorPolykey {} +class ErrorAgent extends ErrorPolykey {} -class ErrorAgentRunning extends ErrorPolykey {} +class ErrorAgentRunning extends ErrorPolykey { + static description = 'Agent Client is running'; + exitCode = sysexits.USAGE; +} -class ErrorAgentClientNotStarted extends ErrorAgent {} +class ErrorAgentClientNotStarted extends ErrorAgent { + static description = 'Agent Client is not started'; + exitCode = sysexits.USAGE; +} -class ErrorAgentClientDestroyed extends ErrorAgent {} +class ErrorAgentClientDestroyed extends ErrorAgent { + static description = 'Agent Client is destroyed'; + exitCode = sysexits.USAGE; +} -class ErrorConnectionInfoMissing extends ErrorAgent { - description = 'Vault already exists'; +class ErrorConnectionInfoMissing extends ErrorAgent { + static description = 'Vault already exists'; exitCode = sysexits.UNAVAILABLE; } diff --git a/src/bin/agent/CommandStart.ts b/src/bin/agent/CommandStart.ts index d99a60369..e4b863a47 100644 --- a/src/bin/agent/CommandStart.ts +++ b/src/bin/agent/CommandStart.ts @@ -175,8 +175,10 @@ class CommandStart extends CommandPolykey { new binErrors.ErrorCLIPolykeyAgentProcess( 'Agent process closed during fork', { - code, - signal, + data: { + code, + signal, + }, }, ), ); diff --git a/src/bin/errors.ts b/src/bin/errors.ts index e8fa532a4..95951d260 100644 --- a/src/bin/errors.ts +++ b/src/bin/errors.ts @@ -1,56 +1,56 @@ import ErrorPolykey from '../ErrorPolykey'; import sysexits from '../utils/sysexits'; -class ErrorCLI extends ErrorPolykey {} +class ErrorCLI extends ErrorPolykey {} -class ErrorCLINodePath extends ErrorCLI { - description = 'Cannot derive default node path from unknown platform'; +class ErrorCLINodePath extends ErrorCLI { + static description = 'Cannot derive default node path from unknown platform'; exitCode = sysexits.USAGE; } -class ErrorCLIClientOptions extends ErrorCLI { - description = 'Missing required client options'; +class ErrorCLIClientOptions extends ErrorCLI { + static description = 'Missing required client options'; exitCode = sysexits.USAGE; } -class ErrorCLIPasswordMissing extends ErrorCLI { - description = +class ErrorCLIPasswordMissing extends ErrorCLI { + static description = 'Password is necessary, provide it via --password-file, PK_PASSWORD or when prompted'; exitCode = sysexits.USAGE; } -class ErrorCLIPasswordFileRead extends ErrorCLI { - description = 'Failed to read password file'; +class ErrorCLIPasswordFileRead extends ErrorCLI { + static description = 'Failed to read password file'; exitCode = sysexits.NOINPUT; } -class ErrorCLIRecoveryCodeFileRead extends ErrorCLI { - description = 'Failed to read recovery code file'; +class ErrorCLIRecoveryCodeFileRead extends ErrorCLI { + static description = 'Failed to read recovery code file'; exitCode = sysexits.NOINPUT; } -class ErrorCLIFileRead extends ErrorCLI { - description = 'Failed to read file'; +class ErrorCLIFileRead extends ErrorCLI { + static description = 'Failed to read file'; exitCode = sysexits.NOINPUT; } -class ErrorCLIPolykeyAgentStatus extends ErrorCLI { - description = 'PolykeyAgent agent status'; +class ErrorCLIPolykeyAgentStatus extends ErrorCLI { + static description = 'PolykeyAgent agent status'; exitCode = sysexits.TEMPFAIL; } -class ErrorCLIPolykeyAgentProcess extends ErrorCLI { - description = 'PolykeyAgent process could not be started'; +class ErrorCLIPolykeyAgentProcess extends ErrorCLI { + static description = 'PolykeyAgent process could not be started'; exitCode = sysexits.OSERR; } -class ErrorNodeFindFailed extends ErrorCLI { - description = 'Failed to find the node in the DHT'; +class ErrorNodeFindFailed extends ErrorCLI { + static description = 'Failed to find the node in the DHT'; exitCode = 1; } -class ErrorNodePingFailed extends ErrorCLI { - description = 'Node was not online or not found.'; +class ErrorNodePingFailed extends ErrorCLI { + static description = 'Node was not online or not found.'; exitCode = 1; } diff --git a/src/bin/keys/CommandDecrypt.ts b/src/bin/keys/CommandDecrypt.ts index 137757bbb..c45691596 100644 --- a/src/bin/keys/CommandDecrypt.ts +++ b/src/bin/keys/CommandDecrypt.ts @@ -52,10 +52,12 @@ class CommandDecrypt extends CommandPolykey { }); } catch (e) { throw new binErrors.ErrorCLIFileRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } cryptoMessage.setData(cipherText); diff --git a/src/bin/keys/CommandEncrypt.ts b/src/bin/keys/CommandEncrypt.ts index dac9d52eb..3d8ddc601 100644 --- a/src/bin/keys/CommandEncrypt.ts +++ b/src/bin/keys/CommandEncrypt.ts @@ -52,10 +52,12 @@ class CommandEncypt extends CommandPolykey { }); } catch (e) { throw new binErrors.ErrorCLIFileRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } cryptoMessage.setData(plainText); diff --git a/src/bin/keys/CommandSign.ts b/src/bin/keys/CommandSign.ts index 4d94d2a24..e69007eb6 100644 --- a/src/bin/keys/CommandSign.ts +++ b/src/bin/keys/CommandSign.ts @@ -52,10 +52,12 @@ class CommandSign extends CommandPolykey { }); } catch (e) { throw new binErrors.ErrorCLIFileRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } cryptoMessage.setData(data); diff --git a/src/bin/keys/CommandVerify.ts b/src/bin/keys/CommandVerify.ts index 42dabed70..c8c094193 100644 --- a/src/bin/keys/CommandVerify.ts +++ b/src/bin/keys/CommandVerify.ts @@ -60,10 +60,12 @@ class CommandVerify extends CommandPolykey { }); } catch (e) { throw new binErrors.ErrorCLIFileRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } cryptoMessage.setData(data); diff --git a/src/bin/polykey-agent.ts b/src/bin/polykey-agent.ts index d92dce2d5..d56d49220 100644 --- a/src/bin/polykey-agent.ts +++ b/src/bin/polykey-agent.ts @@ -40,7 +40,7 @@ async function main(_argv = process.argv): Promise { const processSend = promisify(process.send!.bind(process)); const { p: messageInP, resolveP: resolveMessageInP } = promise(); - process.once('message', (data) => { + process.once('message', (data: AgentChildProcessInput) => { resolveMessageInP(data); }); const messageIn = await messageInP; diff --git a/src/bin/secrets/CommandCreate.ts b/src/bin/secrets/CommandCreate.ts index b0d9a7d0d..f2e2f1c3e 100644 --- a/src/bin/secrets/CommandCreate.ts +++ b/src/bin/secrets/CommandCreate.ts @@ -65,10 +65,12 @@ class CommandCreate extends CommandPolykey { content = await this.fs.promises.readFile(directoryPath); } catch (e) { throw new binErrors.ErrorCLIFileRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } secretMessage.setSecretContent(content); diff --git a/src/bin/secrets/CommandEdit.ts b/src/bin/secrets/CommandEdit.ts index f3d005810..d1ac4e36f 100644 --- a/src/bin/secrets/CommandEdit.ts +++ b/src/bin/secrets/CommandEdit.ts @@ -74,10 +74,12 @@ class CommandEdit extends CommandPolykey { content = await this.fs.promises.readFile(tmpFile); } catch (e) { throw new binErrors.ErrorCLIFileRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } secretMessage.setVault(vaultMessage); diff --git a/src/bin/secrets/CommandUpdate.ts b/src/bin/secrets/CommandUpdate.ts index 941006aed..c7fb3a6fb 100644 --- a/src/bin/secrets/CommandUpdate.ts +++ b/src/bin/secrets/CommandUpdate.ts @@ -65,10 +65,12 @@ class CommandUpdate extends CommandPolykey { content = await this.fs.promises.readFile(directoryPath); } catch (e) { throw new binErrors.ErrorCLIFileRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } secretMessage.setSecretContent(content); diff --git a/src/bin/utils/processors.ts b/src/bin/utils/processors.ts index 509134fc0..d41487173 100644 --- a/src/bin/utils/processors.ts +++ b/src/bin/utils/processors.ts @@ -89,10 +89,12 @@ async function processPassword( password = (await fs.promises.readFile(passwordFile, 'utf-8')).trim(); } catch (e) { throw new binErrors.ErrorCLIPasswordFileRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } } else if (typeof process.env['PK_PASSWORD'] === 'string') { @@ -131,10 +133,12 @@ async function processNewPassword( ).trim(); } catch (e) { throw new binErrors.ErrorCLIPasswordFileRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } } else if (!existing && typeof process.env['PK_PASSWORD'] === 'string') { @@ -167,10 +171,12 @@ async function processRecoveryCode( ).trim(); } catch (e) { throw new binErrors.ErrorCLIRecoveryCodeFileRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } } else if (typeof process.env['PK_RECOVERY_CODE'] === 'string') { @@ -372,10 +378,12 @@ async function processAuthentication( password = (await fs.promises.readFile(passwordFile, 'utf-8')).trim(); } catch (e) { throw new binErrors.ErrorCLIPasswordFileRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } meta = clientUtils.encodeAuthFromPassword(password); diff --git a/src/bootstrap/errors.ts b/src/bootstrap/errors.ts index 1e24566a2..c2e25289c 100644 --- a/src/bootstrap/errors.ts +++ b/src/bootstrap/errors.ts @@ -1,9 +1,9 @@ import { ErrorPolykey, sysexits } from '../errors'; -class ErrorBootstrap extends ErrorPolykey {} +class ErrorBootstrap extends ErrorPolykey {} -class ErrorBootstrapExistingState extends ErrorBootstrap { - description = 'Node path is occupied with existing state'; +class ErrorBootstrapExistingState extends ErrorBootstrap { + static description = 'Node path is occupied with existing state'; exitCode = sysexits.USAGE; } diff --git a/src/claims/errors.ts b/src/claims/errors.ts index 769911597..9685201f8 100644 --- a/src/claims/errors.ts +++ b/src/claims/errors.ts @@ -1,54 +1,103 @@ -import { ErrorPolykey } from '../errors'; +import { ErrorPolykey, sysexits } from '../errors'; -class ErrorClaims extends ErrorPolykey {} +class ErrorClaims extends ErrorPolykey {} -class ErrorClaimsUndefinedCanonicalizedClaim extends ErrorClaims {} +class ErrorClaimsUndefinedCanonicalizedClaim extends ErrorClaims { + static description = 'Could not canonicalize claim'; + exitCode = sysexits.UNKNOWN; +} -class ErrorClaimsUndefinedClaimPayload extends ErrorClaims {} +class ErrorClaimsUndefinedClaimPayload extends ErrorClaims { + static description = 'Missing claim payload'; + exitCode = sysexits.UNKNOWN; +} -class ErrorClaimsUndefinedSignatureHeader extends ErrorClaims {} +class ErrorClaimsUndefinedSignatureHeader extends ErrorClaims { + static description = 'Missing signature header'; + exitCode = sysexits.UNKNOWN; +} /** * Exceptions arising in cross-signing process (GRPC) */ -class ErrorCrossSign extends ErrorClaims {} +class ErrorCrossSign extends ErrorClaims {} -class ErrorEmptyStream extends ErrorCrossSign {} +class ErrorEmptyStream extends ErrorCrossSign { + static description = 'Unexpected end of stream'; + exitCode = sysexits.IOERR; +} -class ErrorUndefinedSinglySignedClaim extends ErrorCrossSign { - description: string = 'An expected singly signed claim was not received'; +class ErrorUndefinedSinglySignedClaim extends ErrorCrossSign { + static description: string = + 'An expected singly signed claim was not received'; + exitCode = sysexits.USAGE; } -class ErrorUndefinedDoublySignedClaim extends ErrorCrossSign { - description: string = 'An expected doubly signed claim was not received'; +class ErrorUndefinedDoublySignedClaim extends ErrorCrossSign { + static description: string = + 'An expected doubly signed claim was not received'; + exitCode = sysexits.USAGE; } -class ErrorUndefinedSignature extends ErrorCrossSign { - description: string = 'A received claim does not have an expected signature'; +class ErrorUndefinedSignature extends ErrorCrossSign { + static description: string = + 'A received claim does not have an expected signature'; + exitCode = sysexits.CONFIG; } -class ErrorSinglySignedClaimVerificationFailed extends ErrorCrossSign {} +class ErrorSinglySignedClaimVerificationFailed extends ErrorCrossSign { + static description = 'Unable to verify intermediary claim'; + exitCode = sysexits.CONFIG; +} -class ErrorDoublySignedClaimVerificationFailed extends ErrorCrossSign {} +class ErrorDoublySignedClaimVerificationFailed extends ErrorCrossSign { + static description = 'Unable to verify claim'; + exitCode = sysexits.CONFIG; +} /** * Exceptions arising during schema validation */ -class ErrorSchemaValidate extends ErrorClaims {} +class ErrorSchemaValidate extends ErrorClaims {} -class ErrorClaimValidationFailed extends ErrorSchemaValidate {} +class ErrorClaimValidationFailed extends ErrorSchemaValidate { + static description = 'Claim data does not match schema'; + exitCode = sysexits.CONFIG; +} -class ErrorNodesClaimType extends ErrorSchemaValidate {} +class ErrorNodesClaimType extends ErrorSchemaValidate { + static description = 'Invalid claim type'; + exitCode = sysexits.CONFIG; +} -class ErrorIdentitiesClaimType extends ErrorSchemaValidate {} +class ErrorIdentitiesClaimType extends ErrorSchemaValidate { + static description = 'Invalid claim type'; + exitCode = sysexits.CONFIG; +} -class ErrorSinglySignedClaimNumSignatures extends ErrorSchemaValidate {} +class ErrorSinglySignedClaimNumSignatures extends ErrorSchemaValidate { + static description = 'Claim is not signed or has more than one signature'; + exitCode = sysexits.CONFIG; +} -class ErrorDoublySignedClaimNumSignatures extends ErrorSchemaValidate {} +class ErrorDoublySignedClaimNumSignatures extends ErrorSchemaValidate { + static description = 'Claim is not signed or does not have two signatures'; + exitCode = sysexits.CONFIG; +} -class ErrorSinglySignedClaimValidationFailed extends ErrorSchemaValidate {} +class ErrorSinglySignedClaimValidationFailed< + T, +> extends ErrorSchemaValidate { + static description = 'Claim data does not match schema'; + exitCode = sysexits.CONFIG; +} -class ErrorDoublySignedClaimValidationFailed extends ErrorSchemaValidate {} +class ErrorDoublySignedClaimValidationFailed< + T, +> extends ErrorSchemaValidate { + static description = 'Claim data does not match schema'; + exitCode = sysexits.CONFIG; +} export { ErrorClaims, diff --git a/src/client/errors.ts b/src/client/errors.ts index 246ddb084..13baa73b0 100644 --- a/src/client/errors.ts +++ b/src/client/errors.ts @@ -1,24 +1,24 @@ import { ErrorPolykey, sysexits } from '../errors'; -class ErrorClient extends ErrorPolykey {} +class ErrorClient extends ErrorPolykey {} -class ErrorClientClientDestroyed extends ErrorClient { - description = 'GRPCClientClient has been destroyed'; +class ErrorClientClientDestroyed extends ErrorClient { + static description = 'GRPCClientClient has been destroyed'; exitCode = sysexits.USAGE; } -class ErrorClientAuthMissing extends ErrorClient { - description = 'Authorisation metadata is required but missing'; +class ErrorClientAuthMissing extends ErrorClient { + static description = 'Authorisation metadata is required but missing'; exitCode = sysexits.NOPERM; } -class ErrorClientAuthFormat extends ErrorClient { - description = 'Authorisation metadata has invalid format'; +class ErrorClientAuthFormat extends ErrorClient { + static description = 'Authorisation metadata has invalid format'; exitCode = sysexits.USAGE; } -class ErrorClientAuthDenied extends ErrorClient { - description = 'Authorisation metadata is incorrect or expired'; +class ErrorClientAuthDenied extends ErrorClient { + static description = 'Authorisation metadata is incorrect or expired'; exitCode = sysexits.NOPERM; } diff --git a/src/discovery/errors.ts b/src/discovery/errors.ts index cadf81048..ca83bfd18 100644 --- a/src/discovery/errors.ts +++ b/src/discovery/errors.ts @@ -1,12 +1,21 @@ -import { ErrorPolykey } from '../errors'; +import { ErrorPolykey, sysexits } from '../errors'; -class ErrorDiscovery extends ErrorPolykey {} +class ErrorDiscovery extends ErrorPolykey {} -class ErrorDiscoveryRunning extends ErrorDiscovery {} +class ErrorDiscoveryRunning extends ErrorDiscovery { + static description = 'Discovery is running'; + exitCode = sysexits.USAGE; +} -class ErrorDiscoveryDestroyed extends ErrorDiscovery {} +class ErrorDiscoveryDestroyed extends ErrorDiscovery { + static description = 'Discovery is destroyed'; + exitCode = sysexits.USAGE; +} -class ErrorDiscoveryNotRunning extends ErrorDiscovery {} +class ErrorDiscoveryNotRunning extends ErrorDiscovery { + static description = 'Discovery is not running'; + exitCode = sysexits.USAGE; +} export { ErrorDiscovery, diff --git a/src/errors.ts b/src/errors.ts index 1d224575e..10d662ed3 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,26 +1,44 @@ import ErrorPolykey from './ErrorPolykey'; import sysexits from './utils/sysexits'; -class ErrorPolykeyUnimplemented extends ErrorPolykey { - description = 'This is an unimplemented functionality'; +class ErrorPolykeyUnimplemented extends ErrorPolykey { + static description = 'This is an unimplemented functionality'; exitCode = sysexits.UNAVAILABLE; } -class ErrorPolykeyAgentRunning extends ErrorPolykey {} +class ErrorPolykeyAgentRunning extends ErrorPolykey { + static description = 'PolykeyAgent is running'; + exitCode = sysexits.USAGE; +} -class ErrorPolykeyAgentNotRunning extends ErrorPolykey {} +class ErrorPolykeyAgentNotRunning extends ErrorPolykey { + static description = 'PolykeyAgent is not running'; + exitCode = sysexits.USAGE; +} -class ErrorPolykeyAgentDestroyed extends ErrorPolykey {} +class ErrorPolykeyAgentDestroyed extends ErrorPolykey { + static description = 'PolykeyAgent is destroyed'; + exitCode = sysexits.USAGE; +} -class ErrorPolykeyClientRunning extends ErrorPolykey {} +class ErrorPolykeyClientRunning extends ErrorPolykey { + static description = 'PolykeyClient is running'; + exitCode = sysexits.USAGE; +} -class ErrorPolykeyClientNotRunning extends ErrorPolykey {} +class ErrorPolykeyClientNotRunning extends ErrorPolykey { + static description = 'PolykeyClient is not running'; + exitCode = sysexits.USAGE; +} -class ErrorPolykeyClientDestroyed extends ErrorPolykey {} +class ErrorPolykeyClientDestroyed extends ErrorPolykey { + static description = 'PolykeyClient is destroyed'; + exitCode = sysexits.USAGE; +} -class ErrorInvalidId extends ErrorPolykey {} +class ErrorInvalidId extends ErrorPolykey {} -class ErrorInvalidConfigEnvironment extends ErrorPolykey {} +class ErrorInvalidConfigEnvironment extends ErrorPolykey {} export { sysexits, diff --git a/src/gestalts/errors.ts b/src/gestalts/errors.ts index b44eb0af6..ed11e46e1 100644 --- a/src/gestalts/errors.ts +++ b/src/gestalts/errors.ts @@ -1,16 +1,31 @@ -import { ErrorPolykey } from '../errors'; +import { ErrorPolykey, sysexits } from '../errors'; -class ErrorGestalts extends ErrorPolykey {} +class ErrorGestalts extends ErrorPolykey {} -class ErrorGestaltsGraphRunning extends ErrorGestalts {} +class ErrorGestaltsGraphRunning extends ErrorGestalts { + static description = 'GestaltGraph is running'; + exitCode = sysexits.USAGE; +} -class ErrorGestaltsGraphNotRunning extends ErrorGestalts {} +class ErrorGestaltsGraphNotRunning extends ErrorGestalts { + static description = 'GestaltGraph is not running'; + exitCode = sysexits.USAGE; +} -class ErrorGestaltsGraphDestroyed extends ErrorGestalts {} +class ErrorGestaltsGraphDestroyed extends ErrorGestalts { + static description = 'GestaltGraph is destroyed'; + exitCode = sysexits.USAGE; +} -class ErrorGestaltsGraphNodeIdMissing extends ErrorGestalts {} +class ErrorGestaltsGraphNodeIdMissing extends ErrorGestalts { + static description = 'Could not find NodeId'; + exitCode = sysexits.NOUSER; +} -class ErrorGestaltsGraphIdentityIdMissing extends ErrorGestalts {} +class ErrorGestaltsGraphIdentityIdMissing extends ErrorGestalts { + static description = 'Could not find IdentityId'; + exitCode = sysexits.NOUSER; +} export { ErrorGestalts, diff --git a/src/git/errors.ts b/src/git/errors.ts index 7995b7aeb..e2f265e32 100644 --- a/src/git/errors.ts +++ b/src/git/errors.ts @@ -1,18 +1,30 @@ -import { ErrorPolykey } from '../errors'; +import { ErrorPolykey, sysexits } from '../errors'; -class ErrorGit extends ErrorPolykey {} +class ErrorGit extends ErrorPolykey {} -class ErrorRepositoryUndefined extends ErrorGit {} +class ErrorRepositoryUndefined extends ErrorGit {} -class ErrorGitPermissionDenied extends ErrorGit {} +class ErrorGitPermissionDenied extends ErrorGit {} -class ErrorGitUndefinedRefs extends ErrorGit {} +class ErrorGitUndefinedRefs extends ErrorGit { + static description = 'Invalid ref'; + exitCode = sysexits.UNKNOWN; +} -class ErrorGitUndefinedType extends ErrorGit {} +class ErrorGitUndefinedType extends ErrorGit { + static description = 'Invalid data type'; + exitCode = sysexits.CONFIG; +} -class ErrorGitReadObject extends ErrorGit {} +class ErrorGitReadObject extends ErrorGit { + static description = 'Failed to read object'; + exitCode = sysexits.IOERR; +} -class ErrorGitUnimplementedMethod extends ErrorGit {} +class ErrorGitUnimplementedMethod extends ErrorGit { + static description = 'Invalid request'; + exitCode = sysexits.USAGE; +} export { ErrorGit, diff --git a/src/grpc/errors.ts b/src/grpc/errors.ts index ccac769e3..023dffdc3 100644 --- a/src/grpc/errors.ts +++ b/src/grpc/errors.ts @@ -1,32 +1,51 @@ -import { ErrorPolykey } from '../errors'; +import { ErrorPolykey, sysexits } from '../errors'; -class ErrorGRPC extends ErrorPolykey {} +class ErrorGRPC extends ErrorPolykey {} -class ErrorGRPCClientTimeout extends ErrorGRPC { - description = 'Client connection timed out'; +class ErrorGRPCClientTimeout extends ErrorGRPC { + static description = 'Client connection timed out'; + exitCode = sysexits.UNAVAILABLE; } -class ErrorGRPCClientVerification extends ErrorGRPC { - description = 'Client could not verify server certificate'; +class ErrorGRPCClientVerification extends ErrorGRPC { + static description = 'Client could not verify server certificate'; + exitCode = sysexits.UNAVAILABLE; } -class ErrorGRPCClientChannelNotReady extends ErrorGRPC { - description = 'Client channel or subchannel is not ready'; +class ErrorGRPCClientChannelNotReady extends ErrorGRPC { + static description = 'Client channel or subchannel is not ready'; + exitCode = sysexits.UNAVAILABLE; } -class ErrorGRPCClientCall extends ErrorGRPC { - description = 'Generic call error'; +class ErrorGRPCClientCall extends ErrorGRPC { + static description = 'Generic call error'; + exitCode = sysexits.UNAVAILABLE; } -class ErrorGRPCServerNotRunning extends ErrorGRPC {} +class ErrorGRPCServerNotRunning extends ErrorGRPC { + static description = 'GRPC Server is not running'; + exitCode = sysexits.USAGE; +} -class ErrorGRPCServerBind extends ErrorGRPC {} +class ErrorGRPCServerBind extends ErrorGRPC { + static description = 'Could not bind to server'; + exitCode = sysexits.UNAVAILABLE; +} -class ErrorGRPCServerShutdown extends ErrorGRPC {} +class ErrorGRPCServerShutdown extends ErrorGRPC { + static description = 'Error during shutdown'; + exitCode = sysexits.UNAVAILABLE; +} -class ErrorGRPCServerNotSecured extends ErrorGRPC {} +class ErrorGRPCServerNotSecured extends ErrorGRPC { + static description = 'Server is not secured'; + exitCode = sysexits.NOPERM; +} -class ErrorGRPCServerVerification extends ErrorGRPC {} +class ErrorGRPCServerVerification extends ErrorGRPC { + static description = 'Failed to verify server certificate'; + exitCode = sysexits.UNAVAILABLE; +} export { ErrorGRPC, diff --git a/src/grpc/utils/utils.ts b/src/grpc/utils/utils.ts index 7b28d4c38..0a223c1a9 100644 --- a/src/grpc/utils/utils.ts +++ b/src/grpc/utils/utils.ts @@ -168,7 +168,7 @@ function fromError(error: Error): ServerStatusResponse { } metadata.set('name', error.name); metadata.set('message', error.message); - metadata.set('data', JSON.stringify((error as errors.ErrorPolykey).data)); + metadata.set('data', JSON.stringify((error as errors.ErrorPolykey).data)); return { metadata, }; @@ -178,7 +178,7 @@ function fromError(error: Error): ServerStatusResponse { * Deserialized GRPC errors into ErrorPolykey * Use this on the receiving side to receive exceptions */ -function toError(e: ServiceError): errors.ErrorPolykey { +function toError(e: ServiceError): errors.ErrorPolykey { const errorName = e.metadata.get('name')[0] as string; const errorMessage = e.metadata.get('message')[0] as string; const errorData = e.metadata.get('data')[0] as string; @@ -197,12 +197,14 @@ function toError(e: ServiceError): errors.ErrorPolykey { errorData != null && errorName in errors ) { - return new errors[errorName](errorMessage, JSON.parse(errorData)); + return new errors[errorName](errorMessage, { data: JSON.parse(errorData) }); } else { - return new grpcErrors.ErrorGRPCClientCall(e.message, { - code: e.code, - details: e.details, - metadata: e.metadata.getMap(), + return new grpcErrors.ErrorGRPCClientCall(e.message, { + data: { + code: e.code, + details: e.details, + metadata: e.metadata.getMap(), + }, }); } } diff --git a/src/identities/errors.ts b/src/identities/errors.ts index 0effd2306..dece95ffc 100644 --- a/src/identities/errors.ts +++ b/src/identities/errors.ts @@ -1,24 +1,51 @@ -import { ErrorPolykey } from '../errors'; - -class ErrorIdentities extends ErrorPolykey {} - -class ErrorIdentitiesManagerRunning extends ErrorIdentities {} - -class ErrorIdentitiesManagerNotRunning extends ErrorIdentities {} - -class ErrorIdentitiesManagerDestroyed extends ErrorIdentities {} - -class ErrorProviderDuplicate extends ErrorIdentities {} - -class ErrorProviderCall extends ErrorIdentities {} - -class ErrorProviderAuthentication extends ErrorIdentities {} - -class ErrorProviderUnauthenticated extends ErrorIdentities {} - -class ErrorProviderUnimplemented extends ErrorIdentities {} - -class ErrorProviderMissing extends ErrorIdentities {} +import { ErrorPolykey, sysexits } from '../errors'; + +class ErrorIdentities extends ErrorPolykey {} + +class ErrorIdentitiesManagerRunning extends ErrorIdentities { + static description = 'IdentitiesManager is running'; + exitCode = sysexits.USAGE; +} + +class ErrorIdentitiesManagerNotRunning extends ErrorIdentities { + static description = 'IdentitiesManager is not running'; + exitCode = sysexits.USAGE; +} + +class ErrorIdentitiesManagerDestroyed extends ErrorIdentities { + static description = 'IdentitiesManager is destroyed'; + exitCode = sysexits.USAGE; +} + +class ErrorProviderDuplicate extends ErrorIdentities { + static description = 'Provider has already been registered'; + exitCode = sysexits.USAGE; +} + +class ErrorProviderCall extends ErrorIdentities { + static description = 'Invalid response received from provider'; + exitCode = sysexits.UNAVAILABLE; +} + +class ErrorProviderAuthentication extends ErrorIdentities { + static description = 'Could not authenticate provider'; + exitCode = sysexits.UNKNOWN; +} + +class ErrorProviderUnauthenticated extends ErrorIdentities { + static description = 'Provider has not been authenticated or access token is expired or invalid'; + exitCode = sysexits.NOPERM; +} + +class ErrorProviderUnimplemented extends ErrorIdentities { + static description = 'Functionality is unavailable'; + exitCode = sysexits.USAGE; +} + +class ErrorProviderMissing extends ErrorIdentities { + static description = 'Provider has not been registered'; + exitCode = sysexits.USAGE; +} export { ErrorIdentities, diff --git a/src/keys/KeyManager.ts b/src/keys/KeyManager.ts index 8addec87c..22d1a4329 100644 --- a/src/keys/KeyManager.ts +++ b/src/keys/KeyManager.ts @@ -269,10 +269,12 @@ class KeyManager { }); } catch (e) { throw new keysErrors.ErrorRootKeysRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } try { @@ -414,10 +416,12 @@ class KeyManager { ); } catch (e) { throw new keysErrors.ErrorRootCertRenew(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } await this.garbageCollectRootCerts(); @@ -535,10 +539,12 @@ class KeyManager { } } catch (e) { throw new keysErrors.ErrorRootCertsGC(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } } @@ -630,10 +636,12 @@ class KeyManager { return false; } throw new keysErrors.ErrorRootKeysRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } return true; @@ -649,10 +657,12 @@ class KeyManager { ]); } catch (e) { throw new keysErrors.ErrorRootKeysRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } let keyPair; @@ -693,10 +703,12 @@ class KeyManager { ]); } catch (e) { throw new keysErrors.ErrorRootKeysWrite(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } } @@ -717,10 +729,12 @@ class KeyManager { }); } catch (e) { throw new keysErrors.ErrorRootKeysRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } const rootKeyPairBits = keysUtils.publicKeyBitSize( @@ -764,10 +778,12 @@ class KeyManager { return false; } throw new keysErrors.ErrorDBKeyRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } return true; @@ -780,10 +796,12 @@ class KeyManager { keysDbKeyCipher = await this.fs.promises.readFile(keyPath); } catch (e) { throw new keysErrors.ErrorDBKeyRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } let keysDbKeyPlain; @@ -814,10 +832,12 @@ class KeyManager { await this.fs.promises.rename(`${keyPath}.tmp`, keyPath); } catch (e) { throw new keysErrors.ErrorDBKeyWrite(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } } @@ -855,10 +875,12 @@ class KeyManager { return false; } throw new keysErrors.ErrorRootCertRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } return true; @@ -873,10 +895,12 @@ class KeyManager { }); } catch (e) { throw new keysErrors.ErrorRootCertRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } const rootCert = keysUtils.certFromPem(rootCertPem); @@ -894,10 +918,12 @@ class KeyManager { ); } catch (e) { throw new keysErrors.ErrorRootCertWrite(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } } @@ -913,10 +939,12 @@ class KeyManager { rootCertsNames = await this.fs.promises.readdir(this.rootCertsPath); } catch (e) { throw new keysErrors.ErrorRootCertRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } rootCertsNames.sort((a, b) => { @@ -950,10 +978,12 @@ class KeyManager { ); } catch (e) { throw new keysErrors.ErrorRootCertRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } return rootCertsPems; diff --git a/src/keys/errors.ts b/src/keys/errors.ts index e239f3a4b..59863b617 100644 --- a/src/keys/errors.ts +++ b/src/keys/errors.ts @@ -1,50 +1,92 @@ import { ErrorPolykey, sysexits } from '../errors'; -class ErrorKeys extends ErrorPolykey {} +class ErrorKeys extends ErrorPolykey {} -class ErrorKeyManagerRunning extends ErrorKeys {} +class ErrorKeyManagerRunning extends ErrorKeys { + static description = 'KeyManager is running'; + exitCode = sysexits.USAGE; +} -class ErrorKeyManagerNotRunning extends ErrorKeys {} +class ErrorKeyManagerNotRunning extends ErrorKeys { + static description = 'KeyManager is not running'; + exitCode = sysexits.USAGE; +} -class ErrorKeyManagerDestroyed extends ErrorKeys {} +class ErrorKeyManagerDestroyed extends ErrorKeys { + static description = 'KeyManager is destroyed'; + exitCode = sysexits.USAGE; +} -class ErrorKeysPasswordInvalid extends ErrorKeys { - description = 'Password has invalid format'; +class ErrorKeysPasswordInvalid extends ErrorKeys { + static description = 'Password has invalid format'; exitCode = sysexits.USAGE; } -class ErrorKeysRecoveryCodeInvalid extends ErrorKeys { - description = 'Recovery code has invalid format'; +class ErrorKeysRecoveryCodeInvalid extends ErrorKeys { + static description = 'Recovery code has invalid format'; exitCode = sysexits.USAGE; } -class ErrorKeysRecoveryCodeIncorrect extends ErrorKeys { - description = +class ErrorKeysRecoveryCodeIncorrect extends ErrorKeys { + static description = "Recovered key pair's public key does not match the root public key"; exitCode = sysexits.USAGE; } -class ErrorRootKeysRead extends ErrorKeys {} +class ErrorRootKeysRead extends ErrorKeys { + static description = 'Unable to read root keypair'; + exitCode = sysexits.IOERR; +} -class ErrorRootKeysParse extends ErrorKeys {} +class ErrorRootKeysParse extends ErrorKeys { + static description = 'Unable to parse root keypair'; + exitCode = sysexits.IOERR; +} -class ErrorRootKeysWrite extends ErrorKeys {} +class ErrorRootKeysWrite extends ErrorKeys { + static description = 'Unable to write root keypair'; + exitCode = sysexits.IOERR; +} -class ErrorRootCertRead extends ErrorKeys {} +class ErrorRootCertRead extends ErrorKeys { + static description = 'Unable to read root certificate'; + exitCode = sysexits.IOERR; +} -class ErrorRootCertWrite extends ErrorKeys {} +class ErrorRootCertWrite extends ErrorKeys { + static description = 'Unable to write root certificate'; + exitCode = sysexits.IOERR; +} -class ErrorRootCertRenew extends ErrorKeys {} +class ErrorRootCertRenew extends ErrorKeys { + static description = 'Unable to renew root certificate'; + exitCode = sysexits.IOERR; +} -class ErrorRootCertsGC extends ErrorKeys {} +class ErrorRootCertsGC extends ErrorKeys { + static description = 'Unexpected error during garbage collection'; + exitCode = sysexits.IOERR; +} -class ErrorEncryptSize extends ErrorKeys {} +class ErrorEncryptSize extends ErrorKeys { + static description = 'Cannot encrypt data with key bit size'; + exitCode = sysexits.USAGE; +} -class ErrorDBKeyRead extends ErrorKeys {} +class ErrorDBKeyRead extends ErrorKeys { + static description = 'Unable to read key'; + exitCode = sysexits.IOERR; +} -class ErrorDBKeyWrite extends ErrorKeys {} +class ErrorDBKeyWrite extends ErrorKeys { + static description = 'Unable to write key'; + exitCode = sysexits.IOERR; +} -class ErrorDBKeyParse extends ErrorKeys {} +class ErrorDBKeyParse extends ErrorKeys { + static description = 'Unable to decrypt key'; + exitCode = sysexits.IOERR; +} export { ErrorKeys, diff --git a/src/locks/Locks.ts b/src/locks/Locks.ts index a91ad1807..2434d30dd 100644 --- a/src/locks/Locks.ts +++ b/src/locks/Locks.ts @@ -1,5 +1,5 @@ import type { ResourceAcquire, ResourceRelease } from '@matrixai/resources'; -import type { NonEmptyArray } from '@/types'; +import type { NonEmptyArray } from '../types'; import { RWLockWriter } from '@matrixai/async-locks'; /** @@ -18,7 +18,9 @@ class Locks { * The ids will be sorted before locking to ensure lock-hierarchy * in order to prevent deadlocks */ - public lockRead(...ids: NonEmptyArray): ResourceAcquire> { + public lockRead( + ...ids: NonEmptyArray + ): ResourceAcquire> { return async () => { ids.sort(); const locks: Array<[string, ResourceRelease, RWLockWriter]> = []; @@ -55,7 +57,7 @@ class Locks { } } }, - locks.map(([,,lock]) => lock) as NonEmptyArray + locks.map(([, , lock]) => lock) as NonEmptyArray, ]; }; } @@ -65,7 +67,9 @@ class Locks { * The ids will be sorted before locking to ensure lock-hierarchy * in order to prevent deadlocks */ - public lockWrite(...ids: NonEmptyArray): ResourceAcquire> { + public lockWrite( + ...ids: NonEmptyArray + ): ResourceAcquire> { return async () => { ids.sort(); const locks: Array<[string, ResourceRelease, RWLockWriter]> = []; @@ -102,7 +106,7 @@ class Locks { } } }, - locks.map(([,,lock]) => lock) as NonEmptyArray + locks.map(([, , lock]) => lock) as NonEmptyArray, ]; }; } diff --git a/src/network/ConnectionForward.ts b/src/network/ConnectionForward.ts index c41238a92..b28d95f2f 100644 --- a/src/network/ConnectionForward.ts +++ b/src/network/ConnectionForward.ts @@ -165,9 +165,11 @@ class ConnectionForward extends Connection { } this.utpSocket.off('message', this.handleMessage); throw new networkErrors.ErrorConnectionStart(e.message, { - code: e.code, - errno: e.errno, - syscall: e.syscall, + data: { + code: e.code, + errno: e.errno, + syscall: e.syscall, + }, }); } finally { clearInterval(punchInterval); diff --git a/src/network/ConnectionReverse.ts b/src/network/ConnectionReverse.ts index a746454bf..265bdaa4a 100644 --- a/src/network/ConnectionReverse.ts +++ b/src/network/ConnectionReverse.ts @@ -157,9 +157,11 @@ class ConnectionReverse extends Connection { this.serverSocket.destroy(); this.utpSocket.off('message', this.handleMessage); throw new networkErrors.ErrorConnectionStart(e.message, { - code: e.code, - errno: e.errno, - syscall: e.syscall, + data: { + code: e.code, + errno: e.errno, + syscall: e.syscall, + }, }); } finally { clearInterval(punchInterval); @@ -247,9 +249,11 @@ class ConnectionReverse extends Connection { tlsSocket.destroy(); } throw new networkErrors.ErrorConnectionCompose(e.message, { - code: e.code, - errno: e.errno, - syscall: e.syscall, + data: { + code: e.code, + errno: e.errno, + syscall: e.syscall, + }, }); } tlsSocket.on('error', async (e) => { diff --git a/src/network/errors.ts b/src/network/errors.ts index 234f90a22..e8189010c 100644 --- a/src/network/errors.ts +++ b/src/network/errors.ts @@ -1,128 +1,132 @@ import { ErrorPolykey, sysexits } from '../errors'; -class ErrorNetwork extends ErrorPolykey {} +class ErrorNetwork extends ErrorPolykey {} -class ErrorProxy extends ErrorNetwork {} +class ErrorProxy extends ErrorNetwork {} -class ErrorProxyNotRunning extends ErrorProxy { - description = 'Proxy is not running'; +class ErrorProxyNotRunning extends ErrorProxy { + static description = 'Proxy is not running'; exitCode = sysexits.USAGE; } -class ErrorProxyConnectInvalidUrl extends ErrorProxy { - description = 'Invalid target host used for HTTP connect proxy'; +class ErrorProxyConnectInvalidUrl extends ErrorProxy { + static description = 'Invalid target host used for HTTP connect proxy'; exitCode = sysexits.PROTOCOL; } -class ErrorProxyConnectMissingNodeId extends ErrorProxy { - description = 'Node ID query parameter is required for HTTP connect proxy'; +class ErrorProxyConnectMissingNodeId extends ErrorProxy { + static description = + 'Node ID query parameter is required for HTTP connect proxy'; exitCode = sysexits.PROTOCOL; } -class ErrorProxyConnectAuth extends ErrorProxy { - description = 'Incorrect HTTP connect proxy password'; +class ErrorProxyConnectAuth extends ErrorProxy { + static description = 'Incorrect HTTP connect proxy password'; exitCode = sysexits.NOPERM; } -class ErrorConnection extends ErrorNetwork {} +class ErrorConnection extends ErrorNetwork {} -class ErrorConnectionNotRunning extends ErrorConnection { - description = 'Connection is not running'; +class ErrorConnectionNotRunning extends ErrorConnection { + static description = 'Connection is not running'; exitCode = sysexits.USAGE; } -class ErrorConnectionComposed extends ErrorConnection { - description = 'Connection is composed'; +class ErrorConnectionComposed extends ErrorConnection { + static description = 'Connection is composed'; exitCode = sysexits.USAGE; } -class ErrorConnectionNotComposed extends ErrorConnection { - description = 'Connection is not composed'; +class ErrorConnectionNotComposed extends ErrorConnection { + static description = 'Connection is not composed'; exitCode = sysexits.USAGE; } -class ErrorConnectionMessageParse extends ErrorConnection { - description = 'Network message received is invalid'; +class ErrorConnectionMessageParse extends ErrorConnection { + static description = 'Network message received is invalid'; exitCode = sysexits.TEMPFAIL; } -class ErrorConnectionTimeout extends ErrorConnection { - description = 'Connection keep-alive timed out'; +class ErrorConnectionTimeout extends ErrorConnection { + static description = 'Connection keep-alive timed out'; exitCode = sysexits.UNAVAILABLE; } -class ErrorConnectionEndTimeout extends ErrorConnection { - description = 'Connection end timed out'; +class ErrorConnectionEndTimeout extends ErrorConnection { + static description = 'Connection end timed out'; exitCode = sysexits.UNAVAILABLE; } /** * Used by ConnectionForward and ConnectionReverse */ -class ErrorConnectionStart extends ErrorConnection { - description = 'Connection start failed'; +class ErrorConnectionStart extends ErrorConnection { + static description = 'Connection start failed'; exitCode = sysexits.PROTOCOL; } -class ErrorConnectionStartTimeout extends ErrorConnectionStart { - description = 'Connection start timed out'; +class ErrorConnectionStartTimeout extends ErrorConnectionStart { + static description = 'Connection start timed out'; exitCode = sysexits.NOHOST; } /** * Used by ConnectionReverse */ -class ErrorConnectionCompose extends ErrorConnection { - description = 'Connection compose failed'; +class ErrorConnectionCompose extends ErrorConnection { + static description = 'Connection compose failed'; exitCode = sysexits.PROTOCOL; } -class ErrorConnectionComposeTimeout extends ErrorConnectionCompose { - description = 'Connection compose timed out'; +class ErrorConnectionComposeTimeout extends ErrorConnectionCompose { + static description = 'Connection compose timed out'; exitCode = sysexits.NOHOST; } /** * Used for certificate verification */ -class ErrorCertChain extends ErrorNetwork {} +class ErrorCertChain extends ErrorNetwork {} -class ErrorCertChainEmpty extends ErrorCertChain { - description = 'Certificate chain is empty'; +class ErrorCertChainEmpty extends ErrorCertChain { + static description = 'Certificate chain is empty'; exitCode = sysexits.PROTOCOL; } -class ErrorCertChainUnclaimed extends ErrorCertChain { - description = 'The target node id is not claimed by any certificate'; +class ErrorCertChainUnclaimed extends ErrorCertChain { + static description = 'The target node id is not claimed by any certificate'; exitCode = sysexits.PROTOCOL; } -class ErrorCertChainBroken extends ErrorCertChain { - description = 'The signature chain is broken'; +class ErrorCertChainBroken extends ErrorCertChain { + static description = 'The signature chain is broken'; exitCode = sysexits.PROTOCOL; } -class ErrorCertChainDateInvalid extends ErrorCertChain { - description = 'Certificate in the chain is expired'; +class ErrorCertChainDateInvalid extends ErrorCertChain { + static description = 'Certificate in the chain is expired'; exitCode = sysexits.PROTOCOL; } -class ErrorCertChainNameInvalid extends ErrorCertChain { - description = 'Certificate is missing the common name'; +class ErrorCertChainNameInvalid extends ErrorCertChain { + static description = 'Certificate is missing the common name'; exitCode = sysexits.PROTOCOL; } -class ErrorCertChainKeyInvalid extends ErrorCertChain { - description = 'Certificate public key does not generate the Node ID'; +class ErrorCertChainKeyInvalid extends ErrorCertChain { + static description = 'Certificate public key does not generate the Node ID'; exitCode = sysexits.PROTOCOL; } -class ErrorCertChainSignatureInvalid extends ErrorCertChain { - description = 'Certificate self-signed signature is invalid'; +class ErrorCertChainSignatureInvalid extends ErrorCertChain { + static description = 'Certificate self-signed signature is invalid'; exitCode = sysexits.PROTOCOL; } -class ErrorHostnameResolutionFailed extends ErrorNetwork {} +class ErrorHostnameResolutionFailed extends ErrorNetwork { + static description = 'Unable to resolve hostname'; + exitCode = sysexits.USAGE; +} export { ErrorNetwork, diff --git a/src/network/utils.ts b/src/network/utils.ts index 8347da631..08dab06ff 100644 --- a/src/network/utils.ts +++ b/src/network/utils.ts @@ -201,11 +201,13 @@ function verifyServerCertificateChain( throw new networkErrors.ErrorCertChainDateInvalid( 'Chain certificate date is invalid', { - cert, - certIndex, - notBefore: cert.validity.notBefore, - notAfter: cert.validity.notAfter, - now, + data: { + cert, + certIndex, + notBefore: cert.validity.notBefore, + notAfter: cert.validity.notAfter, + now, + }, }, ); } @@ -214,8 +216,10 @@ function verifyServerCertificateChain( throw new networkErrors.ErrorCertChainNameInvalid( 'Chain certificate common name attribute is missing', { - cert, - certIndex, + data: { + cert, + certIndex, + }, }, ); } @@ -224,10 +228,12 @@ function verifyServerCertificateChain( throw new networkErrors.ErrorCertChainKeyInvalid( 'Chain certificate public key does not generate its node id', { - cert, - certIndex, - nodeId: certNodeId, - commonName: commonName.value, + data: { + cert, + certIndex, + nodeId: certNodeId, + commonName: commonName.value, + }, }, ); } @@ -235,8 +241,10 @@ function verifyServerCertificateChain( throw new networkErrors.ErrorCertChainSignatureInvalid( 'Chain certificate does not have a valid node-signature', { - cert, - certIndex, + data: { + cert, + certIndex, + }, }, ); } @@ -251,7 +259,7 @@ function verifyServerCertificateChain( throw new networkErrors.ErrorCertChainUnclaimed( 'Node ID is not claimed by any certificate', { - nodeId, + data: { nodeId }, }, ); } @@ -268,9 +276,11 @@ function verifyServerCertificateChain( throw new networkErrors.ErrorCertChainBroken( 'Chain certificate is not signed by parent certificate', { - cert: certChild, - certIndex: certIndex - 1, - certParent, + data: { + cert: certChild, + certIndex: certIndex - 1, + certParent, + }, }, ); } @@ -296,11 +306,13 @@ function verifyClientCertificateChain(certChain: Array): void { throw new networkErrors.ErrorCertChainDateInvalid( 'Chain certificate date is invalid', { - cert, - certIndex, - notBefore: cert.validity.notBefore, - notAfter: cert.validity.notAfter, - now, + data: { + cert, + certIndex, + notBefore: cert.validity.notBefore, + notAfter: cert.validity.notAfter, + now, + }, }, ); } @@ -309,8 +321,10 @@ function verifyClientCertificateChain(certChain: Array): void { throw new networkErrors.ErrorCertChainNameInvalid( 'Chain certificate common name attribute is missing', { - cert, - certIndex, + data: { + cert, + certIndex, + }, }, ); } @@ -319,10 +333,12 @@ function verifyClientCertificateChain(certChain: Array): void { throw new networkErrors.ErrorCertChainKeyInvalid( 'Chain certificate public key does not generate its node id', { - cert, - certIndex, - nodeId: certNodeId, - commonName: commonName.value, + data: { + cert, + certIndex, + nodeId: certNodeId, + commonName: commonName.value, + }, }, ); } @@ -330,8 +346,10 @@ function verifyClientCertificateChain(certChain: Array): void { throw new networkErrors.ErrorCertChainSignatureInvalid( 'Chain certificate does not have a valid node-signature', { - cert, - certIndex, + data: { + cert, + certIndex, + }, }, ); } @@ -343,9 +361,11 @@ function verifyClientCertificateChain(certChain: Array): void { throw new networkErrors.ErrorCertChainSignatureInvalid( 'Chain certificate is not signed by parent certificate', { - cert, - certIndex, - certParent: certNext, + data: { + cert, + certIndex, + certParent: certNext, + }, }, ); } diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 5338e0058..b7c68dfa9 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -15,6 +15,8 @@ import Logger from '@matrixai/logger'; import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; import { IdInternal } from '@matrixai/id'; import { status } from '@matrixai/async-init'; +import { withF } from '@matrixai/resources'; +import { RWLockWriter } from '@matrixai/async-locks'; import NodeConnection from './NodeConnection'; import * as nodesUtils from './utils'; import * as nodesErrors from './errors'; @@ -24,8 +26,6 @@ import * as networkUtils from '../network/utils'; import * as agentErrors from '../agent/errors'; import * as grpcErrors from '../grpc/errors'; import * as nodesPB from '../proto/js/polykey/v1/nodes/nodes_pb'; -import { withF } from '@matrixai/resources'; -import { RWLockWriter } from '@matrixai/async-locks'; type ConnectionAndLock = { connection?: NodeConnection; diff --git a/src/nodes/errors.ts b/src/nodes/errors.ts index a7074ae41..1c491bde4 100644 --- a/src/nodes/errors.ts +++ b/src/nodes/errors.ts @@ -1,69 +1,69 @@ import { ErrorPolykey, sysexits } from '../errors'; -class ErrorNodes extends ErrorPolykey {} +class ErrorNodes extends ErrorPolykey {} -class ErrorNodeGraphRunning extends ErrorNodes { - description = 'NodeGraph is running'; +class ErrorNodeGraphRunning extends ErrorNodes { + static description = 'NodeGraph is running'; exitCode = sysexits.USAGE; } -class ErrorNodeGraphNotRunning extends ErrorNodes { - description = 'NodeGraph is not running'; +class ErrorNodeGraphNotRunning extends ErrorNodes { + static description = 'NodeGraph is not running'; exitCode = sysexits.USAGE; } -class ErrorNodeGraphDestroyed extends ErrorNodes { - description = 'NodeGraph is destroyed'; +class ErrorNodeGraphDestroyed extends ErrorNodes { + static description = 'NodeGraph is destroyed'; exitCode = sysexits.USAGE; } -class ErrorNodeGraphNodeIdNotFound extends ErrorNodes { - description = 'Could not find NodeId'; +class ErrorNodeGraphNodeIdNotFound extends ErrorNodes { + static description = 'Could not find NodeId'; exitCode = sysexits.NOUSER; } -class ErrorNodeGraphEmptyDatabase extends ErrorNodes { - description = 'NodeGraph database was empty'; +class ErrorNodeGraphEmptyDatabase extends ErrorNodes { + static description = 'NodeGraph database was empty'; exitCode = sysexits.USAGE; } -class ErrorNodeGraphOversizedBucket extends ErrorNodes { - description: 'Bucket invalidly contains more nodes than capacity'; +class ErrorNodeGraphOversizedBucket extends ErrorNodes { + static description: 'Bucket invalidly contains more nodes than capacity'; exitCode = sysexits.USAGE; } -class ErrorNodeGraphSameNodeId extends ErrorNodes { - description: 'NodeId must be different for valid bucket calculation'; +class ErrorNodeGraphSameNodeId extends ErrorNodes { + static description: 'NodeId must be different for valid bucket calculation'; exitCode = sysexits.USAGE; } -class ErrorNodeConnectionDestroyed extends ErrorNodes { - description = 'NodeConnection is destroyed'; +class ErrorNodeConnectionDestroyed extends ErrorNodes { + static description = 'NodeConnection is destroyed'; exitCode = sysexits.USAGE; } -class ErrorNodeConnectionTimeout extends ErrorNodes { - description: 'A node connection could not be established (timed out)'; +class ErrorNodeConnectionTimeout extends ErrorNodes { + static description: 'A node connection could not be established (timed out)'; exitCode = sysexits.UNAVAILABLE; } -class ErrorNodeConnectionInfoNotExist extends ErrorNodes { - description: 'NodeConnection info was not found'; +class ErrorNodeConnectionInfoNotExist extends ErrorNodes { + static description: 'NodeConnection info was not found'; exitCode = sysexits.UNAVAILABLE; } -class ErrorNodeConnectionPublicKeyNotFound extends ErrorNodes { - description: 'Public key was not found'; +class ErrorNodeConnectionPublicKeyNotFound extends ErrorNodes { + static description: 'Public key was not found'; exitCode = sysexits.UNAVAILABLE; } -class ErrorNodeConnectionManagerNotRunning extends ErrorNodes { - description = 'NodeConnectionManager is not running'; +class ErrorNodeConnectionManagerNotRunning extends ErrorNodes { + static description = 'NodeConnectionManager is not running'; exitCode = sysexits.USAGE; } -class ErrorNodeConnectionHostWildcard extends ErrorNodes { - description = 'An IP wildcard was provided for the target host'; +class ErrorNodeConnectionHostWildcard extends ErrorNodes { + static description = 'An IP wildcard was provided for the target host'; exitCode = sysexits.USAGE; } diff --git a/src/notifications/errors.ts b/src/notifications/errors.ts index 5d6f68493..3a9ca102f 100644 --- a/src/notifications/errors.ts +++ b/src/notifications/errors.ts @@ -1,39 +1,71 @@ -import { ErrorPolykey } from '../errors'; +import { ErrorPolykey, sysexits } from '../errors'; -class ErrorNotifications extends ErrorPolykey {} +class ErrorNotifications extends ErrorPolykey {} -class ErrorNotificationsUnknownNode extends ErrorNotifications {} +class ErrorNotificationsRunning extends ErrorNotifications { + static description = 'NotiticationsManager is running'; + exitCode = sysexits.USAGE; +} -class ErrorNotificationsRunning extends ErrorNotifications {} +class ErrorNotificationsNotRunning extends ErrorNotifications { + static description = 'NotiticationsManager is not running'; + exitCode = sysexits.USAGE; +} -class ErrorNotificationsNotRunning extends ErrorNotifications {} +class ErrorNotificationsDestroyed extends ErrorNotifications { + static description = 'NotiticationsManager is destroyed'; + exitCode = sysexits.USAGE; +} -class ErrorNotificationsDestroyed extends ErrorNotifications {} +class ErrorNotificationsPermissionsNotFound extends ErrorNotifications { + static description = 'Could not find permissions for NodeId'; + exitCode = sysexits.NOUSER; +} -class ErrorNotificationsPermissionsNotFound extends ErrorNotifications {} +class ErrorNotificationsDb extends ErrorNotifications { + static description = 'Database consistency error'; + exitCode = sysexits.IOERR; +} -class ErrorNotificationsDb extends ErrorNotifications {} - -class ErrorNotificationsParse extends ErrorNotifications {} +class ErrorNotificationsParse extends ErrorNotifications { + static description = 'Unable to verify notification'; + exitCode = sysexits.IOERR; +} /** * Exceptions raised when validating a Notification against a JSON schema */ -class ErrorSchemaValidate extends ErrorNotifications {} +class ErrorSchemaValidate extends ErrorNotifications {} -class ErrorNotificationsInvalidType extends ErrorSchemaValidate {} +class ErrorNotificationsInvalidType extends ErrorSchemaValidate { + static description = 'Invalid notification type'; + exitCode = sysexits.USAGE; +} -class ErrorNotificationsGeneralInvalid extends ErrorSchemaValidate {} +class ErrorNotificationsGeneralInvalid extends ErrorSchemaValidate { + static description = 'Invalid notification data'; + exitCode = sysexits.USAGE; +} -class ErrorNotificationsGestaltInviteInvalid extends ErrorSchemaValidate {} +class ErrorNotificationsGestaltInviteInvalid< + T, +> extends ErrorSchemaValidate { + static description = 'Invalid notification data'; + exitCode = sysexits.USAGE; +} -class ErrorNotificationsVaultShareInvalid extends ErrorSchemaValidate {} +class ErrorNotificationsVaultShareInvalid extends ErrorSchemaValidate { + static description = 'Invalid notification data'; + exitCode = sysexits.USAGE; +} -class ErrorNotificationsValidationFailed extends ErrorSchemaValidate {} +class ErrorNotificationsValidationFailed extends ErrorSchemaValidate { + static description = 'Notification does not match schema'; + exitCode = sysexits.USAGE; +} export { ErrorNotifications, - ErrorNotificationsUnknownNode, ErrorNotificationsRunning, ErrorNotificationsNotRunning, ErrorNotificationsDestroyed, diff --git a/src/schema/Schema.ts b/src/schema/Schema.ts index 33c50fa45..9c107acff 100644 --- a/src/schema/Schema.ts +++ b/src/schema/Schema.ts @@ -82,10 +82,12 @@ class Schema { }); } catch (e) { throw new schemaErrors.ErrorSchemaStateDelete(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } } @@ -93,10 +95,12 @@ class Schema { await utils.mkdirExists(this.fs, this.statePath); } catch (e) { throw new schemaErrors.ErrorSchemaStateCreate(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } const stateVersion = await this.readVersion(); @@ -126,10 +130,12 @@ class Schema { }); } catch (e) { throw new schemaErrors.ErrorSchemaStateDelete(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } this.logger.info(`Destroyed ${this.constructor.name}`); @@ -148,10 +154,12 @@ class Schema { return; } throw new schemaErrors.ErrorSchemaVersionRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } const stateVersion = parseInt(stateVersionData.trim()); @@ -172,10 +180,12 @@ class Schema { ); } catch (e) { throw new schemaErrors.ErrorSchemaVersionWrite(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } }); diff --git a/src/schema/errors.ts b/src/schema/errors.ts index ee5b8b01b..973961386 100644 --- a/src/schema/errors.ts +++ b/src/schema/errors.ts @@ -1,30 +1,60 @@ -import { ErrorPolykey } from '../errors'; +import { ErrorPolykey, sysexits } from '../errors'; -class ErrorSchema extends ErrorPolykey {} +class ErrorSchema extends ErrorPolykey {} -class ErrorSchemaRunning extends ErrorSchema {} +class ErrorSchemaRunning extends ErrorSchema { + static description = 'Schema is running'; + exitCode = sysexits.USAGE; +} -class ErrorSchemaNotRunning extends ErrorSchema {} +class ErrorSchemaNotRunning extends ErrorSchema { + static description = 'Schema is not running'; + exitCode = sysexits.USAGE; +} -class ErrorSchemaDestroyed extends ErrorSchema {} +class ErrorSchemaDestroyed extends ErrorSchema { + static description = 'Schema is destroyed'; + exitCode = sysexits.USAGE; +} -class ErrorSchemaStateCreate extends ErrorSchema {} +class ErrorSchemaStateCreate extends ErrorSchema { + static description = 'Unable to create schema state'; + exitCode = sysexits.IOERR; +} -class ErrorSchemaStateDelete extends ErrorSchema {} +class ErrorSchemaStateDelete extends ErrorSchema { + static description = 'Unable to delete schema state'; + exitCode = sysexits.IOERR; +} -class ErrorSchemaVersionRead extends ErrorSchema {} +class ErrorSchemaVersionRead extends ErrorSchema { + static description = 'Unable to read schema version'; + exitCode = sysexits.IOERR; +} -class ErrorSchemaVersionParse extends ErrorSchema {} +class ErrorSchemaVersionParse extends ErrorSchema { + static description = 'Invalid schema version'; + exitCode = sysexits.IOERR; +} -class ErrorSchemaVersionWrite extends ErrorSchema {} +class ErrorSchemaVersionWrite extends ErrorSchema { + static description = 'Unable to write schema version'; + exitCode = sysexits.IOERR; +} -class ErrorSchemaVersionTooNew extends ErrorSchema {} +class ErrorSchemaVersionTooNew extends ErrorSchema { + static description = 'Invalid state version'; + exitCode = sysexits.USAGE; +} -class ErrorSchemaVersionTooOld extends ErrorSchema {} +class ErrorSchemaVersionTooOld extends ErrorSchema { + static description = 'Unable to upgrade schema version'; + exitCode = sysexits.USAGE; +} -class ErrorSchemaMigrationFail extends ErrorSchema {} +class ErrorSchemaMigrationFail extends ErrorSchema {} -class ErrorSchemaMigrationMissing extends ErrorSchema {} +class ErrorSchemaMigrationMissing extends ErrorSchema {} export { ErrorSchema, diff --git a/src/sessions/errors.ts b/src/sessions/errors.ts index 837020898..588ff9036 100644 --- a/src/sessions/errors.ts +++ b/src/sessions/errors.ts @@ -1,18 +1,36 @@ -import { ErrorPolykey } from '../errors'; - -class ErrorSessions extends ErrorPolykey {} - -class ErrorSessionRunning extends ErrorSessions {} - -class ErrorSessionNotRunning extends ErrorSessions {} - -class ErrorSessionDestroyed extends ErrorSessions {} - -class ErrorSessionManagerRunning extends ErrorSessions {} - -class ErrorSessionManagerNotRunning extends ErrorSessions {} - -class ErrorSessionManagerDestroyed extends ErrorSessions {} +import { ErrorPolykey, sysexits } from '../errors'; + +class ErrorSessions extends ErrorPolykey {} + +class ErrorSessionRunning extends ErrorSessions { + static description = 'Session is running'; + exitCode = sysexits.USAGE; +} + +class ErrorSessionNotRunning extends ErrorSessions { + static description = 'Session is not running'; + exitCode = sysexits.USAGE; +} + +class ErrorSessionDestroyed extends ErrorSessions { + static description = 'Session is destroyed'; + exitCode = sysexits.USAGE; +} + +class ErrorSessionManagerRunning extends ErrorSessions { + static description = 'SessionManager is running'; + exitCode = sysexits.USAGE; +} + +class ErrorSessionManagerNotRunning extends ErrorSessions { + static description = 'SessionManager is not running'; + exitCode = sysexits.USAGE; +} + +class ErrorSessionManagerDestroyed extends ErrorSessions { + static description = 'SessionManager is destroyed'; + exitCode = sysexits.USAGE; +} export { ErrorSessions, diff --git a/src/sigchain/errors.ts b/src/sigchain/errors.ts index 254c7fef6..0d839c490 100644 --- a/src/sigchain/errors.ts +++ b/src/sigchain/errors.ts @@ -1,26 +1,45 @@ -import { ErrorPolykey } from '../errors'; +import { ErrorPolykey, sysexits } from '../errors'; -class ErrorSigchain extends ErrorPolykey {} +class ErrorSigchain extends ErrorPolykey {} -class ErrorSigchainRunning extends ErrorSigchain {} +class ErrorSigchainRunning extends ErrorSigchain { + static description = 'Sigchain is running'; + exitCode = sysexits.USAGE; +} -class ErrorSigchainNotRunning extends ErrorSigchain {} +class ErrorSigchainNotRunning extends ErrorSigchain { + static description = 'Sigchain is not running'; + exitCode = sysexits.USAGE; +} -class ErrorSigchainDestroyed extends ErrorSigchain {} +class ErrorSigchainDestroyed extends ErrorSigchain { + static description = 'Sigchain is destroyed'; + exitCode = sysexits.USAGE; +} -class ErrorSigchainSequenceNumUndefined extends ErrorSigchain {} +class ErrorSigchainSequenceNumUndefined extends ErrorSigchain { + static description = 'Invalid database state'; + exitCode = sysexits.IOERR; +} -class ErrorSigchainClaimUndefined extends ErrorSigchain {} +class ErrorSigchainClaimUndefined extends ErrorSigchain { + static description = 'Could not retrieve claim'; + exitCode = sysexits.USAGE; +} -class ErrorSigchainInvalidSequenceNum extends ErrorSigchain {} +class ErrorSigchainInvalidSequenceNum extends ErrorSigchain { + static description = 'Claim has invalid sequence number'; + exitCode = sysexits.USAGE; +} -class ErrorSigchainInvalidHash extends ErrorSigchain {} +class ErrorSigchainInvalidHash extends ErrorSigchain { + static description = 'Claim has invalid hash'; + exitCode = sysexits.USAGE; +} -class ErrorSighainClaimVerificationFailed extends ErrorSigchain {} +class ErrorSigchainDecrypt extends ErrorSigchain {} -class ErrorSigchainDecrypt extends ErrorSigchain {} - -class ErrorSigchainParse extends ErrorSigchain {} +class ErrorSigchainParse extends ErrorSigchain {} export { ErrorSigchainRunning, @@ -30,7 +49,6 @@ export { ErrorSigchainClaimUndefined, ErrorSigchainInvalidSequenceNum, ErrorSigchainInvalidHash, - ErrorSighainClaimVerificationFailed, ErrorSigchainDecrypt, ErrorSigchainParse, }; diff --git a/src/status/Status.ts b/src/status/Status.ts index 4569f1ed9..5a248ba9f 100644 --- a/src/status/Status.ts +++ b/src/status/Status.ts @@ -112,10 +112,12 @@ class Status { return; } throw new statusErrors.ErrorStatusRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } while (!lock(statusFile.fd)) { @@ -126,10 +128,12 @@ class Status { statusData = (await statusFile.readFile('utf-8')).trim(); } catch (e) { throw new statusErrors.ErrorStatusRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } if (statusData === '') { @@ -145,7 +149,7 @@ class Status { throw new statusErrors.ErrorStatusParse( 'StatusInfo validation failed', { - errors: statusUtils.statusValidate.errors, + data: { errors: statusUtils.statusValidate.errors }, }, ); } @@ -182,10 +186,12 @@ class Status { ); } catch (e) { throw new statusErrors.ErrorStatusWrite(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } } finally { @@ -207,10 +213,12 @@ class Status { statusFile = await this.fs.promises.open(this.statusPath, 'r+'); } catch (e) { throw new statusErrors.ErrorStatusRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } while (!lock(statusFile.fd)) { @@ -221,10 +229,12 @@ class Status { statusData = (await statusFile.readFile('utf-8')).trim(); } catch (e) { throw new statusErrors.ErrorStatusRead(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } let statusInfo; @@ -237,7 +247,7 @@ class Status { throw new statusErrors.ErrorStatusParse( 'StatusInfo validation failed', { - errors: statusUtils.statusValidate.errors, + data: { errors: statusUtils.statusValidate.errors }, }, ); } @@ -256,10 +266,12 @@ class Status { ); } catch (e) { throw new statusErrors.ErrorStatusWrite(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } return statusInfo; diff --git a/src/status/errors.ts b/src/status/errors.ts index 22a2bea08..a56192557 100644 --- a/src/status/errors.ts +++ b/src/status/errors.ts @@ -1,36 +1,39 @@ import { ErrorPolykey, sysexits } from '../errors'; -class ErrorStatus extends ErrorPolykey {} +class ErrorStatus extends ErrorPolykey {} -class ErrorStatusNotRunning extends ErrorStatus {} +class ErrorStatusNotRunning extends ErrorStatus { + static description = 'Status is not running'; + exitCode = sysexits.USAGE; +} -class ErrorStatusLocked extends ErrorStatus { - description = 'Status is locked by another process'; +class ErrorStatusLocked extends ErrorStatus { + static description = 'Status is locked by another process'; exitCode = sysexits.TEMPFAIL; } -class ErrorStatusRead extends ErrorStatus { - description = 'Failed to read status info'; +class ErrorStatusRead extends ErrorStatus { + static description = 'Failed to read status info'; exitCode = sysexits.IOERR; } -class ErrorStatusWrite extends ErrorStatus { - description = 'Failed to write status info'; +class ErrorStatusWrite extends ErrorStatus { + static description = 'Failed to write status info'; exitCode = sysexits.IOERR; } -class ErrorStatusLiveUpdate extends ErrorStatus { - description = 'Failed to update LIVE status info'; +class ErrorStatusLiveUpdate extends ErrorStatus { + static description = 'Failed to update LIVE status info'; exitCode = sysexits.USAGE; } -class ErrorStatusParse extends ErrorStatus { - description = 'Failed to parse status info'; +class ErrorStatusParse extends ErrorStatus { + static description = 'Failed to parse status info'; exitCode = sysexits.CONFIG; } -class ErrorStatusTimeout extends ErrorStatus { - description = 'Poll timed out'; +class ErrorStatusTimeout extends ErrorStatus { + static description = 'Poll timed out'; exitCode = sysexits.TEMPFAIL; } diff --git a/src/utils/errors.ts b/src/utils/errors.ts index af54ffa86..23ea67744 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -1,25 +1,25 @@ import sysexits from './sysexits'; import ErrorPolykey from '../ErrorPolykey'; -class ErrorUtils extends ErrorPolykey {} +class ErrorUtils extends ErrorPolykey {} /** * This is a special error that is only used for absurd situations * Intended to placate typescript so that unreachable code type checks * If this is thrown, this means there is a bug in the code */ -class ErrorUtilsUndefinedBehaviour extends ErrorUtils { - description = 'You should never see this error'; +class ErrorUtilsUndefinedBehaviour extends ErrorUtils { + static description = 'You should never see this error'; exitCode = sysexits.SOFTWARE; } -class ErrorUtilsPollTimeout extends ErrorUtils { - description = 'Poll timed out'; +class ErrorUtilsPollTimeout extends ErrorUtils { + static description = 'Poll timed out'; exitCode = sysexits.TEMPFAIL; } -class ErrorUtilsNodePath extends ErrorUtils { - description = 'Cannot derive default node path from unknown platform'; +class ErrorUtilsNodePath extends ErrorUtils { + static description = 'Cannot derive default node path from unknown platform'; exitCode = sysexits.USAGE; } diff --git a/src/validation/errors.ts b/src/validation/errors.ts index e918ce38b..f6267ba51 100644 --- a/src/validation/errors.ts +++ b/src/validation/errors.ts @@ -1,20 +1,20 @@ -import { CustomError } from 'ts-custom-error'; +import { AbstractError } from '@matrixai/errors'; import { ErrorPolykey, sysexits } from '../errors'; /** * Generic error containing all parsing errors that occurred during * execution. */ -class ErrorValidation extends ErrorPolykey { - description = 'Input data failed validation'; +class ErrorValidation extends ErrorPolykey { + static description = 'Input data failed validation'; exitCode = sysexits.DATAERR; - public errors: Array; + public errors: Array>; constructor(message, data) { super(message, data); if (data.errors != null) { - const errors: Array = []; + const errors: Array> = []; for (const eData of data.errors) { - const errorParse = new ErrorParse(eData.message); + const errorParse = new ErrorParse(eData.message); errorParse.keyPath = eData.keyPath; errorParse.value = eData.value; errorParse.context = eData.context; @@ -28,7 +28,7 @@ class ErrorValidation extends ErrorPolykey { * This packages an `ErrorParse` array into the `data` property * This is to allow encoding to and decoding from GRPC errors */ - static createFromErrors(errors: Array): ErrorValidation { + static createFromErrors(errors: Array>): ErrorValidation { const message = errors.map((e) => e.message).join('; '); const data = { errors: errors.map((e) => ({ @@ -38,7 +38,7 @@ class ErrorValidation extends ErrorPolykey { context: e.context, })), }; - const e = new ErrorValidation(message, data); + const e = new ErrorValidation(message, data); e.errors = errors; return e; } @@ -51,13 +51,12 @@ class ErrorValidation extends ErrorPolykey { * While JS allows us to throw POJOs directly, having a nominal type * is easier to check against */ -class ErrorParse extends CustomError { +class ErrorParse extends AbstractError { + static description: string = 'Failed to parse data into valid format'; + exitCode = sysexits.DATAERR; public keyPath: Array; public value: any; public context: object; - constructor(message?: string) { - super(message); - } } export { ErrorValidation, ErrorParse }; diff --git a/src/vaults/VaultManager.ts b/src/vaults/VaultManager.ts index 71699d1ae..13f57b5e4 100644 --- a/src/vaults/VaultManager.ts +++ b/src/vaults/VaultManager.ts @@ -199,10 +199,12 @@ class VaultManager { throw new vaultsErrors.ErrorVaultManagerKey(); } throw new vaultsErrors.ErrorVaultManagerEFS(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } this.vaultsDb = vaultsDb; @@ -934,10 +936,12 @@ class VaultManager { return false; } throw new vaultsErrors.ErrorVaultManagerEFS(e.message, { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, }); } } diff --git a/src/vaults/errors.ts b/src/vaults/errors.ts index 43e877caf..f8db78e31 100644 --- a/src/vaults/errors.ts +++ b/src/vaults/errors.ts @@ -1,113 +1,114 @@ import { ErrorPolykey, sysexits } from '../errors'; -class ErrorVaults extends ErrorPolykey {} +class ErrorVaults extends ErrorPolykey {} -class ErrorVaultManagerRunning extends ErrorVaults { - description = 'VaultManager is running'; +class ErrorVaultManagerRunning extends ErrorVaults { + static description = 'VaultManager is running'; exitCode = sysexits.USAGE; } -class ErrorVaultManagerNotRunning extends ErrorVaults { - description = 'VaultManager is not running'; +class ErrorVaultManagerNotRunning extends ErrorVaults { + static description = 'VaultManager is not running'; exitCode = sysexits.USAGE; } -class ErrorVaultManagerDestroyed extends ErrorVaults { - description = 'VaultManager is destroyed'; +class ErrorVaultManagerDestroyed extends ErrorVaults { + static description = 'VaultManager is destroyed'; exitCode = sysexits.USAGE; } -class ErrorVaultManagerKey extends ErrorVaults { - description = 'Vault key is invalid'; +class ErrorVaultManagerKey extends ErrorVaults { + static description = 'Vault key is invalid'; exitCode = sysexits.CONFIG; } -class ErrorVaultManagerEFS extends ErrorVaults { - description = 'EFS failed'; +class ErrorVaultManagerEFS extends ErrorVaults { + static description = 'EFS failed'; exitCode = sysexits.UNAVAILABLE; } -class ErrorVault extends ErrorVaults {} +class ErrorVault extends ErrorVaults {} -class ErrorVaultRunning extends ErrorVault { - description = 'Vault is running'; +class ErrorVaultRunning extends ErrorVault { + static description = 'Vault is running'; exitCode = sysexits.USAGE; } -class ErrorVaultNotRunning extends ErrorVault { - description = 'Vault is not running'; +class ErrorVaultNotRunning extends ErrorVault { + static description = 'Vault is not running'; exitCode = sysexits.USAGE; } -class ErrorVaultDestroyed extends ErrorVault { - description = 'Vault is destroyed'; +class ErrorVaultDestroyed extends ErrorVault { + static description = 'Vault is destroyed'; exitCode = sysexits.USAGE; } -class ErrorVaultReferenceInvalid extends ErrorVault { - description = 'Reference is invalid'; +class ErrorVaultReferenceInvalid extends ErrorVault { + static description = 'Reference is invalid'; exitCode = sysexits.USAGE; } -class ErrorVaultReferenceMissing extends ErrorVault { - description = 'Reference does not exist'; +class ErrorVaultReferenceMissing extends ErrorVault { + static description = 'Reference does not exist'; exitCode = sysexits.USAGE; } -class ErrorVaultRemoteDefined extends ErrorVaults { - description = 'Vault is a clone of a remote vault and can not be mutated'; +class ErrorVaultRemoteDefined extends ErrorVaults { + static description = + 'Vault is a clone of a remote vault and can not be mutated'; exitCode = sysexits.USAGE; } -class ErrorVaultRemoteUndefined extends ErrorVaults { - description = 'Vault has no remote set and can not be pulled'; +class ErrorVaultRemoteUndefined extends ErrorVaults { + static description = 'Vault has no remote set and can not be pulled'; exitCode = sysexits.USAGE; } -class ErrorVaultsVaultUndefined extends ErrorVaults { - description = 'Vault does not exist'; +class ErrorVaultsVaultUndefined extends ErrorVaults { + static description = 'Vault does not exist'; exitCode = sysexits.USAGE; } -class ErrorVaultsVaultDefined extends ErrorVaults { - description = 'Vault already exists'; +class ErrorVaultsVaultDefined extends ErrorVaults { + static description = 'Vault already exists'; exitCode = sysexits.USAGE; } -class ErrorVaultsRecursive extends ErrorVaults { - description = 'Recursive option was not set'; +class ErrorVaultsRecursive extends ErrorVaults { + static description = 'Recursive option was not set'; exitCode = sysexits.USAGE; } -class ErrorVaultsCreateVaultId extends ErrorVaults { - description = 'Failed to create unique VaultId'; +class ErrorVaultsCreateVaultId extends ErrorVaults { + static description = 'Failed to create unique VaultId'; exitCode = sysexits.SOFTWARE; } -class ErrorVaultsMergeConflict extends ErrorVaults { - description = 'Merge Conflicts are not supported yet'; +class ErrorVaultsMergeConflict extends ErrorVaults { + static description = 'Merge Conflicts are not supported yet'; exitCode = sysexits.SOFTWARE; } -class ErrorVaultsPermissionDenied extends ErrorVaults { - description = 'Permission was denied'; +class ErrorVaultsPermissionDenied extends ErrorVaults { + static description = 'Permission was denied'; exitCode = sysexits.NOPERM; } -class ErrorVaultsNameConflict extends ErrorVaults { - description = 'Unique name could not be created'; +class ErrorVaultsNameConflict extends ErrorVaults { + static description = 'Unique name could not be created'; exitCode = sysexits.UNAVAILABLE; } -class ErrorSecrets extends ErrorPolykey {} +class ErrorSecrets extends ErrorPolykey {} -class ErrorSecretsSecretUndefined extends ErrorSecrets { - description = 'Secret does not exist'; +class ErrorSecretsSecretUndefined extends ErrorSecrets { + static description = 'Secret does not exist'; exitCode = sysexits.USAGE; } -class ErrorSecretsSecretDefined extends ErrorSecrets { - description = 'Secret already exists'; +class ErrorSecretsSecretDefined extends ErrorSecrets { + static description = 'Secret already exists'; exitCode = sysexits.USAGE; } From 1d2af00699c1c43556b2f7930b7cabb276d8f2d3 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 27 Apr 2022 11:28:59 +1000 Subject: [PATCH 005/137] feat: using `cause` property to establish error chain When any error is thrown as the result of another error occurring, the original error is now contained within the `cause` property of the new error. #304 --- src/bin/keys/CommandDecrypt.ts | 1 + src/bin/keys/CommandEncrypt.ts | 1 + src/bin/keys/CommandSign.ts | 1 + src/bin/keys/CommandVerify.ts | 1 + src/bin/nodes/CommandPing.ts | 2 +- src/bin/secrets/CommandCreate.ts | 1 + src/bin/secrets/CommandEdit.ts | 1 + src/bin/secrets/CommandUpdate.ts | 1 + src/bin/utils/processors.ts | 4 ++++ src/grpc/GRPCClient.ts | 8 +++++--- src/grpc/GRPCServer.ts | 10 ++++++---- .../providers/github/GitHubProvider.ts | 8 +++++++- src/keys/KeyManager.ts | 19 +++++++++++++++++-- src/network/ConnectionForward.ts | 1 + src/network/ConnectionReverse.ts | 2 ++ src/network/utils.ts | 2 +- src/nodes/NodeConnection.ts | 2 +- src/notifications/utils.ts | 2 +- src/schema/Schema.ts | 5 +++++ src/status/Status.ts | 12 +++++++++--- src/validation/utils.ts | 2 ++ src/vaults/VaultInternal.ts | 4 ++-- src/vaults/VaultManager.ts | 4 +++- src/vaults/VaultOps.ts | 3 +++ 24 files changed, 77 insertions(+), 20 deletions(-) diff --git a/src/bin/keys/CommandDecrypt.ts b/src/bin/keys/CommandDecrypt.ts index c45691596..aeb4a5191 100644 --- a/src/bin/keys/CommandDecrypt.ts +++ b/src/bin/keys/CommandDecrypt.ts @@ -58,6 +58,7 @@ class CommandDecrypt extends CommandPolykey { code: e.code, path: e.path, }, + cause: e, }); } cryptoMessage.setData(cipherText); diff --git a/src/bin/keys/CommandEncrypt.ts b/src/bin/keys/CommandEncrypt.ts index 3d8ddc601..2edef5b08 100644 --- a/src/bin/keys/CommandEncrypt.ts +++ b/src/bin/keys/CommandEncrypt.ts @@ -58,6 +58,7 @@ class CommandEncypt extends CommandPolykey { code: e.code, path: e.path, }, + cause: e, }); } cryptoMessage.setData(plainText); diff --git a/src/bin/keys/CommandSign.ts b/src/bin/keys/CommandSign.ts index e69007eb6..4d31dee5f 100644 --- a/src/bin/keys/CommandSign.ts +++ b/src/bin/keys/CommandSign.ts @@ -58,6 +58,7 @@ class CommandSign extends CommandPolykey { code: e.code, path: e.path, }, + cause: e, }); } cryptoMessage.setData(data); diff --git a/src/bin/keys/CommandVerify.ts b/src/bin/keys/CommandVerify.ts index c8c094193..7c0a5de49 100644 --- a/src/bin/keys/CommandVerify.ts +++ b/src/bin/keys/CommandVerify.ts @@ -66,6 +66,7 @@ class CommandVerify extends CommandPolykey { code: e.code, path: e.path, }, + cause: e, }); } cryptoMessage.setData(data); diff --git a/src/bin/nodes/CommandPing.ts b/src/bin/nodes/CommandPing.ts index b22e0d19d..11913011a 100644 --- a/src/bin/nodes/CommandPing.ts +++ b/src/bin/nodes/CommandPing.ts @@ -59,7 +59,7 @@ class CommandPing extends CommandPolykey { error = new binErrors.ErrorNodePingFailed( `Failed to resolve node ID ${nodesUtils.encodeNodeId( nodeId, - )} to an address.`, + )} to an address.`, { cause: err }, ); } else { throw err; diff --git a/src/bin/secrets/CommandCreate.ts b/src/bin/secrets/CommandCreate.ts index f2e2f1c3e..26f22cbbe 100644 --- a/src/bin/secrets/CommandCreate.ts +++ b/src/bin/secrets/CommandCreate.ts @@ -71,6 +71,7 @@ class CommandCreate extends CommandPolykey { code: e.code, path: e.path, }, + cause: e, }); } secretMessage.setSecretContent(content); diff --git a/src/bin/secrets/CommandEdit.ts b/src/bin/secrets/CommandEdit.ts index d1ac4e36f..f86b37499 100644 --- a/src/bin/secrets/CommandEdit.ts +++ b/src/bin/secrets/CommandEdit.ts @@ -80,6 +80,7 @@ class CommandEdit extends CommandPolykey { code: e.code, path: e.path, }, + cause: e, }); } secretMessage.setVault(vaultMessage); diff --git a/src/bin/secrets/CommandUpdate.ts b/src/bin/secrets/CommandUpdate.ts index c7fb3a6fb..c7b9e696d 100644 --- a/src/bin/secrets/CommandUpdate.ts +++ b/src/bin/secrets/CommandUpdate.ts @@ -71,6 +71,7 @@ class CommandUpdate extends CommandPolykey { code: e.code, path: e.path, }, + cause: e, }); } secretMessage.setSecretContent(content); diff --git a/src/bin/utils/processors.ts b/src/bin/utils/processors.ts index d41487173..df43437d0 100644 --- a/src/bin/utils/processors.ts +++ b/src/bin/utils/processors.ts @@ -95,6 +95,7 @@ async function processPassword( code: e.code, path: e.path, }, + cause: e, }); } } else if (typeof process.env['PK_PASSWORD'] === 'string') { @@ -139,6 +140,7 @@ async function processNewPassword( code: e.code, path: e.path, }, + cause: e, }); } } else if (!existing && typeof process.env['PK_PASSWORD'] === 'string') { @@ -177,6 +179,7 @@ async function processRecoveryCode( code: e.code, path: e.path, }, + cause: e, }); } } else if (typeof process.env['PK_RECOVERY_CODE'] === 'string') { @@ -384,6 +387,7 @@ async function processAuthentication( code: e.code, path: e.path, }, + cause: e, }); } meta = clientUtils.encodeAuthFromPassword(password); diff --git a/src/grpc/GRPCClient.ts b/src/grpc/GRPCClient.ts index b55d3a275..b705e9aa5 100644 --- a/src/grpc/GRPCClient.ts +++ b/src/grpc/GRPCClient.ts @@ -129,7 +129,7 @@ abstract class GRPCClient { } catch (e) { // If we fail here then we leak the client object... client.close(); - throw new grpcErrors.ErrorGRPCClientTimeout(); + throw new grpcErrors.ErrorGRPCClientTimeout(e.message, { cause: e }); } let serverCertChain: Array | undefined; if (channelCredentials._isSecure()) { @@ -151,8 +151,10 @@ abstract class GRPCClient { `Failed GRPC server certificate verification connecting to ${address}`, ); const e_ = new grpcErrors.ErrorGRPCClientVerification( - `${e.name}: ${e.message}`, - e.data, + `${e.name}: ${e.message}`,{ + data: e.data, + cause: e, + }, ); session.destroy(e_, http2.constants.NGHTTP2_PROTOCOL_ERROR); } diff --git a/src/grpc/GRPCServer.ts b/src/grpc/GRPCServer.ts index 7d6ab3d35..2c7edf11b 100644 --- a/src/grpc/GRPCServer.ts +++ b/src/grpc/GRPCServer.ts @@ -70,7 +70,7 @@ class GRPCServer { try { this.port = await bindAsync(address, serverCredentials); } catch (e) { - throw new grpcErrors.ErrorGRPCServerBind(e.message); + throw new grpcErrors.ErrorGRPCServerBind(e.message, { cause: e }); } if (serverCredentials._isSecure()) { // @ts-ignore hack for private property @@ -100,8 +100,10 @@ class GRPCServer { `Failed GRPC client certificate verification connecting from ${address}`, ); const e_ = new grpcErrors.ErrorGRPCServerVerification( - `${e.name}: ${e.message}`, - e.data, + `${e.name}: ${e.message}`, { + data: e.data, + cause: e, + }, ); session.destroy(e_, http2.constants.NGHTTP2_PROTOCOL_ERROR); } else { @@ -140,7 +142,7 @@ class GRPCServer { ...(timer != null ? [timer.timerP] : []), ]); } catch (e) { - throw new grpcErrors.ErrorGRPCServerShutdown(e.message); + throw new grpcErrors.ErrorGRPCServerShutdown(e.message, { cause: e }); } finally { if (timer != null) timerStop(timer); } diff --git a/src/identities/providers/github/GitHubProvider.ts b/src/identities/providers/github/GitHubProvider.ts index 4dc939999..122122931 100644 --- a/src/identities/providers/github/GitHubProvider.ts +++ b/src/identities/providers/github/GitHubProvider.ts @@ -120,7 +120,7 @@ class GitHubProvider extends Provider { data = await response.json(); } catch (e) { throw new identitiesErrors.ErrorProviderAuthentication( - 'Provider access token response is not valid JSON', + 'Provider access token response is not valid JSON', { cause: e }, ); } if (data.error) { @@ -200,6 +200,7 @@ class GitHubProvider extends Provider { } catch (e) { throw new identitiesErrors.ErrorProviderCall( `Provider response body is not valid JSON`, + { cause: e }, ); } return data.login; @@ -246,6 +247,7 @@ class GitHubProvider extends Provider { } catch (e) { throw new identitiesErrors.ErrorProviderCall( `Provider response body is not valid JSON`, + { cause: e }, ); } return { @@ -297,6 +299,7 @@ class GitHubProvider extends Provider { } catch (e) { throw new identitiesErrors.ErrorProviderCall( `Provider response body is not valid JSON`, + { cause: e }, ); } for (const item of data) { @@ -343,6 +346,7 @@ class GitHubProvider extends Provider { } catch (e) { throw new identitiesErrors.ErrorProviderCall( `Provider response body is not valid JSON`, + { cause: e }, ); } for (const item of data) { @@ -414,6 +418,7 @@ class GitHubProvider extends Provider { } catch (e) { throw new identitiesErrors.ErrorProviderCall( `Provider response body is not valid JSON`, + { cause: e }, ); } return { @@ -466,6 +471,7 @@ class GitHubProvider extends Provider { } catch (e) { throw new identitiesErrors.ErrorProviderCall( `Provider response body is not valid JSON`, + { cause: e }, ); } const linkClaimData = data.files[this.gistFilename]?.content; diff --git a/src/keys/KeyManager.ts b/src/keys/KeyManager.ts index 22d1a4329..937c80d98 100644 --- a/src/keys/KeyManager.ts +++ b/src/keys/KeyManager.ts @@ -275,6 +275,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } try { @@ -422,6 +423,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } await this.garbageCollectRootCerts(); @@ -545,6 +547,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } } @@ -642,6 +645,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } return true; @@ -663,6 +667,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } let keyPair; @@ -675,7 +680,7 @@ class KeyManager { password, ); } catch (e) { - throw new keysErrors.ErrorRootKeysParse(e.message); + throw new keysErrors.ErrorRootKeysParse(e.message, { cause: e }); } return keyPair; } @@ -709,6 +714,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } } @@ -735,6 +741,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } const rootKeyPairBits = keysUtils.publicKeyBitSize( @@ -784,6 +791,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } return true; @@ -802,6 +810,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } let keysDbKeyPlain; @@ -811,7 +820,7 @@ class KeyManager { keysDbKeyCipher, ); } catch (e) { - throw new keysErrors.ErrorDBKeyParse(e.message); + throw new keysErrors.ErrorDBKeyParse(e.message, { cause: e }); } return keysDbKeyPlain; } @@ -838,6 +847,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } } @@ -881,6 +891,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } return true; @@ -901,6 +912,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } const rootCert = keysUtils.certFromPem(rootCertPem); @@ -924,6 +936,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } } @@ -945,6 +958,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } rootCertsNames.sort((a, b) => { @@ -984,6 +998,7 @@ class KeyManager { code: e.code, path: e.path, }, + cause: e, }); } return rootCertsPems; diff --git a/src/network/ConnectionForward.ts b/src/network/ConnectionForward.ts index b28d95f2f..5e8a829d4 100644 --- a/src/network/ConnectionForward.ts +++ b/src/network/ConnectionForward.ts @@ -170,6 +170,7 @@ class ConnectionForward extends Connection { errno: e.errno, syscall: e.syscall, }, + cause: e, }); } finally { clearInterval(punchInterval); diff --git a/src/network/ConnectionReverse.ts b/src/network/ConnectionReverse.ts index 265bdaa4a..ada434649 100644 --- a/src/network/ConnectionReverse.ts +++ b/src/network/ConnectionReverse.ts @@ -162,6 +162,7 @@ class ConnectionReverse extends Connection { errno: e.errno, syscall: e.syscall, }, + cause: e, }); } finally { clearInterval(punchInterval); @@ -254,6 +255,7 @@ class ConnectionReverse extends Connection { errno: e.errno, syscall: e.syscall, }, + cause: e, }); } tlsSocket.on('error', async (e) => { diff --git a/src/network/utils.ts b/src/network/utils.ts index 08dab06ff..f97f71ef9 100644 --- a/src/network/utils.ts +++ b/src/network/utils.ts @@ -101,7 +101,7 @@ async function resolveHost(host: Host | Hostname): Promise { // Resolve the hostname and get the IPv4 address resolvedHost = await lookup(host, 4); } catch (e) { - throw new networkErrors.ErrorHostnameResolutionFailed(e.message); + throw new networkErrors.ErrorHostnameResolutionFailed(e.message, { cause: e }); } // Returns an array of [ resolved address, family (4 or 6) ] return resolvedHost[0] as Host; diff --git a/src/nodes/NodeConnection.ts b/src/nodes/NodeConnection.ts index 6788c20fe..d81ac9721 100644 --- a/src/nodes/NodeConnection.ts +++ b/src/nodes/NodeConnection.ts @@ -135,7 +135,7 @@ class NodeConnection { await nodeConnection.destroy(); // If the connection times out, re-throw this with a higher level nodes exception if (e instanceof grpcErrors.ErrorGRPCClientTimeout) { - throw new nodesErrors.ErrorNodeConnectionTimeout(); + throw new nodesErrors.ErrorNodeConnectionTimeout(e.message, { cause: e }); } throw e; } diff --git a/src/notifications/utils.ts b/src/notifications/utils.ts index 08532f524..0f55a6620 100644 --- a/src/notifications/utils.ts +++ b/src/notifications/utils.ts @@ -78,7 +78,7 @@ async function verifyAndDecodeNotif(notifJWT: string): Promise { throw err; } else { // Error came from jose - throw new notificationsErrors.ErrorNotificationsParse(); + throw new notificationsErrors.ErrorNotificationsParse(err.message, { cause: err }); } } } diff --git a/src/schema/Schema.ts b/src/schema/Schema.ts index 9c107acff..b7c66be4c 100644 --- a/src/schema/Schema.ts +++ b/src/schema/Schema.ts @@ -88,6 +88,7 @@ class Schema { code: e.code, path: e.path, }, + cause: e, }); } } @@ -101,6 +102,7 @@ class Schema { code: e.code, path: e.path, }, + cause: e, }); } const stateVersion = await this.readVersion(); @@ -136,6 +138,7 @@ class Schema { code: e.code, path: e.path, }, + cause: e, }); } this.logger.info(`Destroyed ${this.constructor.name}`); @@ -160,6 +163,7 @@ class Schema { code: e.code, path: e.path, }, + cause: e, }); } const stateVersion = parseInt(stateVersionData.trim()); @@ -186,6 +190,7 @@ class Schema { code: e.code, path: e.path, }, + cause: e, }); } }); diff --git a/src/status/Status.ts b/src/status/Status.ts index 5a248ba9f..fbee3edce 100644 --- a/src/status/Status.ts +++ b/src/status/Status.ts @@ -118,6 +118,7 @@ class Status { code: e.code, path: e.path, }, + cause: e, }); } while (!lock(statusFile.fd)) { @@ -134,6 +135,7 @@ class Status { code: e.code, path: e.path, }, + cause: e, }); } if (statusData === '') { @@ -143,7 +145,7 @@ class Status { try { statusInfo = JSON.parse(statusData, this.statusReviver); } catch (e) { - throw new statusErrors.ErrorStatusParse('JSON parsing failed'); + throw new statusErrors.ErrorStatusParse('JSON parsing failed', {cause: e}); } if (!statusUtils.statusValidate(statusInfo)) { throw new statusErrors.ErrorStatusParse( @@ -192,6 +194,7 @@ class Status { code: e.code, path: e.path, }, + cause: e, }); } } finally { @@ -219,6 +222,7 @@ class Status { code: e.code, path: e.path, }, + cause: e, }); } while (!lock(statusFile.fd)) { @@ -235,13 +239,14 @@ class Status { code: e.code, path: e.path, }, + cause: e, }); } let statusInfo; try { statusInfo = JSON.parse(statusData, this.statusReviver); } catch (e) { - throw new statusErrors.ErrorStatusParse('JSON parsing failed'); + throw new statusErrors.ErrorStatusParse('JSON parsing failed', { cause: e }); } if (!statusUtils.statusValidate(statusInfo)) { throw new statusErrors.ErrorStatusParse( @@ -272,6 +277,7 @@ class Status { code: e.code, path: e.path, }, + cause: e, }); } return statusInfo; @@ -311,7 +317,7 @@ class Status { ); } catch (e) { if (e instanceof errors.ErrorUtilsPollTimeout) { - throw new errors.ErrorStatusTimeout(); + throw new errors.ErrorStatusTimeout(e.message, { cause: e }); } throw e; } diff --git a/src/validation/utils.ts b/src/validation/utils.ts index 3ce13f258..4221e1508 100644 --- a/src/validation/utils.ts +++ b/src/validation/utils.ts @@ -227,6 +227,7 @@ function parseSeedNodes(data: any): [SeedNodes, boolean] { if (e instanceof TypeError) { throw new validationErrors.ErrorParse( 'Seed nodes must be of format `nodeId@host:port;...`', + { cause: e }, ); } throw e; @@ -245,6 +246,7 @@ function parseSeedNodes(data: any): [SeedNodes, boolean] { if (e instanceof validationErrors.ErrorParse) { throw new validationErrors.ErrorParse( 'Seed nodes must be of format `nodeId@host:port;...`', + { cause: e }, ); } throw e; diff --git a/src/vaults/VaultInternal.ts b/src/vaults/VaultInternal.ts index 76f87e13b..c7f60829b 100644 --- a/src/vaults/VaultInternal.ts +++ b/src/vaults/VaultInternal.ts @@ -376,7 +376,7 @@ class VaultInternal { e instanceof git.Errors.NotFoundError || e instanceof git.Errors.CommitNotFetchedError ) { - throw new vaultsErrors.ErrorVaultReferenceMissing(); + throw new vaultsErrors.ErrorVaultReferenceMissing(e.message, { cause: e }); } throw e; } @@ -551,7 +551,7 @@ class VaultInternal { if (err instanceof git.Errors.SmartHttpError && error) { throw error; } else if (err instanceof git.Errors.MergeNotSupportedError) { - throw new vaultsErrors.ErrorVaultsMergeConflict(); + throw new vaultsErrors.ErrorVaultsMergeConflict(err.message, { cause: err }); } throw err; } diff --git a/src/vaults/VaultManager.ts b/src/vaults/VaultManager.ts index 13f57b5e4..571b8879d 100644 --- a/src/vaults/VaultManager.ts +++ b/src/vaults/VaultManager.ts @@ -196,7 +196,7 @@ class VaultManager { }); } catch (e) { if (e instanceof encryptedFsErrors.ErrorEncryptedFSKey) { - throw new vaultsErrors.ErrorVaultManagerKey(); + throw new vaultsErrors.ErrorVaultManagerKey(e.message, { cause: e }); } throw new vaultsErrors.ErrorVaultManagerEFS(e.message, { data: { @@ -205,6 +205,7 @@ class VaultManager { code: e.code, path: e.path, }, + cause: e, }); } this.vaultsDb = vaultsDb; @@ -942,6 +943,7 @@ class VaultManager { code: e.code, path: e.path, }, + cause: e, }); } } diff --git a/src/vaults/VaultOps.ts b/src/vaults/VaultOps.ts index 203bb4a4a..3de1edd1c 100644 --- a/src/vaults/VaultOps.ts +++ b/src/vaults/VaultOps.ts @@ -109,6 +109,7 @@ async function getSecret(vault: Vault, secretName: string): Promise { if (err.code === 'ENOENT') { throw new vaultsErrors.ErrorSecretsSecretUndefined( `Secret with name: ${secretName} does not exist`, + { cause: err }, ); } throw err; @@ -124,6 +125,7 @@ async function statSecret(vault: Vault, secretName: string): Promise { if (err.code === 'ENOENT') { throw new vaultsErrors.ErrorSecretsSecretUndefined( `Secret with name: ${secretName} does not exist`, + { cause: err }, ); } throw err; @@ -178,6 +180,7 @@ async function mkdir( if (err.code === 'ENOENT' && !recursive) { throw new vaultsErrors.ErrorVaultsRecursive( `Could not create directory '${dirPath}' without recursive option`, + { cause: err }, ); } } From 7ac665303da8cfa2eeff2cc59460a85bcd6b9446 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Mon, 2 May 2022 10:13:01 +1000 Subject: [PATCH 006/137] fix: validation errors are forced to use `void` as `cause` #304 --- src/validation/errors.ts | 14 +++++++------- src/validation/utils.ts | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/validation/errors.ts b/src/validation/errors.ts index f6267ba51..da01aff34 100644 --- a/src/validation/errors.ts +++ b/src/validation/errors.ts @@ -5,16 +5,16 @@ import { ErrorPolykey, sysexits } from '../errors'; * Generic error containing all parsing errors that occurred during * execution. */ -class ErrorValidation extends ErrorPolykey { +class ErrorValidation extends ErrorPolykey { static description = 'Input data failed validation'; exitCode = sysexits.DATAERR; - public errors: Array>; + public errors: Array; constructor(message, data) { super(message, data); if (data.errors != null) { - const errors: Array> = []; + const errors: Array = []; for (const eData of data.errors) { - const errorParse = new ErrorParse(eData.message); + const errorParse = new ErrorParse(eData.message); errorParse.keyPath = eData.keyPath; errorParse.value = eData.value; errorParse.context = eData.context; @@ -28,7 +28,7 @@ class ErrorValidation extends ErrorPolykey { * This packages an `ErrorParse` array into the `data` property * This is to allow encoding to and decoding from GRPC errors */ - static createFromErrors(errors: Array>): ErrorValidation { + static createFromErrors(errors: Array): ErrorValidation { const message = errors.map((e) => e.message).join('; '); const data = { errors: errors.map((e) => ({ @@ -38,7 +38,7 @@ class ErrorValidation extends ErrorPolykey { context: e.context, })), }; - const e = new ErrorValidation(message, data); + const e = new ErrorValidation(message, data); e.errors = errors; return e; } @@ -51,7 +51,7 @@ class ErrorValidation extends ErrorPolykey { * While JS allows us to throw POJOs directly, having a nominal type * is easier to check against */ -class ErrorParse extends AbstractError { +class ErrorParse extends AbstractError { static description: string = 'Failed to parse data into valid format'; exitCode = sysexits.DATAERR; public keyPath: Array; diff --git a/src/validation/utils.ts b/src/validation/utils.ts index 4221e1508..3ce13f258 100644 --- a/src/validation/utils.ts +++ b/src/validation/utils.ts @@ -227,7 +227,6 @@ function parseSeedNodes(data: any): [SeedNodes, boolean] { if (e instanceof TypeError) { throw new validationErrors.ErrorParse( 'Seed nodes must be of format `nodeId@host:port;...`', - { cause: e }, ); } throw e; @@ -246,7 +245,6 @@ function parseSeedNodes(data: any): [SeedNodes, boolean] { if (e instanceof validationErrors.ErrorParse) { throw new validationErrors.ErrorParse( 'Seed nodes must be of format `nodeId@host:port;...`', - { cause: e }, ); } throw e; From 72263c58c4779393a3efacd214ec3407e093e467 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Mon, 2 May 2022 17:13:36 +1000 Subject: [PATCH 007/137] feat: error serialisation/deserialisation over gRPC incorporating error chaining Our gRPC `toError` and `fromError` utils are now able to serialise and deserialise Polykey and non-Polykey errors (as well as non-errors), including the entire error chain if this exists. Also includes the ability to filter out sensitive data, for example when the error is being sent to another agent. Errors sent over the network in this way are now additionally wrapped on the receiving side in an `ErrorPolykeyRemote` to make the source of the error more clear. #304 --- src/ErrorPolykey.ts | 63 +++++-- src/agent/service/nodesChainDataGet.ts | 2 +- .../service/nodesClosestLocalNodesGet.ts | 2 +- src/agent/service/nodesCrossSignClaim.ts | 2 +- .../service/nodesHolePunchMessageSend.ts | 2 +- src/agent/service/notificationsSend.ts | 2 +- src/agent/service/vaultsGitInfoGet.ts | 2 +- src/agent/service/vaultsGitPackGet.ts | 2 +- src/agent/service/vaultsScan.ts | 2 +- src/client/service/gestaltsGestaltList.ts | 2 +- src/client/service/identitiesAuthenticate.ts | 2 +- .../service/identitiesAuthenticatedGet.ts | 2 +- .../service/identitiesInfoConnectedGet.ts | 2 +- src/client/service/identitiesInfoGet.ts | 2 +- src/client/service/keysCertsChainGet.ts | 2 +- src/client/service/vaultsList.ts | 2 +- src/client/service/vaultsLog.ts | 2 +- src/client/service/vaultsPermissionGet.ts | 2 +- src/client/service/vaultsScan.ts | 2 +- src/client/service/vaultsSecretsList.ts | 2 +- src/errors.ts | 12 ++ src/grpc/utils/utils.ts | 162 +++++++++++++++--- tests/grpc/utils.test.ts | 126 +++++++++++++- tests/grpc/utils/testService.ts | 14 +- 24 files changed, 353 insertions(+), 62 deletions(-) diff --git a/src/ErrorPolykey.ts b/src/ErrorPolykey.ts index 17a65d04a..3e418e757 100644 --- a/src/ErrorPolykey.ts +++ b/src/ErrorPolykey.ts @@ -1,20 +1,61 @@ +import type { POJO } from './types'; import { AbstractError } from '@matrixai/errors'; import sysexits from './utils/sysexits'; class ErrorPolykey extends AbstractError { static description: string = 'Polykey error'; exitCode: number = sysexits.GENERAL; - toJSON(): string { - return JSON.stringify({ - name: this.name, - description: this.description, - message: this.message, - exitCode: this.exitCode, - timestamp: this.timestamp, - data: this.data, - cause: this.cause, - stack: this.stack, - }); + public toJSON( + _key: string = '', + options: { + description?: boolean; + message?: boolean, + exitCode?: boolean, + timestamp?: boolean; + data?: boolean; + cause?: boolean; + stack?: boolean; + } = {} + ): { + type: string; + data: { + description?: string; + message?: string; + exitCode?: number, + timestamp?: Date, + data?: POJO; + cause?: T, + stack?: string + } + } { + options.description ??= true; + options.message ??= true; + options.exitCode ??= true; + options.timestamp ??= true; + options.data ??= true; + options.cause ??= true; + options.stack ??= true; + const data: POJO = {}; + if (options.description) data.description = this.description; + if (options.message) data.message = this.message; + if (options.exitCode) data.exitCode = this.exitCode; + if (options.timestamp) data.timestamp = this.timestamp; + if (options.data) data.data = this.data; + if (options.cause) { + // Propagate the options down the exception chain + // but only if the cause is another AbstractError + if (this.cause instanceof ErrorPolykey) { + data.cause = this.cause.toJSON('cause', options); + } else { + // Use `replacer` to further encode this object + data.cause = this.cause; + } + } + if (options.stack) data.stack = this.stack; + return { + type: this.name, + data + }; } } diff --git a/src/agent/service/nodesChainDataGet.ts b/src/agent/service/nodesChainDataGet.ts index 3ed37b99f..2a03bdd7a 100644 --- a/src/agent/service/nodesChainDataGet.ts +++ b/src/agent/service/nodesChainDataGet.ts @@ -37,7 +37,7 @@ function nodesChainDataGet({ sigchain }: { sigchain: Sigchain }) { callback(null, response); return; } catch (e) { - callback(grpcUtils.fromError(e)); + callback(grpcUtils.fromError(e, true)); return; } }; diff --git a/src/agent/service/nodesClosestLocalNodesGet.ts b/src/agent/service/nodesClosestLocalNodesGet.ts index 559337c9d..7e5739495 100644 --- a/src/agent/service/nodesClosestLocalNodesGet.ts +++ b/src/agent/service/nodesClosestLocalNodesGet.ts @@ -53,7 +53,7 @@ function nodesClosestLocalNodesGet({ callback(null, response); return; } catch (e) { - callback(grpcUtils.fromError(e)); + callback(grpcUtils.fromError(e, true)); return; } }; diff --git a/src/agent/service/nodesCrossSignClaim.ts b/src/agent/service/nodesCrossSignClaim.ts index 907494512..2606606ee 100644 --- a/src/agent/service/nodesCrossSignClaim.ts +++ b/src/agent/service/nodesCrossSignClaim.ts @@ -25,7 +25,7 @@ function nodesCrossSignClaim({ ) => { // TODO: Move all "await genClaims.throw" to a final catch(). Wrap this // entire thing in a try block. And re-throw whatever error is caught - const genClaims = grpcUtils.generatorDuplex(call); + const genClaims = grpcUtils.generatorDuplex(call, true); try { await sigchain.transaction(async (sigchain) => { const readStatus = await genClaims.read(); diff --git a/src/agent/service/nodesHolePunchMessageSend.ts b/src/agent/service/nodesHolePunchMessageSend.ts index d524e9f24..2196cceec 100644 --- a/src/agent/service/nodesHolePunchMessageSend.ts +++ b/src/agent/service/nodesHolePunchMessageSend.ts @@ -62,7 +62,7 @@ function nodesHolePunchMessageSend({ callback(null, response); return; } catch (e) { - callback(grpcUtils.fromError(e)); + callback(grpcUtils.fromError(e, true)); return; } }; diff --git a/src/agent/service/notificationsSend.ts b/src/agent/service/notificationsSend.ts index cf2b589ea..d942da04e 100644 --- a/src/agent/service/notificationsSend.ts +++ b/src/agent/service/notificationsSend.ts @@ -25,7 +25,7 @@ function notificationsSend({ callback(null, response); return; } catch (e) { - callback(grpcUtils.fromError(e)); + callback(grpcUtils.fromError(e, true)); return; } }; diff --git a/src/agent/service/vaultsGitInfoGet.ts b/src/agent/service/vaultsGitInfoGet.ts index 72f01a74c..1a043f92b 100644 --- a/src/agent/service/vaultsGitInfoGet.ts +++ b/src/agent/service/vaultsGitInfoGet.ts @@ -23,7 +23,7 @@ function vaultsGitInfoGet({ return async ( call: grpc.ServerWritableStream, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, true); const request = call.request; const vaultMessage = request.getVault(); if (vaultMessage == null) { diff --git a/src/agent/service/vaultsGitPackGet.ts b/src/agent/service/vaultsGitPackGet.ts index 5528ade31..8c0d9232f 100644 --- a/src/agent/service/vaultsGitPackGet.ts +++ b/src/agent/service/vaultsGitPackGet.ts @@ -24,7 +24,7 @@ function vaultsGitPackGet({ return async ( call: grpc.ServerDuplexStream, ) => { - const genDuplex = grpcUtils.generatorDuplex(call); + const genDuplex = grpcUtils.generatorDuplex(call, true); const clientBodyBuffers: Uint8Array[] = []; const clientRequest = (await genDuplex.read()).value; clientBodyBuffers.push(clientRequest!.getChunk_asU8()); diff --git a/src/agent/service/vaultsScan.ts b/src/agent/service/vaultsScan.ts index 6dfd028e4..acdcfb0b1 100644 --- a/src/agent/service/vaultsScan.ts +++ b/src/agent/service/vaultsScan.ts @@ -17,7 +17,7 @@ function vaultsScan({ return async ( call: grpc.ServerWritableStream, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, true); const listMessage = new vaultsPB.List(); // Getting the NodeId from the ReverseProxy connection info const connectionInfo = connectionInfoGet(call); diff --git a/src/client/service/gestaltsGestaltList.ts b/src/client/service/gestaltsGestaltList.ts index 458b5cf32..6f3c1c9ea 100644 --- a/src/client/service/gestaltsGestaltList.ts +++ b/src/client/service/gestaltsGestaltList.ts @@ -16,7 +16,7 @@ function gestaltsGestaltList({ return async ( call: grpc.ServerWritableStream, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); let gestaltMessage: gestaltsPB.Gestalt; try { const metadata = await authenticate(call.metadata); diff --git a/src/client/service/identitiesAuthenticate.ts b/src/client/service/identitiesAuthenticate.ts index 24ccf2f7e..c80378790 100644 --- a/src/client/service/identitiesAuthenticate.ts +++ b/src/client/service/identitiesAuthenticate.ts @@ -21,7 +21,7 @@ function identitiesAuthenticate({ identitiesPB.AuthenticationProcess >, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); diff --git a/src/client/service/identitiesAuthenticatedGet.ts b/src/client/service/identitiesAuthenticatedGet.ts index 1fd4bb9da..fa2ca756f 100644 --- a/src/client/service/identitiesAuthenticatedGet.ts +++ b/src/client/service/identitiesAuthenticatedGet.ts @@ -21,7 +21,7 @@ function identitiesAuthenticatedGet({ identitiesPB.Provider >, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); diff --git a/src/client/service/identitiesInfoConnectedGet.ts b/src/client/service/identitiesInfoConnectedGet.ts index 399600900..865616d06 100644 --- a/src/client/service/identitiesInfoConnectedGet.ts +++ b/src/client/service/identitiesInfoConnectedGet.ts @@ -26,7 +26,7 @@ function identitiesInfoConnectedGet({ identitiesPB.Info >, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); diff --git a/src/client/service/identitiesInfoGet.ts b/src/client/service/identitiesInfoGet.ts index bbf159f55..400367140 100644 --- a/src/client/service/identitiesInfoGet.ts +++ b/src/client/service/identitiesInfoGet.ts @@ -27,7 +27,7 @@ function identitiesInfoGet({ identitiesPB.Info >, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); diff --git a/src/client/service/keysCertsChainGet.ts b/src/client/service/keysCertsChainGet.ts index 8355474fd..792b86916 100644 --- a/src/client/service/keysCertsChainGet.ts +++ b/src/client/service/keysCertsChainGet.ts @@ -15,7 +15,7 @@ function keysCertsChainGet({ return async ( call: grpc.ServerWritableStream, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); diff --git a/src/client/service/vaultsList.ts b/src/client/service/vaultsList.ts index d81902976..c35f51eea 100644 --- a/src/client/service/vaultsList.ts +++ b/src/client/service/vaultsList.ts @@ -19,7 +19,7 @@ function vaultsList({ // Call.on('error', (e) => console.error(e)); // call.on('close', () => console.log('Got close')); // call.on('finish', () => console.log('Got finish')); - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); diff --git a/src/client/service/vaultsLog.ts b/src/client/service/vaultsLog.ts index 99056911a..02b35a6f8 100644 --- a/src/client/service/vaultsLog.ts +++ b/src/client/service/vaultsLog.ts @@ -17,7 +17,7 @@ function vaultsLog({ return async ( call: grpc.ServerWritableStream, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); diff --git a/src/client/service/vaultsPermissionGet.ts b/src/client/service/vaultsPermissionGet.ts index 23780000e..bb2b24dc1 100644 --- a/src/client/service/vaultsPermissionGet.ts +++ b/src/client/service/vaultsPermissionGet.ts @@ -24,7 +24,7 @@ function vaultsPermissionGet({ return async ( call: grpc.ServerWritableStream, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); try { const vaultMessage = call.request; const metadata = await authenticate(call.metadata); diff --git a/src/client/service/vaultsScan.ts b/src/client/service/vaultsScan.ts index 3d8d73a7e..0ed5ebbbe 100644 --- a/src/client/service/vaultsScan.ts +++ b/src/client/service/vaultsScan.ts @@ -19,7 +19,7 @@ function vaultsScan({ return async ( call: grpc.ServerWritableStream, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); diff --git a/src/client/service/vaultsSecretsList.ts b/src/client/service/vaultsSecretsList.ts index db2a1cc36..db71fc128 100644 --- a/src/client/service/vaultsSecretsList.ts +++ b/src/client/service/vaultsSecretsList.ts @@ -18,7 +18,7 @@ function vaultsSecretsList({ return async ( call: grpc.ServerWritableStream, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); diff --git a/src/errors.ts b/src/errors.ts index 10d662ed3..53ec7b8ed 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -6,6 +6,16 @@ class ErrorPolykeyUnimplemented extends ErrorPolykey { exitCode = sysexits.UNAVAILABLE; } +class ErrorPolykeyUnknown extends ErrorPolykey { + static description = 'Unable to deserialise to known error'; + exitCode = sysexits.UNKNOWN; +} + +class ErrorPolykeyRemote extends ErrorPolykey { + static description = 'Remote error from RPC call'; + exitCode = sysexits.UNAVAILABLE; +} + class ErrorPolykeyAgentRunning extends ErrorPolykey { static description = 'PolykeyAgent is running'; exitCode = sysexits.USAGE; @@ -44,6 +54,8 @@ export { sysexits, ErrorPolykey, ErrorPolykeyUnimplemented, + ErrorPolykeyUnknown, + ErrorPolykeyRemote, ErrorPolykeyAgentRunning, ErrorPolykeyAgentNotRunning, ErrorPolykeyAgentDestroyed, diff --git a/src/grpc/utils/utils.ts b/src/grpc/utils/utils.ts index 0a223c1a9..b75a6d21e 100644 --- a/src/grpc/utils/utils.ts +++ b/src/grpc/utils/utils.ts @@ -29,6 +29,7 @@ import type { } from '../types'; import type { CertificatePemChain, PrivateKeyPem } from '../../keys/types'; import { Buffer } from 'buffer'; +import { AbstractError } from '@matrixai/errors'; import * as grpc from '@grpc/grpc-js'; import * as grpcErrors from '../errors'; import * as errors from '../../errors'; @@ -158,17 +159,16 @@ function getServerSession(call: ServerSurfaceCall): Http2Session { * Serializes Error instances into GRPC errors * Use this on the sending side to send exceptions * Do not send exceptions to clients you do not trust + * If sending to an agent (rather than a client), set sensitive to true to + * prevent sensitive information from being sent over the network */ -function fromError(error: Error): ServerStatusResponse { +function fromError(error: Error, sensitive: boolean = false): ServerStatusResponse { const metadata = new grpc.Metadata(); - // If the error is not ErrorPolykey, wrap it up so it can be serialised - // TODO: add additional metadata regarding the network location of the error - if (!(error instanceof errors.ErrorPolykey)) { - error = new errors.ErrorPolykey(error.message); + if (sensitive) { + metadata.set('error', JSON.stringify(error, sensitiveReplacer)); + } else { + metadata.set('error', JSON.stringify(error, replacer)); } - metadata.set('name', error.name); - metadata.set('message', error.message); - metadata.set('data', JSON.stringify((error as errors.ErrorPolykey).data)); return { metadata, }; @@ -178,10 +178,8 @@ function fromError(error: Error): ServerStatusResponse { * Deserialized GRPC errors into ErrorPolykey * Use this on the receiving side to receive exceptions */ -function toError(e: ServiceError): errors.ErrorPolykey { - const errorName = e.metadata.get('name')[0] as string; - const errorMessage = e.metadata.get('message')[0] as string; - const errorData = e.metadata.get('data')[0] as string; +function toError(e: ServiceError): errors.ErrorPolykey { + const errorData = e.metadata.get('error')[0] as string; // Grpc.status is an enum // this will iterate the enum values then enum keys // they will all be of string type @@ -192,14 +190,12 @@ function toError(e: ServiceError): errors.ErrorPolykey { if (isNaN(parseInt(key)) && e.code === grpc.status[key]) { if ( key === 'UNKNOWN' && - errorName != null && - errorMessage != null && - errorData != null && - errorName in errors + errorData != null ) { - return new errors[errorName](errorMessage, { data: JSON.parse(errorData) }); + const error: Error = JSON.parse(errorData, reviver); + return new errors.ErrorPolykeyRemote(error.message, { cause: error }); } else { - return new grpcErrors.ErrorGRPCClientCall(e.message, { + return new grpcErrors.ErrorGRPCClientCall(e.message, { data: { code: e.code, details: e.details, @@ -212,6 +208,124 @@ function toError(e: ServiceError): errors.ErrorPolykey { never(); } +/** + * Replacer function for serialising errors over GRPC (used by `JSON.stringify` + * in `fromError`) + * Polykey errors are handled by their inbuilt `toJSON` method , so this only + * serialises other errors + */ + function replacer(key: string, value: any): any { + if (value instanceof AbstractError) { + // Include the standard properties from an AbstractError + return { + type: value.name, + data: { + description: value.description, + message: value.message, + timestamp: value.timestamp, + data: value.data, + cause: value.cause, + stack: value.stack, + } + } + } else if (value instanceof Error) { + // If it's some other type of error then only serialise the message and + // stack (and the type of the error) + return { + type: value.name, + data: { + message: value.message, + stack: value.stack, + } + } + } else { + // If it's not an error then just leave as is + return value; + } +} + +/** + * The same as `replacer`, however this will additionally filter out any + * sensitive data that should not be sent over the network when sending to an + * agent (as opposed to a client) + */ +function sensitiveReplacer(key: string, value: any) { + if (key === 'stack') { + return; + } else { + return replacer(key, value); + } +} + +/** + * Error constructors for non-Polykey errors + * Allows these errors to be reconstructed from GRPC metadata + */ +const otherErrors = { + 'Error': Error, + 'EvalError': EvalError, + 'RangeError': RangeError, + 'ReferenceError': ReferenceError, + 'SyntaxError': SyntaxError, + 'TypeError': TypeError, + 'URIError': URIError +}; + +/** + * Reviver function for deserialising errors sent over GRPC (used by + * `JSON.parse` in `toError`) + * The final result returned will always be an error - if the deserialised + * data is of an unknown type then this will be wrapped as an + * `ErrorPolykeyUnknown` + */ +function reviver(key: string, value: any): any { + // If the value is an error then reconstruct it + if (typeof value === 'object' && typeof value.type === 'string' && typeof value.data === 'object') { + const message = value.data.message ?? ''; + if (value.type in errors) { + const error = new errors[value.type]( + message, + { + timestamp: value.data.timestamp, + data: value.data.data, + cause: value.data.cause, + }, + ); + error.exitCode = value.data.exitCode; + if (value.data.stack) { + error.stack = value.data.stack; + } + return error; + } else if (value.type in otherErrors) { + const error = new otherErrors[value.type](message); + if (value.data.stack) { + error.stack = value.data.stack; + } + return error; + } else { + const error = new errors.ErrorPolykeyUnknown('', { data: value }); + if (value.data.stack) { + error.stack = value.data.stack; + } + return error; + } + } else if (key === '') { + // The value is not an error + const error = new errors.ErrorPolykeyUnknown('', { data: value }); + return error; + } else if (key === 'timestamp') { + // Encode timestamps + const timestampParsed = Date.parse(value); + if (!isNaN(timestampParsed)) { + return new Date(timestampParsed); + } else { + return undefined; + } + } else { + return value; + } +} + /** * Converts GRPC unary call to promisified unary call * Used on the client side @@ -326,12 +440,15 @@ function promisifyReadableStreamCall( */ function generatorWritable( stream: ClientWritableStream, + sensitive: boolean, ): AsyncGeneratorWritableStream>; function generatorWritable( stream: ServerWritableStream, + sensitive: boolean, ): AsyncGeneratorWritableStream>; function generatorWritable( stream: ClientWritableStream | ServerWritableStream, + sensitive: boolean = false, ) { const streamWrite = promisify(stream.write).bind(stream); const gf = async function* () { @@ -340,7 +457,7 @@ function generatorWritable( try { vW = yield; } catch (e) { - stream.emit('error', fromError(e)); + stream.emit('error', fromError(e, sensitive)); stream.end(); return; } @@ -393,6 +510,7 @@ function promisifyWritableStreamCall( }); const g = generatorWritable( stream, + false, ) as AsyncGeneratorWritableStreamClient< TWrite, ClientWritableStream @@ -412,15 +530,18 @@ function promisifyWritableStreamCall( */ function generatorDuplex( stream: ClientDuplexStream, + sensitive: boolean, ): AsyncGeneratorDuplexStream>; function generatorDuplex( stream: ServerDuplexStream, + sensitive: boolean, ): AsyncGeneratorDuplexStream>; function generatorDuplex( stream: ClientDuplexStream | ServerDuplexStream, + sensitive: boolean = false, ) { const gR = generatorReadable(stream as any); - const gW = generatorWritable(stream as any); + const gW = generatorWritable(stream as any, sensitive); const gf = async function* () { let vR: any, vW: any; while (true) { @@ -485,6 +606,7 @@ function promisifyDuplexStreamCall( }); const g = generatorDuplex( stream, + false, ) as AsyncGeneratorDuplexStreamClient< TRead, TWrite, diff --git a/tests/grpc/utils.test.ts b/tests/grpc/utils.test.ts index c17f0457d..b2390e2fa 100644 --- a/tests/grpc/utils.test.ts +++ b/tests/grpc/utils.test.ts @@ -4,6 +4,7 @@ import * as grpc from '@grpc/grpc-js'; import { getLogger } from '@grpc/grpc-js/build/src/logging'; import * as grpcUtils from '@/grpc/utils'; import * as grpcErrors from '@/grpc/errors'; +import * as errors from '@/errors'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as utils from './utils'; @@ -57,13 +58,14 @@ describe('GRPC utils', () => { const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('error'); const pCall = unary(messageTo); - await expect(pCall).rejects.toThrow(grpcErrors.ErrorGRPC); + await expect(pCall).rejects.toThrow(errors.ErrorPolykeyRemote); try { await pCall; } catch (e) { // This information comes from the server expect(e.message).toBe('test error'); - expect(e.data).toMatchObject({ + expect(e.cause).toBeInstanceOf(grpcErrors.ErrorGRPC); + expect(e.cause.data).toMatchObject({ grpc: true, }); } @@ -103,7 +105,7 @@ describe('GRPC utils', () => { const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge(challenge); const stream = serverStream(messageTo); - await expect(() => stream.next()).rejects.toThrow(grpcErrors.ErrorGRPC); + await expect(() => stream.next()).rejects.toThrow(errors.ErrorPolykeyRemote); // The generator will have ended // the internal stream will be automatically destroyed const result = await stream.next(); @@ -274,7 +276,7 @@ describe('GRPC utils', () => { const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('error'); await genDuplex.write(messageTo); - await expect(() => genDuplex.read()).rejects.toThrow(grpcErrors.ErrorGRPC); + await expect(() => genDuplex.read()).rejects.toThrow(errors.ErrorPolykeyRemote); expect(genDuplex.stream.destroyed).toBe(true); expect(genDuplex.stream.getPeer()).toBe(`127.0.0.1:${port}`); }); @@ -287,9 +289,123 @@ describe('GRPC utils', () => { const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('error'); await expect(() => genDuplex.next(messageTo)).rejects.toThrow( - grpcErrors.ErrorGRPC, + errors.ErrorPolykeyRemote, ); expect(genDuplex.stream.destroyed).toBe(true); expect(genDuplex.stream.getPeer()).toBe(`127.0.0.1:${port}`); }); + test('serialising and deserialising Polykey errors', async () => { + const timestamp = new Date(); + const error = new errors.ErrorPolykey('test error', { + timestamp, + data: { + int: 1, + str: 'one', + }, + }); + error.exitCode = 255; + const serialised = grpcUtils.fromError(error).metadata!; + const stringifiedError = serialised.get('error')[0] as string; + const parsedError = JSON.parse(stringifiedError); + expect(parsedError).toMatchObject({ + type: 'ErrorPolykey', + data: expect.any(Object), + }); + const deserialisedError = grpcUtils.toError({ + name: '', + message: '', + code: 2, + details: '', + metadata: serialised + }); + expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); + expect(deserialisedError.message).toBe('test error'); + expect(deserialisedError.cause).toBeInstanceOf(errors.ErrorPolykey); + expect(deserialisedError.cause.message).toBe('test error'); + expect(deserialisedError.cause.exitCode).toBe(255); + expect(deserialisedError.cause.timestamp).toEqual(timestamp); + expect(deserialisedError.cause.data).toEqual(error.data); + expect(deserialisedError.cause.stack).toBe(error.stack); + }); + test('serialising and deserialising generic errors', async () => { + const error = new TypeError('test error'); + const serialised = grpcUtils.fromError(error).metadata!; + const stringifiedError = serialised.get('error')[0] as string; + const parsedError = JSON.parse(stringifiedError); + expect(parsedError).toMatchObject({ + type: 'TypeError', + data: expect.any(Object), + }); + const deserialisedError = grpcUtils.toError({ + name: '', + message: '', + code: 2, + details: '', + metadata: serialised + }); + expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); + expect(deserialisedError.message).toBe('test error'); + expect(deserialisedError.cause).toBeInstanceOf(TypeError); + expect(deserialisedError.cause.message).toBe('test error'); + expect(deserialisedError.cause.stack).toBe(error.stack); + }); + test('serialising and deserialising non-errors', async () => { + const error = 'not an error' as unknown as Error; + const serialised = grpcUtils.fromError(error).metadata!; + const stringifiedError = serialised.get('error')[0] as string; + const parsedError = JSON.parse(stringifiedError); + expect(parsedError).toEqual('not an error'); + const deserialisedError = grpcUtils.toError({ + name: '', + message: '', + code: 2, + details: '', + metadata: serialised + }); + expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); + expect(deserialisedError.message).toBe(''); + expect(deserialisedError.cause).toBeInstanceOf(errors.ErrorPolykeyUnknown); + expect(deserialisedError.cause.message).toBe(''); + expect(deserialisedError.cause.data).toEqual('not an error'); + }); + test('serialising and deserialising sensitive errors', async () => { + const timestamp = new Date(); + const error = new errors.ErrorPolykey('test error', { + timestamp, + data: { + int: 1, + str: 'one', + }, + }); + error.exitCode = 255; + const serialised = grpcUtils.fromError(error, true).metadata!; + const stringifiedError = serialised.get('error')[0] as string; + const parsedError = JSON.parse(stringifiedError); + // Stack is the only thing that should not be serialised + expect(parsedError).toEqual({ + type: 'ErrorPolykey', + data: { + description: errors.ErrorPolykey.description, + message: 'test error', + exitCode: 255, + timestamp: expect.any(String), + data: error.data, + }, + }); + const deserialisedError = grpcUtils.toError({ + name: '', + message: '', + code: 2, + details: '', + metadata: serialised + }); + expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); + expect(deserialisedError.message).toBe('test error'); + expect(deserialisedError.cause).toBeInstanceOf(errors.ErrorPolykey); + expect(deserialisedError.cause.message).toBe('test error'); + expect(deserialisedError.cause.exitCode).toBe(255); + expect(deserialisedError.cause.timestamp).toEqual(timestamp); + expect(deserialisedError.cause.data).toEqual(error.data); + expect(deserialisedError.cause.stack).not.toBe(error.stack); + }); }); diff --git a/tests/grpc/utils/testService.ts b/tests/grpc/utils/testService.ts index 5c3356d7f..1297c354c 100644 --- a/tests/grpc/utils/testService.ts +++ b/tests/grpc/utils/testService.ts @@ -43,7 +43,7 @@ function createTestService({ // we'll send back an error callback( grpcUtils.fromError( - new grpcErrors.ErrorGRPC('test error', { grpc: true }), + new grpcErrors.ErrorGRPC('test error', { data: { grpc: true } }), ), ); } else { @@ -67,13 +67,13 @@ function createTestService({ ); call.sendMetadata(meta); } - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); const messageFrom = call.request; const messageTo = new utilsPB.EchoMessage(); const challenge = messageFrom.getChallenge(); if (challenge === 'error') { await genWritable.throw( - new grpcErrors.ErrorGRPC('test error', { grpc: true }), + new grpcErrors.ErrorGRPC('test error', { data: { grpc: true } }), ); } else { // Will send back a number of message @@ -131,7 +131,7 @@ function createTestService({ ); call.sendMetadata(meta); } - const genDuplex = grpcUtils.generatorDuplex(call); + const genDuplex = grpcUtils.generatorDuplex(call, false); const readStatus = await genDuplex.read(); // If nothing to read, end and destroy if (readStatus.done) { @@ -143,7 +143,7 @@ function createTestService({ const incomingMessage = readStatus.value; if (incomingMessage.getChallenge() === 'error') { await genDuplex.throw( - new grpcErrors.ErrorGRPC('test error', { grpc: true }), + new grpcErrors.ErrorGRPC('test error', { data: { grpc: true } }), ); } else { const outgoingMessage = new utilsPB.EchoMessage(); @@ -169,7 +169,7 @@ function createTestService({ // we'll send back an error callback( grpcUtils.fromError( - new grpcErrors.ErrorGRPC('test error', { grpc: true }), + new grpcErrors.ErrorGRPC('test error', { data: { grpc: true } }), ), ); } else { @@ -182,7 +182,7 @@ function createTestService({ serverStreamFail: async ( call: grpc.ServerWritableStream, ): Promise => { - const genWritable = grpcUtils.generatorWritable(call); + const genWritable = grpcUtils.generatorWritable(call, false); try { const echoMessage = new utilsPB.EchoMessage().setChallenge('Hello!'); for (let i = 0; i < 10; i++) { From e5dfadbfb8bfd9b279b246651e5d5284888b6fd1 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 4 May 2022 15:14:36 +1000 Subject: [PATCH 008/137] feat: added logger to service handlers All of the agent and client service handlers are now passed a shared logger that is used to log errors to stderr. #304 --- src/ErrorPolykey.ts | 18 +-- src/agent/service/index.ts | 55 ++++---- src/agent/service/nodesChainDataGet.ts | 10 +- .../service/nodesClosestLocalNodesGet.ts | 4 + src/agent/service/nodesCrossSignClaim.ts | 12 +- .../service/nodesHolePunchMessageSend.ts | 4 + src/agent/service/notificationsSend.ts | 4 + src/agent/service/vaultsGitInfoGet.ts | 116 ++++++++-------- src/agent/service/vaultsGitPackGet.ts | 128 +++++++++--------- src/agent/service/vaultsScan.ts | 4 + src/bin/nodes/CommandPing.ts | 3 +- src/claims/errors.ts | 8 +- src/client/service/agentLockAll.ts | 8 +- src/client/service/agentStatus.ts | 4 + src/client/service/agentStop.ts | 4 + src/client/service/agentUnlock.ts | 10 +- .../service/gestaltsActionsGetByIdentity.ts | 4 + .../service/gestaltsActionsGetByNode.ts | 4 + .../service/gestaltsActionsSetByIdentity.ts | 4 + .../service/gestaltsActionsSetByNode.ts | 4 + .../service/gestaltsActionsUnsetByIdentity.ts | 4 + .../service/gestaltsActionsUnsetByNode.ts | 4 + .../service/gestaltsDiscoveryByIdentity.ts | 4 + src/client/service/gestaltsDiscoveryByNode.ts | 4 + .../service/gestaltsGestaltGetByIdentity.ts | 4 + .../service/gestaltsGestaltGetByNode.ts | 4 + src/client/service/gestaltsGestaltList.ts | 4 + .../service/gestaltsGestaltTrustByIdentity.ts | 4 + .../service/gestaltsGestaltTrustByNode.ts | 4 + src/client/service/identitiesAuthenticate.ts | 8 +- .../service/identitiesAuthenticatedGet.ts | 8 +- src/client/service/identitiesClaim.ts | 8 +- .../service/identitiesInfoConnectedGet.ts | 8 +- src/client/service/identitiesInfoGet.ts | 8 +- src/client/service/identitiesProvidersList.ts | 8 +- src/client/service/identitiesTokenDelete.ts | 8 +- src/client/service/identitiesTokenGet.ts | 8 +- src/client/service/identitiesTokenPut.ts | 8 +- src/client/service/keysCertsChainGet.ts | 8 +- src/client/service/keysCertsGet.ts | 8 +- src/client/service/keysDecrypt.ts | 8 +- src/client/service/keysEncrypt.ts | 8 +- src/client/service/keysKeyPairRenew.ts | 8 +- src/client/service/keysKeyPairReset.ts | 8 +- src/client/service/keysKeyPairRoot.ts | 8 +- src/client/service/keysPasswordChange.ts | 8 +- src/client/service/keysSign.ts | 8 +- src/client/service/keysVerify.ts | 8 +- src/client/service/nodesAdd.ts | 8 +- src/client/service/nodesClaim.ts | 8 +- src/client/service/nodesFind.ts | 8 +- src/client/service/nodesPing.ts | 8 +- src/client/service/notificationsClear.ts | 8 +- src/client/service/notificationsRead.ts | 8 +- src/client/service/notificationsSend.ts | 8 +- src/client/service/vaultsClone.ts | 4 + src/client/service/vaultsCreate.ts | 8 +- src/client/service/vaultsDelete.ts | 8 +- src/client/service/vaultsList.ts | 8 +- src/client/service/vaultsLog.ts | 8 +- src/client/service/vaultsPermissionGet.ts | 8 +- src/client/service/vaultsPermissionSet.ts | 8 +- src/client/service/vaultsPermissionUnset.ts | 8 +- src/client/service/vaultsPull.ts | 4 + src/client/service/vaultsRename.ts | 8 +- src/client/service/vaultsScan.ts | 8 +- src/client/service/vaultsSecretsDelete.ts | 8 +- src/client/service/vaultsSecretsEdit.ts | 8 +- src/client/service/vaultsSecretsGet.ts | 8 +- src/client/service/vaultsSecretsList.ts | 8 +- src/client/service/vaultsSecretsMkdir.ts | 8 +- src/client/service/vaultsSecretsNew.ts | 8 +- src/client/service/vaultsSecretsNewDir.ts | 8 +- src/client/service/vaultsSecretsRename.ts | 8 +- src/client/service/vaultsSecretsStat.ts | 4 + src/client/service/vaultsVersion.ts | 8 +- src/gestalts/utils.ts | 2 +- src/grpc/GRPCClient.ts | 3 +- src/grpc/GRPCServer.ts | 3 +- src/grpc/utils/utils.ts | 53 ++++---- src/identities/errors.ts | 3 +- .../providers/github/GitHubProvider.ts | 3 +- src/network/utils.ts | 4 +- src/nodes/NodeConnection.ts | 4 +- src/notifications/errors.ts | 4 +- src/notifications/utils.ts | 4 +- src/status/Status.ts | 8 +- src/vaults/VaultInternal.ts | 8 +- .../agent/service/nodesCrossSignClaim.test.ts | 11 +- tests/agent/service/notificationsSend.test.ts | 1 + tests/client/GRPCClientClient.test.ts | 2 +- tests/client/service/agentLockAll.test.ts | 1 + tests/client/service/agentStatus.test.ts | 1 + tests/client/service/agentStop.test.ts | 1 + tests/client/service/agentUnlock.test.ts | 1 + ...staltsActionsSetUnsetGetByIdentity.test.ts | 3 + .../gestaltsActionsSetUnsetGetByNode.test.ts | 3 + .../gestaltsDiscoveryByIdentity.test.ts | 1 + .../service/gestaltsDiscoveryByNode.test.ts | 1 + .../gestaltsGestaltGetByIdentity.test.ts | 1 + .../service/gestaltsGestaltGetByNode.test.ts | 1 + .../service/gestaltsGestaltList.test.ts | 1 + .../gestaltsGestaltTrustByIdentity.test.ts | 1 + .../gestaltsGestaltTrustByNode.test.ts | 1 + .../service/identitiesAuthenticate.test.ts | 1 + .../identitiesAuthenticatedGet.test.ts | 1 + tests/client/service/identitiesClaim.test.ts | 1 + .../identitiesInfoConnectedGet.test.ts | 1 + .../client/service/identitiesInfoGet.test.ts | 1 + .../service/identitiesProvidersList.test.ts | 1 + .../identitiesTokenPutDeleteGet.test.ts | 3 + .../client/service/keysCertsChainGet.test.ts | 1 + tests/client/service/keysCertsGet.test.ts | 1 + .../client/service/keysEncryptDecrypt.test.ts | 2 + tests/client/service/keysKeyPairRenew.test.ts | 1 + tests/client/service/keysKeyPairReset.test.ts | 1 + tests/client/service/keysKeyPairRoot.test.ts | 1 + .../client/service/keysPasswordChange.test.ts | 1 + tests/client/service/keysSignVerify.test.ts | 2 + tests/client/service/nodesAdd.test.ts | 1 + tests/client/service/nodesClaim.test.ts | 1 + tests/client/service/nodesFind.test.ts | 3 +- tests/client/service/nodesPing.test.ts | 1 + .../client/service/notificationsClear.test.ts | 1 + .../client/service/notificationsRead.test.ts | 1 + .../client/service/notificationsSend.test.ts | 1 + tests/grpc/utils.test.ts | 16 ++- 127 files changed, 666 insertions(+), 316 deletions(-) diff --git a/src/ErrorPolykey.ts b/src/ErrorPolykey.ts index 3e418e757..deba43ef2 100644 --- a/src/ErrorPolykey.ts +++ b/src/ErrorPolykey.ts @@ -9,24 +9,24 @@ class ErrorPolykey extends AbstractError { _key: string = '', options: { description?: boolean; - message?: boolean, - exitCode?: boolean, + message?: boolean; + exitCode?: boolean; timestamp?: boolean; data?: boolean; cause?: boolean; stack?: boolean; - } = {} + } = {}, ): { type: string; data: { description?: string; message?: string; - exitCode?: number, - timestamp?: Date, + exitCode?: number; + timestamp?: Date; data?: POJO; - cause?: T, - stack?: string - } + cause?: T; + stack?: string; + }; } { options.description ??= true; options.message ??= true; @@ -54,7 +54,7 @@ class ErrorPolykey extends AbstractError { if (options.stack) data.stack = this.stack; return { type: this.name, - data + data, }; } } diff --git a/src/agent/service/index.ts b/src/agent/service/index.ts index aa96bfd2e..caa8c60ed 100644 --- a/src/agent/service/index.ts +++ b/src/agent/service/index.ts @@ -1,16 +1,15 @@ -import type { KeyManager } from '../../keys'; -import type { VaultManager } from '../../vaults'; -import type { - NodeGraph, - NodeManager, - NodeConnectionManager, -} from '../../nodes'; -import type { NotificationsManager } from '../../notifications'; -import type { Sigchain } from '../../sigchain'; -import type { ACL } from '../../acl'; -import type { GestaltGraph } from '../../gestalts'; +import type KeyManager from '../../keys/KeyManager'; +import type VaultManager from '../../vaults/VaultManager'; +import type NodeGraph from '../../nodes/NodeGraph'; +import type NodeManager from '../../nodes/NodeManager'; +import type NodeConnectionManager from '../../nodes/NodeConnectionManager'; +import type NotificationsManager from '../../notifications/NotificationsManager'; +import type Sigchain from '../../sigchain/Sigchain'; +import type ACL from '../../acl/ACL'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { IAgentServiceServer } from '../../proto/js/polykey/v1/agent_service_grpc_pb'; import type Proxy from '../../network/Proxy'; +import Logger from '@matrixai/logger'; import echo from './echo'; import nodesChainDataGet from './nodesChainDataGet'; import nodesClaimsGet from './nodesClaimsGet'; @@ -24,7 +23,11 @@ import vaultsScan from './vaultsScan'; import { AgentServiceService } from '../../proto/js/polykey/v1/agent_service_grpc_pb'; import * as agentUtils from '../utils'; -function createService(container: { +function createService({ + proxy, + logger = new Logger(createService.name), + ...containerRest +}: { keyManager: KeyManager; vaultManager: VaultManager; nodeConnectionManager: NodeConnectionManager; @@ -35,23 +38,25 @@ function createService(container: { acl: ACL; gestaltGraph: GestaltGraph; proxy: Proxy; + logger?: Logger; }): IAgentServiceServer { - const connectionInfoGet = agentUtils.connectionInfoGetter(container.proxy); - const container_ = { - ...container, + const connectionInfoGet = agentUtils.connectionInfoGetter(proxy); + const container = { + ...containerRest, + logger, connectionInfoGet: connectionInfoGet, }; const service: IAgentServiceServer = { - echo: echo(container_), - nodesChainDataGet: nodesChainDataGet(container_), - nodesClaimsGet: nodesClaimsGet(container_), - nodesClosestLocalNodesGet: nodesClosestLocalNodesGet(container_), - nodesCrossSignClaim: nodesCrossSignClaim(container_), - nodesHolePunchMessageSend: nodesHolePunchMessageSend(container_), - notificationsSend: notificationsSend(container_), - vaultsGitInfoGet: vaultsGitInfoGet(container_), - vaultsGitPackGet: vaultsGitPackGet(container_), - vaultsScan: vaultsScan(container_), + echo: echo(container), + nodesChainDataGet: nodesChainDataGet(container), + nodesClaimsGet: nodesClaimsGet(container), + nodesClosestLocalNodesGet: nodesClosestLocalNodesGet(container), + nodesCrossSignClaim: nodesCrossSignClaim(container), + nodesHolePunchMessageSend: nodesHolePunchMessageSend(container), + notificationsSend: notificationsSend(container), + vaultsGitInfoGet: vaultsGitInfoGet(container), + vaultsGitPackGet: vaultsGitPackGet(container), + vaultsScan: vaultsScan(container), }; return service; } diff --git a/src/agent/service/nodesChainDataGet.ts b/src/agent/service/nodesChainDataGet.ts index 2a03bdd7a..4301dff01 100644 --- a/src/agent/service/nodesChainDataGet.ts +++ b/src/agent/service/nodesChainDataGet.ts @@ -2,13 +2,20 @@ import type * as grpc from '@grpc/grpc-js'; import type { Sigchain } from '../../sigchain'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type { ClaimIdEncoded } from '../../claims/types'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; /** * Retrieves the ChainDataEncoded of this node. */ -function nodesChainDataGet({ sigchain }: { sigchain: Sigchain }) { +function nodesChainDataGet({ + sigchain, + logger, +}: { + sigchain: Sigchain; + logger: Logger; +}) { return async ( call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData, @@ -38,6 +45,7 @@ function nodesChainDataGet({ sigchain }: { sigchain: Sigchain }) { return; } catch (e) { callback(grpcUtils.fromError(e, true)); + logger.error(e); return; } }; diff --git a/src/agent/service/nodesClosestLocalNodesGet.ts b/src/agent/service/nodesClosestLocalNodesGet.ts index 7e5739495..dc709195b 100644 --- a/src/agent/service/nodesClosestLocalNodesGet.ts +++ b/src/agent/service/nodesClosestLocalNodesGet.ts @@ -1,6 +1,7 @@ import type * as grpc from '@grpc/grpc-js'; import type { NodeConnectionManager } from '../../nodes'; import type { NodeId } from '../../nodes/types'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { utils as nodesUtils } from '../../nodes'; import { validateSync, utils as validationUtils } from '../../validation'; @@ -13,8 +14,10 @@ import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; */ function nodesClosestLocalNodesGet({ nodeConnectionManager, + logger, }: { nodeConnectionManager: NodeConnectionManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -54,6 +57,7 @@ function nodesClosestLocalNodesGet({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); + logger.error(e); return; } }; diff --git a/src/agent/service/nodesCrossSignClaim.ts b/src/agent/service/nodesCrossSignClaim.ts index 2606606ee..45af67a8d 100644 --- a/src/agent/service/nodesCrossSignClaim.ts +++ b/src/agent/service/nodesCrossSignClaim.ts @@ -5,6 +5,7 @@ import type { NodeId } from '../../nodes/types'; import type { Sigchain } from '../../sigchain'; import type { KeyManager } from '../../keys'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { utils as claimsUtils, errors as claimsErrors } from '../../claims'; import { utils as nodesUtils } from '../../nodes'; @@ -15,16 +16,16 @@ function nodesCrossSignClaim({ keyManager, nodeManager, sigchain, + logger, }: { keyManager: KeyManager; nodeManager: NodeManager; sigchain: Sigchain; + logger: Logger; }) { return async ( call: grpc.ServerDuplexStream, ) => { - // TODO: Move all "await genClaims.throw" to a final catch(). Wrap this - // entire thing in a try block. And re-throw whatever error is caught const genClaims = grpcUtils.generatorDuplex(call, true); try { await sigchain.transaction(async (sigchain) => { @@ -149,9 +150,7 @@ function nodesCrossSignClaim({ senderPublicKey, )); if (!verifiedDoubly) { - await genClaims.throw( - new claimsErrors.ErrorDoublySignedClaimVerificationFailed(), - ); + throw new claimsErrors.ErrorDoublySignedClaimVerificationFailed(); } // If verified, then we can safely add to our sigchain await sigchain.addExistingClaim(constructedDoublySignedClaim); @@ -161,8 +160,7 @@ function nodesCrossSignClaim({ }); } catch (e) { await genClaims.throw(e); - // TODO: Handle the exception on this server - throw e? - // throw e; + logger.error(e); return; } }; diff --git a/src/agent/service/nodesHolePunchMessageSend.ts b/src/agent/service/nodesHolePunchMessageSend.ts index 2196cceec..438af3775 100644 --- a/src/agent/service/nodesHolePunchMessageSend.ts +++ b/src/agent/service/nodesHolePunchMessageSend.ts @@ -3,6 +3,7 @@ import type { NodeManager, NodeConnectionManager } from '../../nodes'; import type KeyManager from '../../keys/KeyManager'; import type { NodeId } from '../../nodes/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import type Logger from '@matrixai/logger'; import * as networkUtils from '../../network/utils'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; @@ -13,10 +14,12 @@ function nodesHolePunchMessageSend({ keyManager, nodeManager, nodeConnectionManager, + logger, }: { keyManager: KeyManager; nodeManager: NodeManager; nodeConnectionManager: NodeConnectionManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -63,6 +66,7 @@ function nodesHolePunchMessageSend({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); + logger.error(e); return; } }; diff --git a/src/agent/service/notificationsSend.ts b/src/agent/service/notificationsSend.ts index d942da04e..f11a18c95 100644 --- a/src/agent/service/notificationsSend.ts +++ b/src/agent/service/notificationsSend.ts @@ -1,14 +1,17 @@ import type * as grpc from '@grpc/grpc-js'; import type { NotificationsManager } from '../../notifications'; import type * as notificationsPB from '../../proto/js/polykey/v1/notifications/notifications_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { utils as notificationsUtils } from '../../notifications'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function notificationsSend({ notificationsManager, + logger, }: { notificationsManager: NotificationsManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall< @@ -26,6 +29,7 @@ function notificationsSend({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); + logger.error(e); return; } }; diff --git a/src/agent/service/vaultsGitInfoGet.ts b/src/agent/service/vaultsGitInfoGet.ts index 1a043f92b..6f4ae9873 100644 --- a/src/agent/service/vaultsGitInfoGet.ts +++ b/src/agent/service/vaultsGitInfoGet.ts @@ -2,6 +2,7 @@ import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type ACL from '../../acl/ACL'; import type { ConnectionInfoGet } from '../../agent/types'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsUtils from '../../vaults/utils'; @@ -14,80 +15,81 @@ import * as agentErrors from '../errors'; function vaultsGitInfoGet({ vaultManager, acl, + logger, connectionInfoGet, }: { vaultManager: VaultManager; acl: ACL; + logger: Logger; connectionInfoGet: ConnectionInfoGet; }) { return async ( call: grpc.ServerWritableStream, ): Promise => { const genWritable = grpcUtils.generatorWritable(call, true); - const request = call.request; - const vaultMessage = request.getVault(); - if (vaultMessage == null) { - await genWritable.throw({ code: grpc.status.NOT_FOUND }); - return; - } - let vaultName; - const vaultNameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(vaultNameOrId as VaultName); - vaultName = vaultNameOrId; - if (vaultId == null) { - try { - vaultId = validationUtils.parseVaultId(vaultNameOrId); - vaultName = (await vaultManager.getVaultMeta(vaultId))?.vaultName; - } catch (err) { - await genWritable.throw(new vaultsErrors.ErrorVaultsVaultUndefined()); - return; + try { + const request = call.request; + const vaultMessage = request.getVault(); + if (vaultMessage == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); } - } - // Getting the NodeId from the ReverseProxy connection info - const connectionInfo = connectionInfoGet(call); - // If this is getting run the connection exists - // It SHOULD exist here - if (connectionInfo == null) { - throw new agentErrors.ErrorConnectionInfoMissing(); - } - const nodeId = connectionInfo.remoteNodeId; - const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); - const actionType = validationUtils.parseVaultAction(request.getAction()); - const permissions = await acl.getNodePerm(nodeId); - if (permissions == null) { - await genWritable.throw( - new vaultsErrors.ErrorVaultsPermissionDenied( + let vaultName; + const vaultNameOrId = vaultMessage.getNameOrId(); + let vaultId = await vaultManager.getVaultId(vaultNameOrId as VaultName); + vaultName = vaultNameOrId; + if (vaultId == null) { + try { + vaultId = validationUtils.parseVaultId(vaultNameOrId); + vaultName = (await vaultManager.getVaultMeta(vaultId))?.vaultName; + } catch (e) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(e.message, { + cause: e, + }); + } + } + // Getting the NodeId from the ReverseProxy connection info + const connectionInfo = connectionInfoGet(call); + // If this is getting run the connection exists + // It SHOULD exist here + if (connectionInfo == null) { + throw new agentErrors.ErrorConnectionInfoMissing(); + } + const nodeId = connectionInfo.remoteNodeId; + const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); + const actionType = validationUtils.parseVaultAction(request.getAction()); + const permissions = await acl.getNodePerm(nodeId); + if (permissions == null) { + throw new vaultsErrors.ErrorVaultsPermissionDenied( `No permissions found for ${nodeIdEncoded}`, - ), - ); - return; - } - const vaultPerms = permissions.vaults[vaultId]; - if (vaultPerms?.[actionType] !== null) { - await genWritable.throw( - new vaultsErrors.ErrorVaultsPermissionDenied( + ); + } + const vaultPerms = permissions.vaults[vaultId]; + if (vaultPerms?.[actionType] !== null) { + throw new vaultsErrors.ErrorVaultsPermissionDenied( `${nodeIdEncoded} does not have permission to ${actionType} from vault ${vaultsUtils.encodeVaultId( vaultId, )}`, - ), - ); - return; - } - const meta = new grpc.Metadata(); - meta.set('vaultName', vaultName); - meta.set('vaultId', vaultsUtils.encodeVaultId(vaultId)); - genWritable.stream.sendMetadata(meta); - const response = new vaultsPB.PackChunk(); - const responseGen = vaultManager.handleInfoRequest(vaultId); - for await (const byte of responseGen) { - if (byte !== null) { - response.setChunk(byte); - await genWritable.next(response); - } else { - await genWritable.next(null); + ); + } + const meta = new grpc.Metadata(); + meta.set('vaultName', vaultName); + meta.set('vaultId', vaultsUtils.encodeVaultId(vaultId)); + genWritable.stream.sendMetadata(meta); + const response = new vaultsPB.PackChunk(); + const responseGen = vaultManager.handleInfoRequest(vaultId); + for await (const byte of responseGen) { + if (byte !== null) { + response.setChunk(byte); + await genWritable.next(response); + } else { + await genWritable.next(null); + } } + await genWritable.next(null); + } catch (e) { + await genWritable.throw(e); + logger.error(e); } - await genWritable.next(null); }; } diff --git a/src/agent/service/vaultsGitPackGet.ts b/src/agent/service/vaultsGitPackGet.ts index 8c0d9232f..e96398529 100644 --- a/src/agent/service/vaultsGitPackGet.ts +++ b/src/agent/service/vaultsGitPackGet.ts @@ -3,6 +3,7 @@ import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type { ConnectionInfoGet } from '../../agent/types'; import type ACL from '../../acl/ACL'; +import type Logger from '@matrixai/logger'; import * as nodesUtils from '../../nodes/utils'; import * as grpcErrors from '../../grpc/errors'; import * as grpcUtils from '../../grpc/utils'; @@ -15,86 +16,87 @@ import * as agentErrors from '../errors'; function vaultsGitPackGet({ vaultManager, acl, + logger, connectionInfoGet, }: { vaultManager: VaultManager; acl: ACL; + logger: Logger; connectionInfoGet: ConnectionInfoGet; }) { return async ( call: grpc.ServerDuplexStream, - ) => { + ): Promise => { const genDuplex = grpcUtils.generatorDuplex(call, true); - const clientBodyBuffers: Uint8Array[] = []; - const clientRequest = (await genDuplex.read()).value; - clientBodyBuffers.push(clientRequest!.getChunk_asU8()); - const body = Buffer.concat(clientBodyBuffers); - const meta = call.metadata; - // Getting the NodeId from the ReverseProxy connection info - const connectionInfo = connectionInfoGet(call); - // If this is getting run the connection exists - // It SHOULD exist here - if (connectionInfo == null) { - throw new agentErrors.ErrorConnectionInfoMissing(); - } - const nodeId = connectionInfo.remoteNodeId; - const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); - // Getting vaultId - const vaultNameOrId = meta.get('vaultNameOrId').pop()!.toString(); - if (vaultNameOrId == null) { - throw new grpcErrors.ErrorGRPC('vault-name not in metadata'); - } - let vaultId = await vaultManager.getVaultId(vaultNameOrId as VaultName); - vaultId = vaultId ?? vaultsUtils.decodeVaultId(vaultNameOrId); - if (vaultId == null) { - await genDuplex.throw( + try { + const clientBodyBuffers: Uint8Array[] = []; + const clientRequest = (await genDuplex.read()).value; + clientBodyBuffers.push(clientRequest!.getChunk_asU8()); + const body = Buffer.concat(clientBodyBuffers); + const meta = call.metadata; + // Getting the NodeId from the ReverseProxy connection info + const connectionInfo = connectionInfoGet(call); + // If this is getting run the connection exists + // It SHOULD exist here + if (connectionInfo == null) { + throw new agentErrors.ErrorConnectionInfoMissing(); + } + const nodeId = connectionInfo.remoteNodeId; + const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); + // Getting vaultId + const vaultNameOrId = meta.get('vaultNameOrId').pop()!.toString(); + if (vaultNameOrId == null) { + throw new grpcErrors.ErrorGRPC('vault-name not in metadata'); + } + let vaultId = await vaultManager.getVaultId(vaultNameOrId as VaultName); + vaultId = vaultId ?? vaultsUtils.decodeVaultId(vaultNameOrId); + if (vaultId == null) { // Throwing permission error to hide information about vaults existence - new vaultsErrors.ErrorVaultsPermissionDenied( + throw new vaultsErrors.ErrorVaultsPermissionDenied( `No permissions found for ${nodeIdEncoded}`, - ), + ); + } + // Checking permissions + const permissions = await acl.getNodePerm(nodeId); + const vaultPerms = permissions?.vaults[vaultId]; + const actionType = validationUtils.parseVaultAction( + meta.get('vaultAction').pop(), ); - return; - } - // Checking permissions - const permissions = await acl.getNodePerm(nodeId); - const vaultPerms = permissions?.vaults[vaultId]; - const actionType = validationUtils.parseVaultAction( - meta.get('vaultAction').pop(), - ); - if (vaultPerms?.[actionType] !== null) { - await genDuplex.throw( - new vaultsErrors.ErrorVaultsPermissionDenied( + if (vaultPerms?.[actionType] !== null) { + throw new vaultsErrors.ErrorVaultsPermissionDenied( `${nodeIdEncoded} does not have permission to ${actionType} from vault ${vaultsUtils.encodeVaultId( vaultId, )}`, - ), + ); + } + const response = new vaultsPB.PackChunk(); + const [sideBand, progressStream] = await vaultManager.handlePackRequest( + vaultId, + Buffer.from(body), ); - return; - } - const response = new vaultsPB.PackChunk(); - const [sideBand, progressStream] = await vaultManager.handlePackRequest( - vaultId, - Buffer.from(body), - ); - response.setChunk(Buffer.from('0008NAK\n')); - await genDuplex.write(response); - const responseBuffers: Uint8Array[] = []; - await new Promise((resolve, reject) => { - sideBand.on('data', async (data: Uint8Array) => { - responseBuffers.push(data); + response.setChunk(Buffer.from('0008NAK\n')); + await genDuplex.write(response); + const responseBuffers: Uint8Array[] = []; + await new Promise((resolve, reject) => { + sideBand.on('data', async (data: Uint8Array) => { + responseBuffers.push(data); + }); + sideBand.on('end', async () => { + response.setChunk(Buffer.concat(responseBuffers)); + await genDuplex.write(response); + resolve(); + }); + sideBand.on('error', (err) => { + reject(err); + }); + progressStream.write(Buffer.from('0014progress is at 50%\n')); + progressStream.end(); }); - sideBand.on('end', async () => { - response.setChunk(Buffer.concat(responseBuffers)); - await genDuplex.write(response); - resolve(); - }); - sideBand.on('error', (err) => { - reject(err); - }); - progressStream.write(Buffer.from('0014progress is at 50%\n')); - progressStream.end(); - }); - await genDuplex.next(null); + await genDuplex.next(null); + } catch (e) { + await genDuplex.throw(e); + logger.error(e); + } }; } diff --git a/src/agent/service/vaultsScan.ts b/src/agent/service/vaultsScan.ts index acdcfb0b1..bd7cb004b 100644 --- a/src/agent/service/vaultsScan.ts +++ b/src/agent/service/vaultsScan.ts @@ -2,6 +2,7 @@ import type * as grpc from '@grpc/grpc-js'; import type VaultManager from '../../vaults/VaultManager'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type { ConnectionInfoGet } from '../../agent/types'; +import type Logger from '@matrixai/logger'; import * as agentErrors from '../../agent/errors'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import * as vaultsUtils from '../../vaults/utils'; @@ -9,9 +10,11 @@ import * as grpcUtils from '../../grpc/utils'; function vaultsScan({ vaultManager, + logger, connectionInfoGet, }: { vaultManager: VaultManager; + logger: Logger; connectionInfoGet: ConnectionInfoGet; }) { return async ( @@ -42,6 +45,7 @@ function vaultsScan({ await genWritable.next(null); } catch (e) { await genWritable.throw(e); + logger.error(e); } }; } diff --git a/src/bin/nodes/CommandPing.ts b/src/bin/nodes/CommandPing.ts index 11913011a..3ff6049a1 100644 --- a/src/bin/nodes/CommandPing.ts +++ b/src/bin/nodes/CommandPing.ts @@ -59,7 +59,8 @@ class CommandPing extends CommandPolykey { error = new binErrors.ErrorNodePingFailed( `Failed to resolve node ID ${nodesUtils.encodeNodeId( nodeId, - )} to an address.`, { cause: err }, + )} to an address.`, + { cause: err }, ); } else { throw err; diff --git a/src/claims/errors.ts b/src/claims/errors.ts index 9685201f8..95b03c74a 100644 --- a/src/claims/errors.ts +++ b/src/claims/errors.ts @@ -85,16 +85,12 @@ class ErrorDoublySignedClaimNumSignatures extends ErrorSchemaValidate { exitCode = sysexits.CONFIG; } -class ErrorSinglySignedClaimValidationFailed< - T, -> extends ErrorSchemaValidate { +class ErrorSinglySignedClaimValidationFailed extends ErrorSchemaValidate { static description = 'Claim data does not match schema'; exitCode = sysexits.CONFIG; } -class ErrorDoublySignedClaimValidationFailed< - T, -> extends ErrorSchemaValidate { +class ErrorDoublySignedClaimValidationFailed extends ErrorSchemaValidate { static description = 'Claim data does not match schema'; exitCode = sysexits.CONFIG; } diff --git a/src/client/service/agentLockAll.ts b/src/client/service/agentLockAll.ts index dd80ebf62..6f7eaba76 100644 --- a/src/client/service/agentLockAll.ts +++ b/src/client/service/agentLockAll.ts @@ -1,15 +1,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { SessionManager } from '../../sessions'; +import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function agentLockAll({ - sessionManager, authenticate, + sessionManager, + logger, }: { - sessionManager: SessionManager; authenticate: Authenticate; + sessionManager: SessionManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -24,6 +27,7 @@ function agentLockAll({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/agentStatus.ts b/src/client/service/agentStatus.ts index e90042ebd..ecac4e1c1 100644 --- a/src/client/service/agentStatus.ts +++ b/src/client/service/agentStatus.ts @@ -4,6 +4,7 @@ import type KeyManager from '../../keys/KeyManager'; import type GRPCServer from '../../grpc/GRPCServer'; import type Proxy from '../../network/Proxy'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import type Logger from '@matrixai/logger'; import process from 'process'; import * as grpcUtils from '../../grpc/utils'; import * as nodesUtils from '../../nodes/utils'; @@ -15,12 +16,14 @@ function agentStatus({ grpcServerClient, grpcServerAgent, proxy, + logger, }: { authenticate: Authenticate; keyManager: KeyManager; grpcServerClient: GRPCServer; grpcServerAgent: GRPCServer; proxy: Proxy; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -46,6 +49,7 @@ function agentStatus({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/agentStop.ts b/src/client/service/agentStop.ts index 6f0c83bdc..f359036b8 100644 --- a/src/client/service/agentStop.ts +++ b/src/client/service/agentStop.ts @@ -1,6 +1,7 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type PolykeyAgent from '../../PolykeyAgent'; +import type Logger from '@matrixai/logger'; import { status, running } from '@matrixai/async-init'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; @@ -8,9 +9,11 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function agentStop({ authenticate, pkAgent, + logger, }: { authenticate: Authenticate; pkAgent: PolykeyAgent; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -29,6 +32,7 @@ function agentStop({ callback(null, response); } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } // Stop is called after GRPC resources are cleared diff --git a/src/client/service/agentUnlock.ts b/src/client/service/agentUnlock.ts index a3ff33ddd..1814eb81a 100644 --- a/src/client/service/agentUnlock.ts +++ b/src/client/service/agentUnlock.ts @@ -1,9 +1,16 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; +import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; -function agentUnlock({ authenticate }: { authenticate: Authenticate }) { +function agentUnlock({ + authenticate, + logger, +}: { + authenticate: Authenticate; + logger: Logger; +}) { return async ( call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData, @@ -16,6 +23,7 @@ function agentUnlock({ authenticate }: { authenticate: Authenticate }) { return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsGetByIdentity.ts b/src/client/service/gestaltsActionsGetByIdentity.ts index c4df02f2c..3ec511381 100644 --- a/src/client/service/gestaltsActionsGetByIdentity.ts +++ b/src/client/service/gestaltsActionsGetByIdentity.ts @@ -3,6 +3,7 @@ import type { Authenticate } from '../types'; import type { GestaltGraph } from '../../gestalts'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; @@ -11,9 +12,11 @@ import * as permissionsPB from '../../proto/js/polykey/v1/permissions/permission function gestaltsActionsGetByIdentity({ authenticate, gestaltGraph, + logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -55,6 +58,7 @@ function gestaltsActionsGetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsGetByNode.ts b/src/client/service/gestaltsActionsGetByNode.ts index f4bcd4d5a..77b6c54fd 100644 --- a/src/client/service/gestaltsActionsGetByNode.ts +++ b/src/client/service/gestaltsActionsGetByNode.ts @@ -3,6 +3,7 @@ import type { Authenticate } from '../types'; import type { NodeId } from '../../nodes/types'; import type { GestaltGraph } from '../../gestalts'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; @@ -11,9 +12,11 @@ import * as permissionsPB from '../../proto/js/polykey/v1/permissions/permission function gestaltsActionsGetByNode({ authenticate, gestaltGraph, + logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -47,6 +50,7 @@ function gestaltsActionsGetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsSetByIdentity.ts b/src/client/service/gestaltsActionsSetByIdentity.ts index 0a7637876..34140fec9 100644 --- a/src/client/service/gestaltsActionsSetByIdentity.ts +++ b/src/client/service/gestaltsActionsSetByIdentity.ts @@ -4,6 +4,7 @@ import type { GestaltGraph } from '../../gestalts'; import type { GestaltAction } from '../../gestalts/types'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; @@ -12,9 +13,11 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function gestaltsActionsSetByIdentity({ authenticate, gestaltGraph, + logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -56,6 +59,7 @@ function gestaltsActionsSetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsSetByNode.ts b/src/client/service/gestaltsActionsSetByNode.ts index f7e2e22fc..0c801c350 100644 --- a/src/client/service/gestaltsActionsSetByNode.ts +++ b/src/client/service/gestaltsActionsSetByNode.ts @@ -4,6 +4,7 @@ import type { GestaltGraph } from '../../gestalts'; import type { GestaltAction } from '../../gestalts/types'; import type { NodeId } from '../../nodes/types'; import type * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; @@ -12,9 +13,11 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function gestaltsActionsSetByNode({ authenticate, gestaltGraph, + logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -43,6 +46,7 @@ function gestaltsActionsSetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsUnsetByIdentity.ts b/src/client/service/gestaltsActionsUnsetByIdentity.ts index a247babd8..9ab5ac61e 100644 --- a/src/client/service/gestaltsActionsUnsetByIdentity.ts +++ b/src/client/service/gestaltsActionsUnsetByIdentity.ts @@ -4,6 +4,7 @@ import type { GestaltGraph } from '../../gestalts'; import type { GestaltAction } from '../../gestalts/types'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; @@ -12,9 +13,11 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function gestaltsActionsUnsetByIdentity({ authenticate, gestaltGraph, + logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -56,6 +59,7 @@ function gestaltsActionsUnsetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsUnsetByNode.ts b/src/client/service/gestaltsActionsUnsetByNode.ts index 0add07203..795f9c4fc 100644 --- a/src/client/service/gestaltsActionsUnsetByNode.ts +++ b/src/client/service/gestaltsActionsUnsetByNode.ts @@ -4,6 +4,7 @@ import type { GestaltGraph } from '../../gestalts'; import type { GestaltAction } from '../../gestalts/types'; import type { NodeId } from '../../nodes/types'; import type * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; @@ -12,9 +13,11 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function gestaltsActionsUnsetByNode({ authenticate, gestaltGraph, + logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -43,6 +46,7 @@ function gestaltsActionsUnsetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsDiscoveryByIdentity.ts b/src/client/service/gestaltsDiscoveryByIdentity.ts index 4ebeae0ce..c8e515ab7 100644 --- a/src/client/service/gestaltsDiscoveryByIdentity.ts +++ b/src/client/service/gestaltsDiscoveryByIdentity.ts @@ -3,6 +3,7 @@ import type { Authenticate } from '../types'; import type { Discovery } from '../../discovery'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import type Logger from '@matrixai/logger'; import { validateSync } from '../../validation'; import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; @@ -12,9 +13,11 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function gestaltsDiscoveryByIdentity({ authenticate, discovery, + logger, }: { authenticate: Authenticate; discovery: Discovery; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -48,6 +51,7 @@ function gestaltsDiscoveryByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsDiscoveryByNode.ts b/src/client/service/gestaltsDiscoveryByNode.ts index c8f900141..26e575c51 100644 --- a/src/client/service/gestaltsDiscoveryByNode.ts +++ b/src/client/service/gestaltsDiscoveryByNode.ts @@ -3,6 +3,7 @@ import type { Authenticate } from '../types'; import type { Discovery } from '../../discovery'; import type { NodeId } from '../../nodes/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import type Logger from '@matrixai/logger'; import { validateSync } from '../../validation'; import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; @@ -12,9 +13,11 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function gestaltsDiscoveryByNode({ authenticate, discovery, + logger, }: { authenticate: Authenticate; discovery: Discovery; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -44,6 +47,7 @@ function gestaltsDiscoveryByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltGetByIdentity.ts b/src/client/service/gestaltsGestaltGetByIdentity.ts index 357761c11..5f2257a82 100644 --- a/src/client/service/gestaltsGestaltGetByIdentity.ts +++ b/src/client/service/gestaltsGestaltGetByIdentity.ts @@ -3,6 +3,7 @@ import type { Authenticate } from '../types'; import type { GestaltGraph } from '../../gestalts'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; @@ -11,9 +12,11 @@ import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; function gestaltsGestaltGetByIdentity({ authenticate, gestaltGraph, + logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -53,6 +56,7 @@ function gestaltsGestaltGetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltGetByNode.ts b/src/client/service/gestaltsGestaltGetByNode.ts index 424ad0f65..a0ea6f03c 100644 --- a/src/client/service/gestaltsGestaltGetByNode.ts +++ b/src/client/service/gestaltsGestaltGetByNode.ts @@ -3,6 +3,7 @@ import type { Authenticate } from '../types'; import type { NodeId } from '../../nodes/types'; import type { GestaltGraph } from '../../gestalts'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; @@ -11,9 +12,11 @@ import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; function gestaltsGestaltGetByNode({ authenticate, gestaltGraph, + logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -46,6 +49,7 @@ function gestaltsGestaltGetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltList.ts b/src/client/service/gestaltsGestaltList.ts index 6f3c1c9ea..305cd3b7d 100644 --- a/src/client/service/gestaltsGestaltList.ts +++ b/src/client/service/gestaltsGestaltList.ts @@ -3,15 +3,18 @@ import type { Authenticate } from '../types'; import type { GestaltGraph } from '../../gestalts'; import type { Gestalt } from '../../gestalts/types'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; function gestaltsGestaltList({ authenticate, gestaltGraph, + logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + logger: Logger; }) { return async ( call: grpc.ServerWritableStream, @@ -31,6 +34,7 @@ function gestaltsGestaltList({ return; } catch (e) { await genWritable.throw(e); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltTrustByIdentity.ts b/src/client/service/gestaltsGestaltTrustByIdentity.ts index 754364f79..df7b60dc4 100644 --- a/src/client/service/gestaltsGestaltTrustByIdentity.ts +++ b/src/client/service/gestaltsGestaltTrustByIdentity.ts @@ -4,6 +4,7 @@ import type { GestaltGraph } from '../../gestalts'; import type { IdentityId, ProviderId } from '../../identities/types'; import type { Discovery } from '../../discovery'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import type Logger from '@matrixai/logger'; import { validateSync } from '../../validation'; import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; @@ -14,10 +15,12 @@ function gestaltsGestaltTrustByIdentity({ authenticate, gestaltGraph, discovery, + logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; discovery: Discovery; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -70,6 +73,7 @@ function gestaltsGestaltTrustByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltTrustByNode.ts b/src/client/service/gestaltsGestaltTrustByNode.ts index b8f03fb87..8ebe7660b 100644 --- a/src/client/service/gestaltsGestaltTrustByNode.ts +++ b/src/client/service/gestaltsGestaltTrustByNode.ts @@ -4,6 +4,7 @@ import type { GestaltGraph } from '../../gestalts'; import type { Discovery } from '../../discovery'; import type { NodeId } from '../../nodes/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import type Logger from '@matrixai/logger'; import { validateSync } from '../../validation'; import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; @@ -15,10 +16,12 @@ function gestaltsGestaltTrustByNode({ authenticate, gestaltGraph, discovery, + logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; discovery: Discovery; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -58,6 +61,7 @@ function gestaltsGestaltTrustByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/identitiesAuthenticate.ts b/src/client/service/identitiesAuthenticate.ts index c80378790..e2e39162f 100644 --- a/src/client/service/identitiesAuthenticate.ts +++ b/src/client/service/identitiesAuthenticate.ts @@ -2,6 +2,7 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { IdentitiesManager } from '../../identities'; import type { ProviderId } from '../../identities/types'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { errors as identitiesErrors } from '../../identities'; import { validateSync, utils as validationUtils } from '../../validation'; @@ -9,11 +10,13 @@ import { matchSync, never } from '../../utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; function identitiesAuthenticate({ - identitiesManager, authenticate, + identitiesManager, + logger, }: { - identitiesManager: IdentitiesManager; authenticate: Authenticate; + identitiesManager: IdentitiesManager; + logger: Logger; }) { return async ( call: grpc.ServerWritableStream< @@ -70,6 +73,7 @@ function identitiesAuthenticate({ return; } catch (e) { await genWritable.throw(e); + logger.error(e); return; } }; diff --git a/src/client/service/identitiesAuthenticatedGet.ts b/src/client/service/identitiesAuthenticatedGet.ts index fa2ca756f..d344c14a6 100644 --- a/src/client/service/identitiesAuthenticatedGet.ts +++ b/src/client/service/identitiesAuthenticatedGet.ts @@ -2,6 +2,7 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { IdentitiesManager } from '../../identities'; import type { ProviderId } from '../../identities/types'; +import type Logger from '@matrixai/logger'; import { validateSync } from '../../validation'; import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; @@ -9,11 +10,13 @@ import * as validationUtils from '../../validation/utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; function identitiesAuthenticatedGet({ - identitiesManager, authenticate, + identitiesManager, + logger, }: { - identitiesManager: IdentitiesManager; authenticate: Authenticate; + identitiesManager: IdentitiesManager; + logger: Logger; }) { return async ( call: grpc.ServerWritableStream< @@ -60,6 +63,7 @@ function identitiesAuthenticatedGet({ return; } catch (e) { await genWritable.throw(e); + logger.error(e); return; } }; diff --git a/src/client/service/identitiesClaim.ts b/src/client/service/identitiesClaim.ts index 0964ecf78..2367998df 100644 --- a/src/client/service/identitiesClaim.ts +++ b/src/client/service/identitiesClaim.ts @@ -4,6 +4,7 @@ import type KeyManager from '../../keys/KeyManager'; import type { Sigchain } from '../../sigchain'; import type { IdentitiesManager } from '../../identities'; import type { IdentityId, ProviderId } from '../../identities/types'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { utils as claimsUtils } from '../../claims'; import { utils as nodesUtils } from '../../nodes'; @@ -16,15 +17,17 @@ import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_p * Augments the keynode with a new identity. */ function identitiesClaim({ + authenticate, identitiesManager, sigchain, keyManager, - authenticate, + logger, }: { + authenticate: Authenticate; identitiesManager: IdentitiesManager; sigchain: Sigchain; keyManager: KeyManager; - authenticate: Authenticate; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -80,6 +83,7 @@ function identitiesClaim({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/identitiesInfoConnectedGet.ts b/src/client/service/identitiesInfoConnectedGet.ts index 865616d06..f232e3a4d 100644 --- a/src/client/service/identitiesInfoConnectedGet.ts +++ b/src/client/service/identitiesInfoConnectedGet.ts @@ -6,6 +6,7 @@ import type { IdentityId, ProviderId, } from '../../identities/types'; +import type Logger from '@matrixai/logger'; import { validateSync } from '../../validation'; import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; @@ -14,11 +15,13 @@ import * as identitiesErrors from '../../identities/errors'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; function identitiesInfoConnectedGet({ - identitiesManager, authenticate, + identitiesManager, + logger, }: { - identitiesManager: IdentitiesManager; authenticate: Authenticate; + identitiesManager: IdentitiesManager; + logger: Logger; }) { return async ( call: grpc.ServerWritableStream< @@ -116,6 +119,7 @@ function identitiesInfoConnectedGet({ return; } catch (e) { await genWritable.throw(e); + logger.error(e); return; } }; diff --git a/src/client/service/identitiesInfoGet.ts b/src/client/service/identitiesInfoGet.ts index 400367140..31a8139c8 100644 --- a/src/client/service/identitiesInfoGet.ts +++ b/src/client/service/identitiesInfoGet.ts @@ -6,6 +6,7 @@ import type { IdentityId, ProviderId, } from '../../identities/types'; +import type Logger from '@matrixai/logger'; import { validateSync } from '../../validation'; import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; @@ -15,11 +16,13 @@ import * as identitiesErrors from '../../identities/errors'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; function identitiesInfoGet({ - identitiesManager, authenticate, + identitiesManager, + logger, }: { - identitiesManager: IdentitiesManager; authenticate: Authenticate; + identitiesManager: IdentitiesManager; + logger: Logger; }) { return async ( call: grpc.ServerWritableStream< @@ -109,6 +112,7 @@ function identitiesInfoGet({ return; } catch (e) { await genWritable.throw(e); + logger.error(e); return; } }; diff --git a/src/client/service/identitiesProvidersList.ts b/src/client/service/identitiesProvidersList.ts index a7ce51051..8fa533a9c 100644 --- a/src/client/service/identitiesProvidersList.ts +++ b/src/client/service/identitiesProvidersList.ts @@ -2,15 +2,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { IdentitiesManager } from '../../identities'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; function identitiesProvidersList({ - identitiesManager, authenticate, + identitiesManager, + logger, }: { - identitiesManager: IdentitiesManager; authenticate: Authenticate; + identitiesManager: IdentitiesManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -26,6 +29,7 @@ function identitiesProvidersList({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/identitiesTokenDelete.ts b/src/client/service/identitiesTokenDelete.ts index 835fee428..69bba5775 100644 --- a/src/client/service/identitiesTokenDelete.ts +++ b/src/client/service/identitiesTokenDelete.ts @@ -3,17 +3,20 @@ import type { Authenticate } from '../types'; import type { IdentitiesManager } from '../../identities'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function identitiesTokenDelete({ - identitiesManager, authenticate, + identitiesManager, + logger, }: { - identitiesManager: IdentitiesManager; authenticate: Authenticate; + identitiesManager: IdentitiesManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -47,6 +50,7 @@ function identitiesTokenDelete({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/identitiesTokenGet.ts b/src/client/service/identitiesTokenGet.ts index 102ae3a07..cb7987156 100644 --- a/src/client/service/identitiesTokenGet.ts +++ b/src/client/service/identitiesTokenGet.ts @@ -2,17 +2,20 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { IdentitiesManager } from '../../identities'; import type { IdentityId, ProviderId } from '../../identities/types'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; function identitiesTokenGet({ - identitiesManager, authenticate, + identitiesManager, + logger, }: { - identitiesManager: IdentitiesManager; authenticate: Authenticate; + identitiesManager: IdentitiesManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -47,6 +50,7 @@ function identitiesTokenGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/identitiesTokenPut.ts b/src/client/service/identitiesTokenPut.ts index 1a371cb95..cb532d4c1 100644 --- a/src/client/service/identitiesTokenPut.ts +++ b/src/client/service/identitiesTokenPut.ts @@ -3,17 +3,20 @@ import type { Authenticate } from '../types'; import type { IdentitiesManager } from '../../identities'; import type { IdentityId, ProviderId, TokenData } from '../../identities/types'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function identitiesTokenPut({ - identitiesManager, authenticate, + identitiesManager, + logger, }: { - identitiesManager: IdentitiesManager; authenticate: Authenticate; + identitiesManager: IdentitiesManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall< @@ -52,6 +55,7 @@ function identitiesTokenPut({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/keysCertsChainGet.ts b/src/client/service/keysCertsChainGet.ts index 792b86916..b62c85783 100644 --- a/src/client/service/keysCertsChainGet.ts +++ b/src/client/service/keysCertsChainGet.ts @@ -2,15 +2,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { KeyManager } from '../../keys'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysCertsChainGet({ - keyManager, authenticate, + keyManager, + logger, }: { - keyManager: KeyManager; authenticate: Authenticate; + keyManager: KeyManager; + logger: Logger; }) { return async ( call: grpc.ServerWritableStream, @@ -30,6 +33,7 @@ function keysCertsChainGet({ return; } catch (e) { await genWritable.throw(e); + logger.error(e); return; } }; diff --git a/src/client/service/keysCertsGet.ts b/src/client/service/keysCertsGet.ts index 198a67884..6d63cfba8 100644 --- a/src/client/service/keysCertsGet.ts +++ b/src/client/service/keysCertsGet.ts @@ -2,15 +2,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { KeyManager } from '../../keys'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysCertsGet({ - keyManager, authenticate, + keyManager, + logger, }: { - keyManager: KeyManager; authenticate: Authenticate; + keyManager: KeyManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -26,6 +29,7 @@ function keysCertsGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/keysDecrypt.ts b/src/client/service/keysDecrypt.ts index 0aa84d004..05e68e066 100644 --- a/src/client/service/keysDecrypt.ts +++ b/src/client/service/keysDecrypt.ts @@ -1,15 +1,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { KeyManager } from '../../keys'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysDecrypt({ - keyManager, authenticate, + keyManager, + logger, }: { - keyManager: KeyManager; authenticate: Authenticate; + keyManager: KeyManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -27,6 +30,7 @@ function keysDecrypt({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/keysEncrypt.ts b/src/client/service/keysEncrypt.ts index 8c048e94c..2c84444fb 100644 --- a/src/client/service/keysEncrypt.ts +++ b/src/client/service/keysEncrypt.ts @@ -1,15 +1,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { KeyManager } from '../../keys'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysEncrypt({ - keyManager, authenticate, + keyManager, + logger, }: { - keyManager: KeyManager; authenticate: Authenticate; + keyManager: KeyManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -27,6 +30,7 @@ function keysEncrypt({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/keysKeyPairRenew.ts b/src/client/service/keysKeyPairRenew.ts index ffcd9b5b4..c2d88acca 100644 --- a/src/client/service/keysKeyPairRenew.ts +++ b/src/client/service/keysKeyPairRenew.ts @@ -2,15 +2,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { KeyManager } from '../../keys'; import type * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function keysKeyPairRenew({ - keyManager, authenticate, + keyManager, + logger, }: { - keyManager: KeyManager; authenticate: Authenticate; + keyManager: KeyManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -27,6 +30,7 @@ function keysKeyPairRenew({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/keysKeyPairReset.ts b/src/client/service/keysKeyPairReset.ts index a5fee6145..82e73277e 100644 --- a/src/client/service/keysKeyPairReset.ts +++ b/src/client/service/keysKeyPairReset.ts @@ -2,15 +2,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { KeyManager } from '../../keys'; import type * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function keysKeyPairReset({ - keyManager, authenticate, + keyManager, + logger, }: { - keyManager: KeyManager; authenticate: Authenticate; + keyManager: KeyManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -27,6 +30,7 @@ function keysKeyPairReset({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/keysKeyPairRoot.ts b/src/client/service/keysKeyPairRoot.ts index 4a5858347..9f20b410b 100644 --- a/src/client/service/keysKeyPairRoot.ts +++ b/src/client/service/keysKeyPairRoot.ts @@ -2,15 +2,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { KeyManager } from '../../keys'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysKeyPairRoot({ - keyManager, authenticate, + keyManager, + logger, }: { - keyManager: KeyManager; authenticate: Authenticate; + keyManager: KeyManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -27,6 +30,7 @@ function keysKeyPairRoot({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/keysPasswordChange.ts b/src/client/service/keysPasswordChange.ts index 2d5074abf..21ad66425 100644 --- a/src/client/service/keysPasswordChange.ts +++ b/src/client/service/keysPasswordChange.ts @@ -2,15 +2,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { KeyManager } from '../../keys'; import type * as sessionsPB from '../../proto/js/polykey/v1/sessions/sessions_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function keysPasswordChange({ - keyManager, authenticate, + keyManager, + logger, }: { - keyManager: KeyManager; authenticate: Authenticate; + keyManager: KeyManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -25,6 +28,7 @@ function keysPasswordChange({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/keysSign.ts b/src/client/service/keysSign.ts index 5f2eee691..14f722a0c 100644 --- a/src/client/service/keysSign.ts +++ b/src/client/service/keysSign.ts @@ -1,15 +1,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { KeyManager } from '../../keys'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysSign({ - keyManager, authenticate, + keyManager, + logger, }: { - keyManager: KeyManager; authenticate: Authenticate; + keyManager: KeyManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -28,6 +31,7 @@ function keysSign({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/keysVerify.ts b/src/client/service/keysVerify.ts index 1090642c5..26918bc3d 100644 --- a/src/client/service/keysVerify.ts +++ b/src/client/service/keysVerify.ts @@ -2,15 +2,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { KeyManager } from '../../keys'; import type * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function keysVerify({ - keyManager, authenticate, + keyManager, + logger, }: { - keyManager: KeyManager; authenticate: Authenticate; + keyManager: KeyManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -29,6 +32,7 @@ function keysVerify({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/nodesAdd.ts b/src/client/service/nodesAdd.ts index 57924cd5e..7cbfb739f 100644 --- a/src/client/service/nodesAdd.ts +++ b/src/client/service/nodesAdd.ts @@ -4,6 +4,7 @@ import type { NodeManager } from '../../nodes'; import type { NodeId, NodeAddress } from '../../nodes/types'; import type { Host, Hostname, Port } from '../../network/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; @@ -15,11 +16,13 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; * of the passed ID or host/port. */ function nodesAdd({ - nodeManager, authenticate, + nodeManager, + logger, }: { - nodeManager: NodeManager; authenticate: Authenticate; + nodeManager: NodeManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -60,6 +63,7 @@ function nodesAdd({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/nodesClaim.ts b/src/client/service/nodesClaim.ts index 280dedb24..b82731c05 100644 --- a/src/client/service/nodesClaim.ts +++ b/src/client/service/nodesClaim.ts @@ -4,6 +4,7 @@ import type { NodeManager } from '../../nodes'; import type { NodeId } from '../../nodes/types'; import type { NotificationsManager } from '../../notifications'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; @@ -15,13 +16,15 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; * other node and host node. */ function nodesClaim({ + authenticate, nodeManager, notificationsManager, - authenticate, + logger, }: { + authenticate: Authenticate; nodeManager: NodeManager; notificationsManager: NotificationsManager; - authenticate: Authenticate; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -65,6 +68,7 @@ function nodesClaim({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/nodesFind.ts b/src/client/service/nodesFind.ts index 7982fd9ad..b8cb887db 100644 --- a/src/client/service/nodesFind.ts +++ b/src/client/service/nodesFind.ts @@ -2,6 +2,7 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { NodeConnectionManager } from '../../nodes'; import type { NodeId } from '../../nodes/types'; +import type Logger from '@matrixai/logger'; import { utils as nodesUtils } from '../../nodes'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; @@ -14,11 +15,13 @@ import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; * @throws ErrorNodeGraphNodeNotFound if node address cannot be found */ function nodesFind({ - nodeConnectionManager, authenticate, + nodeConnectionManager, + logger, }: { - nodeConnectionManager: NodeConnectionManager; authenticate: Authenticate; + nodeConnectionManager: NodeConnectionManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -53,6 +56,7 @@ function nodesFind({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/nodesPing.ts b/src/client/service/nodesPing.ts index 7dfd89939..2356f2072 100644 --- a/src/client/service/nodesPing.ts +++ b/src/client/service/nodesPing.ts @@ -3,6 +3,7 @@ import type { Authenticate } from '../types'; import type { NodeManager } from '../../nodes'; import type { NodeId } from '../../nodes/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { validateSync, utils as validationUtils } from '../../validation'; import { matchSync } from '../../utils'; @@ -12,11 +13,13 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; * Checks if a remote node is online. */ function nodesPing({ - nodeManager, authenticate, + nodeManager, + logger, }: { - nodeManager: NodeManager; authenticate: Authenticate; + nodeManager: NodeManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -47,6 +50,7 @@ function nodesPing({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/notificationsClear.ts b/src/client/service/notificationsClear.ts index 322f64cf6..7d2ba80cc 100644 --- a/src/client/service/notificationsClear.ts +++ b/src/client/service/notificationsClear.ts @@ -1,15 +1,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { NotificationsManager } from '../../notifications'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function notificationsClear({ - notificationsManager, authenticate, + notificationsManager, + logger, }: { - notificationsManager: NotificationsManager; authenticate: Authenticate; + notificationsManager: NotificationsManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -24,6 +27,7 @@ function notificationsClear({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/notificationsRead.ts b/src/client/service/notificationsRead.ts index e890ce6c0..f8bccc692 100644 --- a/src/client/service/notificationsRead.ts +++ b/src/client/service/notificationsRead.ts @@ -1,15 +1,18 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { NotificationsManager } from '../../notifications'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import * as notificationsPB from '../../proto/js/polykey/v1/notifications/notifications_pb'; function notificationsRead({ - notificationsManager, authenticate, + notificationsManager, + logger, }: { - notificationsManager: NotificationsManager; authenticate: Authenticate; + notificationsManager: NotificationsManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -65,6 +68,7 @@ function notificationsRead({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/notificationsSend.ts b/src/client/service/notificationsSend.ts index ed3b26e05..c30512611 100644 --- a/src/client/service/notificationsSend.ts +++ b/src/client/service/notificationsSend.ts @@ -3,6 +3,7 @@ import type { Authenticate } from '../types'; import type { NotificationsManager } from '../../notifications'; import type { NodeId } from '../../nodes/types'; import type * as notificationsPB from '../../proto/js/polykey/v1/notifications/notifications_pb'; +import type Logger from '@matrixai/logger'; import { utils as grpcUtils } from '../../grpc'; import { utils as notificationsUtils } from '../../notifications'; import { validateSync, utils as validationUtils } from '../../validation'; @@ -10,11 +11,13 @@ import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function notificationsSend({ - notificationsManager, authenticate, + notificationsManager, + logger, }: { - notificationsManager: NotificationsManager; authenticate: Authenticate; + notificationsManager: NotificationsManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -50,6 +53,7 @@ function notificationsSend({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsClone.ts b/src/client/service/vaultsClone.ts index a35d70e7f..75b6dcf56 100644 --- a/src/client/service/vaultsClone.ts +++ b/src/client/service/vaultsClone.ts @@ -1,6 +1,7 @@ import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; @@ -10,9 +11,11 @@ import * as vaultsUtils from '../../vaults/utils'; function vaultsClone({ authenticate, vaultManager, + logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -46,6 +49,7 @@ function vaultsClone({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsCreate.ts b/src/client/service/vaultsCreate.ts index 363e4a200..74224733b 100644 --- a/src/client/service/vaultsCreate.ts +++ b/src/client/service/vaultsCreate.ts @@ -3,16 +3,19 @@ import type { VaultId, VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsUtils from '../../vaults/utils'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; function vaultsCreate({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -31,6 +34,7 @@ function vaultsCreate({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsDelete.ts b/src/client/service/vaultsDelete.ts index d2f029c4a..0f7aa01e7 100644 --- a/src/client/service/vaultsDelete.ts +++ b/src/client/service/vaultsDelete.ts @@ -3,16 +3,19 @@ import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import * as validationUtils from '../../validation/utils'; function vaultsDelete({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -32,6 +35,7 @@ function vaultsDelete({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsList.ts b/src/client/service/vaultsList.ts index c35f51eea..794c44909 100644 --- a/src/client/service/vaultsList.ts +++ b/src/client/service/vaultsList.ts @@ -2,16 +2,19 @@ import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsUtils from '../../vaults/utils'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; function vaultsList({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerWritableStream, @@ -34,6 +37,7 @@ function vaultsList({ return; } catch (e) { await genWritable.throw(e); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsLog.ts b/src/client/service/vaultsLog.ts index 02b35a6f8..6d720e825 100644 --- a/src/client/service/vaultsLog.ts +++ b/src/client/service/vaultsLog.ts @@ -1,6 +1,7 @@ import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb'; import * as grpcUtils from '../../grpc/utils'; @@ -8,11 +9,13 @@ import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import * as validationUtils from '../../validation/utils'; function vaultsLog({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerWritableStream, @@ -52,6 +55,7 @@ function vaultsLog({ return; } catch (e) { await genWritable.throw(e); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsPermissionGet.ts b/src/client/service/vaultsPermissionGet.ts index bb2b24dc1..8dd0866c3 100644 --- a/src/client/service/vaultsPermissionGet.ts +++ b/src/client/service/vaultsPermissionGet.ts @@ -5,6 +5,7 @@ import type * as grpc from '@grpc/grpc-js'; import type { VaultActions } from '../../vaults/types'; import type ACL from '../../acl/ACL'; import type { NodeId, NodeIdEncoded } from 'nodes/types'; +import type Logger from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; import * as grpcUtils from '../../grpc/utils'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; @@ -16,10 +17,12 @@ function vaultsPermissionGet({ authenticate, vaultManager, acl, + logger, }: { authenticate: Authenticate; vaultManager: VaultManager; acl: ACL; + logger: Logger; }) { return async ( call: grpc.ServerWritableStream, @@ -57,8 +60,9 @@ function vaultsPermissionGet({ } await genWritable.next(null); return; - } catch (err) { - await genWritable.throw(err); + } catch (e) { + await genWritable.throw(e); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsPermissionSet.ts b/src/client/service/vaultsPermissionSet.ts index 6b4768ee8..f19ec7da3 100644 --- a/src/client/service/vaultsPermissionSet.ts +++ b/src/client/service/vaultsPermissionSet.ts @@ -6,6 +6,7 @@ import type ACL from '../../acl/ACL'; import type NotificationsManager from '../../notifications/NotificationsManager'; import type { VaultActions } from '../../vaults/types'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as vaultsUtils from '../../vaults/utils'; import * as vaultsErrors from '../../vaults/errors'; @@ -14,17 +15,19 @@ import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsPermissionSet({ - vaultManager, authenticate, + vaultManager, gestaltGraph, acl, notificationsManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; gestaltGraph: GestaltGraph; acl: ACL; notificationsManager: NotificationsManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -74,6 +77,7 @@ function vaultsPermissionSet({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsPermissionUnset.ts b/src/client/service/vaultsPermissionUnset.ts index d16d81d98..cd9c0ee9e 100644 --- a/src/client/service/vaultsPermissionUnset.ts +++ b/src/client/service/vaultsPermissionUnset.ts @@ -4,6 +4,7 @@ import type VaultManager from '../../vaults/VaultManager'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type ACL from '../../acl/ACL'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as vaultsErrors from '../../vaults/errors'; import * as validationUtils from '../../validation/utils'; @@ -11,15 +12,17 @@ import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsPermissionUnset({ - vaultManager, authenticate, + vaultManager, gestaltGraph, acl, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; gestaltGraph: GestaltGraph; acl: ACL; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -73,6 +76,7 @@ function vaultsPermissionUnset({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsPull.ts b/src/client/service/vaultsPull.ts index 8c18e1a29..821e3179a 100644 --- a/src/client/service/vaultsPull.ts +++ b/src/client/service/vaultsPull.ts @@ -2,6 +2,7 @@ import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; import type { VaultName } from '../../vaults/types'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; @@ -11,9 +12,11 @@ import * as vaultsUtils from '../../vaults/utils'; function vaultsPull({ authenticate, vaultManager, + logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -58,6 +61,7 @@ function vaultsPull({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsRename.ts b/src/client/service/vaultsRename.ts index 506162989..27276c1aa 100644 --- a/src/client/service/vaultsRename.ts +++ b/src/client/service/vaultsRename.ts @@ -1,6 +1,7 @@ import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; @@ -8,11 +9,13 @@ import * as vaultsUtils from '../../vaults/utils'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; function vaultsRename({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -37,6 +40,7 @@ function vaultsRename({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsScan.ts b/src/client/service/vaultsScan.ts index 0ed5ebbbe..f0392dba5 100644 --- a/src/client/service/vaultsScan.ts +++ b/src/client/service/vaultsScan.ts @@ -3,6 +3,7 @@ import type { NodeId } from '../../nodes/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type * as grpc from '@grpc/grpc-js'; import type VaultManager from '../../vaults/VaultManager'; +import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; @@ -10,11 +11,13 @@ import { matchSync } from '../../utils'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; function vaultsScan({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerWritableStream, @@ -53,6 +56,7 @@ function vaultsScan({ return; } catch (e) { await genWritable.throw(e); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsDelete.ts b/src/client/service/vaultsSecretsDelete.ts index 07a56a92d..6332c1442 100644 --- a/src/client/service/vaultsSecretsDelete.ts +++ b/src/client/service/vaultsSecretsDelete.ts @@ -2,6 +2,7 @@ import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; @@ -9,11 +10,13 @@ import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsSecretsDelete({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -40,6 +43,7 @@ function vaultsSecretsDelete({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsEdit.ts b/src/client/service/vaultsSecretsEdit.ts index 8f45362b2..d502d9808 100644 --- a/src/client/service/vaultsSecretsEdit.ts +++ b/src/client/service/vaultsSecretsEdit.ts @@ -2,6 +2,7 @@ import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; @@ -9,11 +10,13 @@ import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsSecretsEdit({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -46,6 +49,7 @@ function vaultsSecretsEdit({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsGet.ts b/src/client/service/vaultsSecretsGet.ts index fa836e1b0..bd3c3a330 100644 --- a/src/client/service/vaultsSecretsGet.ts +++ b/src/client/service/vaultsSecretsGet.ts @@ -2,6 +2,7 @@ import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; @@ -9,11 +10,13 @@ import * as vaultOps from '../../vaults/VaultOps'; import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; function vaultsSecretsGet({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -43,6 +46,7 @@ function vaultsSecretsGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsList.ts b/src/client/service/vaultsSecretsList.ts index db71fc128..c9732edbf 100644 --- a/src/client/service/vaultsSecretsList.ts +++ b/src/client/service/vaultsSecretsList.ts @@ -3,17 +3,20 @@ import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import type Logger from '@matrixai/logger'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultOps from '../../vaults/VaultOps'; import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; function vaultsSecretsList({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerWritableStream, @@ -42,6 +45,7 @@ function vaultsSecretsList({ return; } catch (e) { await genWritable.throw(e); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsMkdir.ts b/src/client/service/vaultsSecretsMkdir.ts index fca32d4f9..3753571c7 100644 --- a/src/client/service/vaultsSecretsMkdir.ts +++ b/src/client/service/vaultsSecretsMkdir.ts @@ -2,6 +2,7 @@ import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; @@ -9,11 +10,13 @@ import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsSecretsMkdir({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -42,6 +45,7 @@ function vaultsSecretsMkdir({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsNew.ts b/src/client/service/vaultsSecretsNew.ts index 3c22baa7a..b264631f9 100644 --- a/src/client/service/vaultsSecretsNew.ts +++ b/src/client/service/vaultsSecretsNew.ts @@ -2,6 +2,7 @@ import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; @@ -9,11 +10,13 @@ import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsSecretsNew({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -41,6 +44,7 @@ function vaultsSecretsNew({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsNewDir.ts b/src/client/service/vaultsSecretsNewDir.ts index 31a075e01..36fd2b3af 100644 --- a/src/client/service/vaultsSecretsNewDir.ts +++ b/src/client/service/vaultsSecretsNewDir.ts @@ -3,6 +3,7 @@ import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type { FileSystem } from '../../types'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; @@ -10,13 +11,15 @@ import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsSecretsNewDir({ - vaultManager, authenticate, + vaultManager, fs, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; fs: FileSystem; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -43,6 +46,7 @@ function vaultsSecretsNewDir({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsRename.ts b/src/client/service/vaultsSecretsRename.ts index 7de527519..ceeb7160e 100644 --- a/src/client/service/vaultsSecretsRename.ts +++ b/src/client/service/vaultsSecretsRename.ts @@ -2,6 +2,7 @@ import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; @@ -9,11 +10,13 @@ import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsSecretsRename({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -46,6 +49,7 @@ function vaultsSecretsRename({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsStat.ts b/src/client/service/vaultsSecretsStat.ts index e657d4009..ab03c57e4 100644 --- a/src/client/service/vaultsSecretsStat.ts +++ b/src/client/service/vaultsSecretsStat.ts @@ -1,6 +1,7 @@ import type VaultManager from '../../vaults/VaultManager'; import type { VaultName } from '../../vaults/types'; import type { Authenticate } from '../types'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; @@ -10,9 +11,11 @@ import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; function vaultsSecretsStat({ authenticate, vaultManager, + logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -39,6 +42,7 @@ function vaultsSecretsStat({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/client/service/vaultsVersion.ts b/src/client/service/vaultsVersion.ts index 4338966da..fcb32a2fe 100644 --- a/src/client/service/vaultsVersion.ts +++ b/src/client/service/vaultsVersion.ts @@ -1,17 +1,20 @@ import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; +import type Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; function vaultsVersion({ - vaultManager, authenticate, + vaultManager, + logger, }: { - vaultManager: VaultManager; authenticate: Authenticate; + vaultManager: VaultManager; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -52,6 +55,7 @@ function vaultsVersion({ return; } catch (e) { callback(grpcUtils.fromError(e)); + logger.error(e); return; } }; diff --git a/src/gestalts/utils.ts b/src/gestalts/utils.ts index 1f1df121f..2bba234e6 100644 --- a/src/gestalts/utils.ts +++ b/src/gestalts/utils.ts @@ -11,7 +11,7 @@ import type { NodeId } from '../nodes/types'; import type { IdentityId, ProviderId } from '../identities/types'; import canonicalize from 'canonicalize'; import { gestaltActions } from './types'; -import { utils as nodesUtils } from '../nodes'; +import * as nodesUtils from '../nodes/utils'; /** * Construct GestaltKey from GestaltId diff --git a/src/grpc/GRPCClient.ts b/src/grpc/GRPCClient.ts index b705e9aa5..22a7c65e5 100644 --- a/src/grpc/GRPCClient.ts +++ b/src/grpc/GRPCClient.ts @@ -151,7 +151,8 @@ abstract class GRPCClient { `Failed GRPC server certificate verification connecting to ${address}`, ); const e_ = new grpcErrors.ErrorGRPCClientVerification( - `${e.name}: ${e.message}`,{ + `${e.name}: ${e.message}`, + { data: e.data, cause: e, }, diff --git a/src/grpc/GRPCServer.ts b/src/grpc/GRPCServer.ts index 2c7edf11b..b7a0ac84c 100644 --- a/src/grpc/GRPCServer.ts +++ b/src/grpc/GRPCServer.ts @@ -100,7 +100,8 @@ class GRPCServer { `Failed GRPC client certificate verification connecting from ${address}`, ); const e_ = new grpcErrors.ErrorGRPCServerVerification( - `${e.name}: ${e.message}`, { + `${e.name}: ${e.message}`, + { data: e.data, cause: e, }, diff --git a/src/grpc/utils/utils.ts b/src/grpc/utils/utils.ts index b75a6d21e..7db50484c 100644 --- a/src/grpc/utils/utils.ts +++ b/src/grpc/utils/utils.ts @@ -162,7 +162,10 @@ function getServerSession(call: ServerSurfaceCall): Http2Session { * If sending to an agent (rather than a client), set sensitive to true to * prevent sensitive information from being sent over the network */ -function fromError(error: Error, sensitive: boolean = false): ServerStatusResponse { +function fromError( + error: Error, + sensitive: boolean = false, +): ServerStatusResponse { const metadata = new grpc.Metadata(); if (sensitive) { metadata.set('error', JSON.stringify(error, sensitiveReplacer)); @@ -188,10 +191,7 @@ function toError(e: ServiceError): errors.ErrorPolykey { // check if the error code matches a known grpc status // @ts-ignore grpc.status[key] is in fact a string if (isNaN(parseInt(key)) && e.code === grpc.status[key]) { - if ( - key === 'UNKNOWN' && - errorData != null - ) { + if (key === 'UNKNOWN' && errorData != null) { const error: Error = JSON.parse(errorData, reviver); return new errors.ErrorPolykeyRemote(error.message, { cause: error }); } else { @@ -214,7 +214,7 @@ function toError(e: ServiceError): errors.ErrorPolykey { * Polykey errors are handled by their inbuilt `toJSON` method , so this only * serialises other errors */ - function replacer(key: string, value: any): any { +function replacer(key: string, value: any): any { if (value instanceof AbstractError) { // Include the standard properties from an AbstractError return { @@ -226,8 +226,8 @@ function toError(e: ServiceError): errors.ErrorPolykey { data: value.data, cause: value.cause, stack: value.stack, - } - } + }, + }; } else if (value instanceof Error) { // If it's some other type of error then only serialise the message and // stack (and the type of the error) @@ -236,8 +236,8 @@ function toError(e: ServiceError): errors.ErrorPolykey { data: { message: value.message, stack: value.stack, - } - } + }, + }; } else { // If it's not an error then just leave as is return value; @@ -262,13 +262,13 @@ function sensitiveReplacer(key: string, value: any) { * Allows these errors to be reconstructed from GRPC metadata */ const otherErrors = { - 'Error': Error, - 'EvalError': EvalError, - 'RangeError': RangeError, - 'ReferenceError': ReferenceError, - 'SyntaxError': SyntaxError, - 'TypeError': TypeError, - 'URIError': URIError + Error: Error, + EvalError: EvalError, + RangeError: RangeError, + ReferenceError: ReferenceError, + SyntaxError: SyntaxError, + TypeError: TypeError, + URIError: URIError, }; /** @@ -280,17 +280,18 @@ const otherErrors = { */ function reviver(key: string, value: any): any { // If the value is an error then reconstruct it - if (typeof value === 'object' && typeof value.type === 'string' && typeof value.data === 'object') { + if ( + typeof value === 'object' && + typeof value.type === 'string' && + typeof value.data === 'object' + ) { const message = value.data.message ?? ''; if (value.type in errors) { - const error = new errors[value.type]( - message, - { - timestamp: value.data.timestamp, - data: value.data.data, - cause: value.data.cause, - }, - ); + const error = new errors[value.type](message, { + timestamp: value.data.timestamp, + data: value.data.data, + cause: value.data.cause, + }); error.exitCode = value.data.exitCode; if (value.data.stack) { error.stack = value.data.stack; diff --git a/src/identities/errors.ts b/src/identities/errors.ts index dece95ffc..40ade2ceb 100644 --- a/src/identities/errors.ts +++ b/src/identities/errors.ts @@ -33,7 +33,8 @@ class ErrorProviderAuthentication extends ErrorIdentities { } class ErrorProviderUnauthenticated extends ErrorIdentities { - static description = 'Provider has not been authenticated or access token is expired or invalid'; + static description = + 'Provider has not been authenticated or access token is expired or invalid'; exitCode = sysexits.NOPERM; } diff --git a/src/identities/providers/github/GitHubProvider.ts b/src/identities/providers/github/GitHubProvider.ts index 122122931..8fd0a79fe 100644 --- a/src/identities/providers/github/GitHubProvider.ts +++ b/src/identities/providers/github/GitHubProvider.ts @@ -120,7 +120,8 @@ class GitHubProvider extends Provider { data = await response.json(); } catch (e) { throw new identitiesErrors.ErrorProviderAuthentication( - 'Provider access token response is not valid JSON', { cause: e }, + 'Provider access token response is not valid JSON', + { cause: e }, ); } if (data.error) { diff --git a/src/network/utils.ts b/src/network/utils.ts index f97f71ef9..1df7faa7f 100644 --- a/src/network/utils.ts +++ b/src/network/utils.ts @@ -101,7 +101,9 @@ async function resolveHost(host: Host | Hostname): Promise { // Resolve the hostname and get the IPv4 address resolvedHost = await lookup(host, 4); } catch (e) { - throw new networkErrors.ErrorHostnameResolutionFailed(e.message, { cause: e }); + throw new networkErrors.ErrorHostnameResolutionFailed(e.message, { + cause: e, + }); } // Returns an array of [ resolved address, family (4 or 6) ] return resolvedHost[0] as Host; diff --git a/src/nodes/NodeConnection.ts b/src/nodes/NodeConnection.ts index d81ac9721..f79272413 100644 --- a/src/nodes/NodeConnection.ts +++ b/src/nodes/NodeConnection.ts @@ -135,7 +135,9 @@ class NodeConnection { await nodeConnection.destroy(); // If the connection times out, re-throw this with a higher level nodes exception if (e instanceof grpcErrors.ErrorGRPCClientTimeout) { - throw new nodesErrors.ErrorNodeConnectionTimeout(e.message, { cause: e }); + throw new nodesErrors.ErrorNodeConnectionTimeout(e.message, { + cause: e, + }); } throw e; } diff --git a/src/notifications/errors.ts b/src/notifications/errors.ts index 3a9ca102f..028862e50 100644 --- a/src/notifications/errors.ts +++ b/src/notifications/errors.ts @@ -47,9 +47,7 @@ class ErrorNotificationsGeneralInvalid extends ErrorSchemaValidate { exitCode = sysexits.USAGE; } -class ErrorNotificationsGestaltInviteInvalid< - T, -> extends ErrorSchemaValidate { +class ErrorNotificationsGestaltInviteInvalid extends ErrorSchemaValidate { static description = 'Invalid notification data'; exitCode = sysexits.USAGE; } diff --git a/src/notifications/utils.ts b/src/notifications/utils.ts index 0f55a6620..a31b0ad59 100644 --- a/src/notifications/utils.ts +++ b/src/notifications/utils.ts @@ -78,7 +78,9 @@ async function verifyAndDecodeNotif(notifJWT: string): Promise { throw err; } else { // Error came from jose - throw new notificationsErrors.ErrorNotificationsParse(err.message, { cause: err }); + throw new notificationsErrors.ErrorNotificationsParse(err.message, { + cause: err, + }); } } } diff --git a/src/status/Status.ts b/src/status/Status.ts index fbee3edce..01647736c 100644 --- a/src/status/Status.ts +++ b/src/status/Status.ts @@ -145,7 +145,9 @@ class Status { try { statusInfo = JSON.parse(statusData, this.statusReviver); } catch (e) { - throw new statusErrors.ErrorStatusParse('JSON parsing failed', {cause: e}); + throw new statusErrors.ErrorStatusParse('JSON parsing failed', { + cause: e, + }); } if (!statusUtils.statusValidate(statusInfo)) { throw new statusErrors.ErrorStatusParse( @@ -246,7 +248,9 @@ class Status { try { statusInfo = JSON.parse(statusData, this.statusReviver); } catch (e) { - throw new statusErrors.ErrorStatusParse('JSON parsing failed', { cause: e }); + throw new statusErrors.ErrorStatusParse('JSON parsing failed', { + cause: e, + }); } if (!statusUtils.statusValidate(statusInfo)) { throw new statusErrors.ErrorStatusParse( diff --git a/src/vaults/VaultInternal.ts b/src/vaults/VaultInternal.ts index c7f60829b..34597b034 100644 --- a/src/vaults/VaultInternal.ts +++ b/src/vaults/VaultInternal.ts @@ -376,7 +376,9 @@ class VaultInternal { e instanceof git.Errors.NotFoundError || e instanceof git.Errors.CommitNotFetchedError ) { - throw new vaultsErrors.ErrorVaultReferenceMissing(e.message, { cause: e }); + throw new vaultsErrors.ErrorVaultReferenceMissing(e.message, { + cause: e, + }); } throw e; } @@ -551,7 +553,9 @@ class VaultInternal { if (err instanceof git.Errors.SmartHttpError && error) { throw error; } else if (err instanceof git.Errors.MergeNotSupportedError) { - throw new vaultsErrors.ErrorVaultsMergeConflict(err.message, { cause: err }); + throw new vaultsErrors.ErrorVaultsMergeConflict(err.message, { + cause: err, + }); } throw err; } diff --git a/tests/agent/service/nodesCrossSignClaim.test.ts b/tests/agent/service/nodesCrossSignClaim.test.ts index 0c3a1da7a..5b3f6c53e 100644 --- a/tests/agent/service/nodesCrossSignClaim.test.ts +++ b/tests/agent/service/nodesCrossSignClaim.test.ts @@ -5,6 +5,7 @@ import fs from 'fs'; import path from 'path'; import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { ErrorPolykeyRemote } from '@/errors'; import PolykeyAgent from '@/PolykeyAgent'; import GRPCServer from '@/grpc/GRPCServer'; import GRPCClientAgent from '@/agent/GRPCClientAgent'; @@ -14,7 +15,6 @@ import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import * as claimsUtils from '@/claims/utils'; -import * as claimsErrors from '@/claims/errors'; import * as testNodesUtils from '../../nodes/utils'; import * as testUtils from '../../utils'; @@ -78,6 +78,7 @@ describe('nodesCrossSignClaim', () => { keyManager: pkAgent.keyManager, nodeManager: pkAgent.nodeManager, sigchain: pkAgent.sigchain, + logger, }), }; grpcServer = new GRPCServer({ logger }); @@ -204,9 +205,7 @@ describe('nodesCrossSignClaim', () => { // 2. X <- sends its intermediary signed claim <- Y const crossSignMessageUndefinedSingly = new nodesPB.CrossSign(); await genClaims.write(crossSignMessageUndefinedSingly); - await expect(() => genClaims.read()).rejects.toThrow( - claimsErrors.ErrorUndefinedSinglySignedClaim, - ); + await expect(() => genClaims.read()).rejects.toThrow(ErrorPolykeyRemote); expect(genClaims.stream.destroyed).toBe(true); // Check sigchain's lock is released expect(pkAgent.sigchain.locked).toBe(false); @@ -226,9 +225,7 @@ describe('nodesCrossSignClaim', () => { intermediaryNoSignature, ); await genClaims.write(crossSignMessageUndefinedSinglySignature); - await expect(() => genClaims.read()).rejects.toThrow( - claimsErrors.ErrorUndefinedSignature, - ); + await expect(() => genClaims.read()).rejects.toThrow(ErrorPolykeyRemote); expect(genClaims.stream.destroyed).toBe(true); // Check sigchain's lock is released expect(pkAgent.sigchain.locked).toBe(false); diff --git a/tests/agent/service/notificationsSend.test.ts b/tests/agent/service/notificationsSend.test.ts index a0eb81ffa..3732b407e 100644 --- a/tests/agent/service/notificationsSend.test.ts +++ b/tests/agent/service/notificationsSend.test.ts @@ -137,6 +137,7 @@ describe('notificationsSend', () => { const agentService = { notificationsSend: notificationsSend({ notificationsManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/GRPCClientClient.test.ts b/tests/client/GRPCClientClient.test.ts index a6ce3f3bb..bb083f816 100644 --- a/tests/client/GRPCClientClient.test.ts +++ b/tests/client/GRPCClientClient.test.ts @@ -1,6 +1,6 @@ +import type * as grpc from '@grpc/grpc-js'; import type { Host, Port } from '@/network/types'; import type { NodeId } from '@/nodes/types'; -import type * as grpc from '@grpc/grpc-js'; import os from 'os'; import path from 'path'; import fs from 'fs'; diff --git a/tests/client/service/agentLockAll.test.ts b/tests/client/service/agentLockAll.test.ts index 21a533dd6..4ae0d6665 100644 --- a/tests/client/service/agentLockAll.test.ts +++ b/tests/client/service/agentLockAll.test.ts @@ -75,6 +75,7 @@ describe('agentLockall', () => { agentLockAll: agentLockAll({ authenticate, sessionManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/agentStatus.test.ts b/tests/client/service/agentStatus.test.ts index 04c68aa2e..cb26d32d2 100644 --- a/tests/client/service/agentStatus.test.ts +++ b/tests/client/service/agentStatus.test.ts @@ -83,6 +83,7 @@ describe('agentStatus', () => { grpcServerClient, grpcServerAgent, proxy, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/agentStop.test.ts b/tests/client/service/agentStop.test.ts index 6a5e00dd4..a799729cb 100644 --- a/tests/client/service/agentStop.test.ts +++ b/tests/client/service/agentStop.test.ts @@ -59,6 +59,7 @@ describe('agentStop', () => { agentStop: agentStop({ authenticate, pkAgent: pkAgent as unknown as PolykeyAgent, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/agentUnlock.test.ts b/tests/client/service/agentUnlock.test.ts index 4ca05aba0..4a64076ad 100644 --- a/tests/client/service/agentUnlock.test.ts +++ b/tests/client/service/agentUnlock.test.ts @@ -22,6 +22,7 @@ describe('agentUnlock', () => { const clientService = { agentUnlock: agentUnlock({ authenticate, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts b/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts index 4ea77f742..09dfaae3b 100644 --- a/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts +++ b/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts @@ -72,14 +72,17 @@ describe('gestaltsActionsByIdentity', () => { gestaltsActionsSetByIdentity: gestaltsActionsSetByIdentity({ authenticate, gestaltGraph, + logger, }), gestaltsActionsGetByIdentity: gestaltsActionsGetByIdentity({ authenticate, gestaltGraph, + logger, }), gestaltsActionsUnsetByIdentity: gestaltsActionsUnsetByIdentity({ authenticate, gestaltGraph, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsActionsSetUnsetGetByNode.test.ts b/tests/client/service/gestaltsActionsSetUnsetGetByNode.test.ts index 5eb2e40bf..cfec8dfda 100644 --- a/tests/client/service/gestaltsActionsSetUnsetGetByNode.test.ts +++ b/tests/client/service/gestaltsActionsSetUnsetGetByNode.test.ts @@ -66,14 +66,17 @@ describe('gestaltsActionsByNode', () => { gestaltsActionsSetByNode: gestaltsActionsSetByNode({ authenticate, gestaltGraph, + logger, }), gestaltsActionsGetByNode: gestaltsActionsGetByNode({ authenticate, gestaltGraph, + logger, }), gestaltsActionsUnsetByNode: gestaltsActionsUnsetByNode({ authenticate, gestaltGraph, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsDiscoveryByIdentity.test.ts b/tests/client/service/gestaltsDiscoveryByIdentity.test.ts index a987f6aad..2c314711b 100644 --- a/tests/client/service/gestaltsDiscoveryByIdentity.test.ts +++ b/tests/client/service/gestaltsDiscoveryByIdentity.test.ts @@ -155,6 +155,7 @@ describe('gestaltsDiscoveryByIdentity', () => { gestaltsDiscoveryByIdentity: gestaltsDiscoveryByIdentity({ authenticate, discovery, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsDiscoveryByNode.test.ts b/tests/client/service/gestaltsDiscoveryByNode.test.ts index d03fe307a..7071428e6 100644 --- a/tests/client/service/gestaltsDiscoveryByNode.test.ts +++ b/tests/client/service/gestaltsDiscoveryByNode.test.ts @@ -155,6 +155,7 @@ describe('gestaltsDiscoveryByNode', () => { gestaltsDiscoveryByNode: gestaltsDiscoveryByNode({ authenticate, discovery, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsGestaltGetByIdentity.test.ts b/tests/client/service/gestaltsGestaltGetByIdentity.test.ts index a8aa0b5bf..cddc5af3f 100644 --- a/tests/client/service/gestaltsGestaltGetByIdentity.test.ts +++ b/tests/client/service/gestaltsGestaltGetByIdentity.test.ts @@ -89,6 +89,7 @@ describe('gestaltsGestaltGetByIdentity', () => { gestaltsGestaltGetByIdentity: gestaltsGestaltGetByIdentity({ authenticate, gestaltGraph, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsGestaltGetByNode.test.ts b/tests/client/service/gestaltsGestaltGetByNode.test.ts index ebff5bf7d..2a5848203 100644 --- a/tests/client/service/gestaltsGestaltGetByNode.test.ts +++ b/tests/client/service/gestaltsGestaltGetByNode.test.ts @@ -86,6 +86,7 @@ describe('gestaltsGestaltGetByNode', () => { gestaltsGestaltGetByNode: gestaltsGestaltGetByNode({ authenticate, gestaltGraph, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsGestaltList.test.ts b/tests/client/service/gestaltsGestaltList.test.ts index 6b714e073..c724124d7 100644 --- a/tests/client/service/gestaltsGestaltList.test.ts +++ b/tests/client/service/gestaltsGestaltList.test.ts @@ -92,6 +92,7 @@ describe('gestaltsGestaltList', () => { gestaltsGestaltList: gestaltsGestaltList({ authenticate, gestaltGraph, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts index 8bd0a749e..74ecff0e3 100644 --- a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts +++ b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts @@ -227,6 +227,7 @@ describe('gestaltsGestaltTrustByIdentity', () => { authenticate, gestaltGraph, discovery, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsGestaltTrustByNode.test.ts b/tests/client/service/gestaltsGestaltTrustByNode.test.ts index ccc7c827d..7cb297e67 100644 --- a/tests/client/service/gestaltsGestaltTrustByNode.test.ts +++ b/tests/client/service/gestaltsGestaltTrustByNode.test.ts @@ -225,6 +225,7 @@ describe('gestaltsGestaltTrustByNode', () => { authenticate, gestaltGraph, discovery, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/identitiesAuthenticate.test.ts b/tests/client/service/identitiesAuthenticate.test.ts index fb3c2a9ff..73bce737e 100644 --- a/tests/client/service/identitiesAuthenticate.test.ts +++ b/tests/client/service/identitiesAuthenticate.test.ts @@ -56,6 +56,7 @@ describe('identitiesAuthenticate', () => { identitiesAuthenticate: identitiesAuthenticate({ authenticate, identitiesManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/identitiesAuthenticatedGet.test.ts b/tests/client/service/identitiesAuthenticatedGet.test.ts index 8233589d5..1dacdddbc 100644 --- a/tests/client/service/identitiesAuthenticatedGet.test.ts +++ b/tests/client/service/identitiesAuthenticatedGet.test.ts @@ -48,6 +48,7 @@ describe('identitiesAuthenticatedGet', () => { identitiesAuthenticatedGet: identitiesAuthenticatedGet({ authenticate, identitiesManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/identitiesClaim.test.ts b/tests/client/service/identitiesClaim.test.ts index b040a7b0a..6259afaea 100644 --- a/tests/client/service/identitiesClaim.test.ts +++ b/tests/client/service/identitiesClaim.test.ts @@ -148,6 +148,7 @@ describe('identitiesClaim', () => { identitiesManager, sigchain, keyManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/identitiesInfoConnectedGet.test.ts b/tests/client/service/identitiesInfoConnectedGet.test.ts index 0dce4a1bb..300567584 100644 --- a/tests/client/service/identitiesInfoConnectedGet.test.ts +++ b/tests/client/service/identitiesInfoConnectedGet.test.ts @@ -52,6 +52,7 @@ describe('identitiesInfoConnectedGet', () => { identitiesInfoConnectedGet: identitiesInfoConnectedGet({ authenticate, identitiesManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/identitiesInfoGet.test.ts b/tests/client/service/identitiesInfoGet.test.ts index 41bc2a1e0..68b9df655 100644 --- a/tests/client/service/identitiesInfoGet.test.ts +++ b/tests/client/service/identitiesInfoGet.test.ts @@ -51,6 +51,7 @@ describe('identitiesInfoGet', () => { identitiesInfoGet: identitiesInfoGet({ authenticate, identitiesManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/identitiesProvidersList.test.ts b/tests/client/service/identitiesProvidersList.test.ts index 071703386..e75ffd477 100644 --- a/tests/client/service/identitiesProvidersList.test.ts +++ b/tests/client/service/identitiesProvidersList.test.ts @@ -60,6 +60,7 @@ describe('identitiesProvidersList', () => { identitiesProvidersList: identitiesProvidersList({ authenticate, identitiesManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/identitiesTokenPutDeleteGet.test.ts b/tests/client/service/identitiesTokenPutDeleteGet.test.ts index 6fca93e68..f26eb192b 100644 --- a/tests/client/service/identitiesTokenPutDeleteGet.test.ts +++ b/tests/client/service/identitiesTokenPutDeleteGet.test.ts @@ -56,14 +56,17 @@ describe('identitiesTokenPutDeleteGet', () => { identitiesTokenPut: identitiesTokenPut({ authenticate, identitiesManager, + logger, }), identitiesTokenGet: identitiesTokenGet({ authenticate, identitiesManager, + logger, }), identitiesTokenDelete: identitiesTokenDelete({ authenticate, identitiesManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/keysCertsChainGet.test.ts b/tests/client/service/keysCertsChainGet.test.ts index f0b97a681..48b734c95 100644 --- a/tests/client/service/keysCertsChainGet.test.ts +++ b/tests/client/service/keysCertsChainGet.test.ts @@ -61,6 +61,7 @@ describe('keysCertsChainGet', () => { keysCertsChainGet: keysCertsChainGet({ authenticate, keyManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/keysCertsGet.test.ts b/tests/client/service/keysCertsGet.test.ts index ad2fb28ba..d3bd83e09 100644 --- a/tests/client/service/keysCertsGet.test.ts +++ b/tests/client/service/keysCertsGet.test.ts @@ -60,6 +60,7 @@ describe('keysCertsGet', () => { keysCertsGet: keysCertsGet({ authenticate, keyManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/keysEncryptDecrypt.test.ts b/tests/client/service/keysEncryptDecrypt.test.ts index 0c2a1259a..a6421649f 100644 --- a/tests/client/service/keysEncryptDecrypt.test.ts +++ b/tests/client/service/keysEncryptDecrypt.test.ts @@ -55,10 +55,12 @@ describe('keysEncryptDecrypt', () => { keysEncrypt: keysEncrypt({ authenticate, keyManager, + logger, }), keysDecrypt: keysDecrypt({ authenticate, keyManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/keysKeyPairRenew.test.ts b/tests/client/service/keysKeyPairRenew.test.ts index 714055cf0..550f793dd 100644 --- a/tests/client/service/keysKeyPairRenew.test.ts +++ b/tests/client/service/keysKeyPairRenew.test.ts @@ -74,6 +74,7 @@ describe('keysKeyPairRenew', () => { keysKeyPairRenew: keysKeyPairRenew({ authenticate, keyManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/keysKeyPairReset.test.ts b/tests/client/service/keysKeyPairReset.test.ts index 155d6071e..754d80075 100644 --- a/tests/client/service/keysKeyPairReset.test.ts +++ b/tests/client/service/keysKeyPairReset.test.ts @@ -74,6 +74,7 @@ describe('keysKeyPairReset', () => { keysKeyPairReset: keysKeyPairReset({ authenticate, keyManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/keysKeyPairRoot.test.ts b/tests/client/service/keysKeyPairRoot.test.ts index 19330b0cc..e5d5f2629 100644 --- a/tests/client/service/keysKeyPairRoot.test.ts +++ b/tests/client/service/keysKeyPairRoot.test.ts @@ -56,6 +56,7 @@ describe('keysKeyPairRoot', () => { keysKeyPairRoot: keysKeyPairRoot({ authenticate, keyManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/keysPasswordChange.test.ts b/tests/client/service/keysPasswordChange.test.ts index 8f22e95e2..7814ec86a 100644 --- a/tests/client/service/keysPasswordChange.test.ts +++ b/tests/client/service/keysPasswordChange.test.ts @@ -62,6 +62,7 @@ describe('keysPasswordChange', () => { keysPasswordChange: keysPasswordChange({ authenticate, keyManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/keysSignVerify.test.ts b/tests/client/service/keysSignVerify.test.ts index 34cf424fd..c420d7ed6 100644 --- a/tests/client/service/keysSignVerify.test.ts +++ b/tests/client/service/keysSignVerify.test.ts @@ -56,10 +56,12 @@ describe('keysSignVerify', () => { keysSign: keysSign({ authenticate, keyManager, + logger, }), keysVerify: keysVerify({ authenticate, keyManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/nodesAdd.test.ts b/tests/client/service/nodesAdd.test.ts index 1cd51eb05..168e64a34 100644 --- a/tests/client/service/nodesAdd.test.ts +++ b/tests/client/service/nodesAdd.test.ts @@ -116,6 +116,7 @@ describe('nodesAdd', () => { nodesAdd: nodesAdd({ authenticate, nodeManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/nodesClaim.test.ts b/tests/client/service/nodesClaim.test.ts index 07d41e500..2686ce3ed 100644 --- a/tests/client/service/nodesClaim.test.ts +++ b/tests/client/service/nodesClaim.test.ts @@ -159,6 +159,7 @@ describe('nodesClaim', () => { authenticate, nodeManager, notificationsManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/nodesFind.test.ts b/tests/client/service/nodesFind.test.ts index 1197638f5..0297bccbd 100644 --- a/tests/client/service/nodesFind.test.ts +++ b/tests/client/service/nodesFind.test.ts @@ -110,8 +110,9 @@ describe('nodesFind', () => { await nodeConnectionManager.start(); const clientService = { nodesFind: nodesFind({ - nodeConnectionManager, authenticate, + nodeConnectionManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/nodesPing.test.ts b/tests/client/service/nodesPing.test.ts index 0bfcabc97..43dddcba1 100644 --- a/tests/client/service/nodesPing.test.ts +++ b/tests/client/service/nodesPing.test.ts @@ -121,6 +121,7 @@ describe('nodesPing', () => { nodesPing: nodesPing({ authenticate, nodeManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/notificationsClear.test.ts b/tests/client/service/notificationsClear.test.ts index 2fab2e233..62cc7ce63 100644 --- a/tests/client/service/notificationsClear.test.ts +++ b/tests/client/service/notificationsClear.test.ts @@ -135,6 +135,7 @@ describe('notificationsClear', () => { notificationsClear: notificationsClear({ authenticate, notificationsManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/notificationsRead.test.ts b/tests/client/service/notificationsRead.test.ts index 1b77af1a3..393943f5e 100644 --- a/tests/client/service/notificationsRead.test.ts +++ b/tests/client/service/notificationsRead.test.ts @@ -209,6 +209,7 @@ describe('notificationsRead', () => { notificationsRead: notificationsRead({ authenticate, notificationsManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/notificationsSend.test.ts b/tests/client/service/notificationsSend.test.ts index 01764d368..7709f7b47 100644 --- a/tests/client/service/notificationsSend.test.ts +++ b/tests/client/service/notificationsSend.test.ts @@ -144,6 +144,7 @@ describe('notificationsSend', () => { notificationsSend: notificationsSend({ authenticate, notificationsManager, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/grpc/utils.test.ts b/tests/grpc/utils.test.ts index b2390e2fa..496f6553b 100644 --- a/tests/grpc/utils.test.ts +++ b/tests/grpc/utils.test.ts @@ -105,7 +105,9 @@ describe('GRPC utils', () => { const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge(challenge); const stream = serverStream(messageTo); - await expect(() => stream.next()).rejects.toThrow(errors.ErrorPolykeyRemote); + await expect(() => stream.next()).rejects.toThrow( + errors.ErrorPolykeyRemote, + ); // The generator will have ended // the internal stream will be automatically destroyed const result = await stream.next(); @@ -276,7 +278,9 @@ describe('GRPC utils', () => { const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('error'); await genDuplex.write(messageTo); - await expect(() => genDuplex.read()).rejects.toThrow(errors.ErrorPolykeyRemote); + await expect(() => genDuplex.read()).rejects.toThrow( + errors.ErrorPolykeyRemote, + ); expect(genDuplex.stream.destroyed).toBe(true); expect(genDuplex.stream.getPeer()).toBe(`127.0.0.1:${port}`); }); @@ -316,7 +320,7 @@ describe('GRPC utils', () => { message: '', code: 2, details: '', - metadata: serialised + metadata: serialised, }); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); @@ -341,7 +345,7 @@ describe('GRPC utils', () => { message: '', code: 2, details: '', - metadata: serialised + metadata: serialised, }); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); @@ -360,7 +364,7 @@ describe('GRPC utils', () => { message: '', code: 2, details: '', - metadata: serialised + metadata: serialised, }); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe(''); @@ -397,7 +401,7 @@ describe('GRPC utils', () => { message: '', code: 2, details: '', - metadata: serialised + metadata: serialised, }); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); From 631a67067f1b961faf6401a3976a3b7329c01b49 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 4 May 2022 16:14:42 +1000 Subject: [PATCH 009/137] syntax: removing index imports --- src/PolykeyAgent.ts | 38 ++++++++++--------- .../service/gestaltsActionsGetByIdentity.ts | 16 +++++--- tests/client/rpcVaults.test.ts | 6 +-- tests/client/utils.ts | 5 +-- tests/grpc/GRPCClient.test.ts | 7 ++-- tests/grpc/GRPCServer.test.ts | 8 ++-- tests/grpc/utils/GRPCClientTest.ts | 5 ++- tests/grpc/utils/testService.ts | 3 +- 8 files changed, 50 insertions(+), 38 deletions(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index ba9cafc37..a72ba5f16 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -8,27 +8,31 @@ import process from 'process'; import Logger from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { CreateDestroyStartStop } from '@matrixai/async-init/dist/CreateDestroyStartStop'; -import { KeyManager, utils as keysUtils } from './keys'; -import { Status } from './status'; -import { Schema } from './schema'; -import { VaultManager } from './vaults'; -import { ACL } from './acl'; -import { NodeConnectionManager, NodeGraph, NodeManager } from './nodes'; -import * as nodesUtils from './nodes/utils'; -import { NotificationsManager } from './notifications'; -import { GestaltGraph } from './gestalts'; -import { Sigchain } from './sigchain'; -import { Discovery } from './discovery'; -import { SessionManager } from './sessions'; -import { GRPCServer } from './grpc'; -import { IdentitiesManager, providers } from './identities'; +import KeyManager from './keys/KeyManager'; +import Status from './status/Status'; +import Schema from './schema/Schema'; +import VaultManager from './vaults/VaultManager'; +import ACL from './acl/ACL'; +import NodeManager from './nodes/NodeManager'; +import NodeGraph from './nodes/NodeGraph'; +import NodeConnectionManager from './nodes/NodeConnectionManager'; +import NotificationsManager from './notifications/NotificationsManager'; +import GestaltGraph from './gestalts/GestaltGraph'; +import Sigchain from './sigchain/Sigchain'; +import Discovery from './discovery/Discovery'; +import SessionManager from './sessions/SessionManager'; +import GRPCServer from './grpc/GRPCServer'; +import IdentitiesManager from './identities/IdentitiesManager'; +import { providers } from './identities'; import Proxy from './network/Proxy'; import { EventBus, captureRejectionSymbol } from './events'; -import { createAgentService, AgentServiceService } from './agent'; -import { createClientService, ClientServiceService } from './client'; +import createAgentService, { AgentServiceService } from './agent/service'; +import createClientService, { ClientServiceService } from './client/service'; import config from './config'; -import * as utils from './utils'; import * as errors from './errors'; +import * as utils from './utils'; +import * as keysUtils from './keys/utils'; +import * as nodesUtils from './nodes/utils'; type NetworkConfig = { forwardHost?: Host; diff --git a/src/client/service/gestaltsActionsGetByIdentity.ts b/src/client/service/gestaltsActionsGetByIdentity.ts index 3ec511381..db6faa41e 100644 --- a/src/client/service/gestaltsActionsGetByIdentity.ts +++ b/src/client/service/gestaltsActionsGetByIdentity.ts @@ -1,12 +1,14 @@ +import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { GestaltGraph } from '../../gestalts'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; -import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; -import { matchSync } from '../../utils'; +import { matchSync } from '../../utils/matchers'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; +import * as validationErrors from '../../validation/errors'; +import * as grpcUtils from '../../grpc/utils'; import * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; function gestaltsActionsGetByIdentity({ @@ -58,7 +60,9 @@ function gestaltsActionsGetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + if (!(e instanceof validationErrors.ErrorValidation)) { + logger.error(e); + } return; } }; diff --git a/tests/client/rpcVaults.test.ts b/tests/client/rpcVaults.test.ts index 6e477e62d..96f3db089 100644 --- a/tests/client/rpcVaults.test.ts +++ b/tests/client/rpcVaults.test.ts @@ -7,12 +7,12 @@ import os from 'os'; import path from 'path'; import fs from 'fs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import { PolykeyAgent } from '@'; +import PolykeyAgent from '@/PolykeyAgent'; +import KeyManager from '@/keys/KeyManager'; +import Proxy from '@/network/Proxy'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; import * as secretsPB from '@/proto/js/polykey/v1/secrets/secrets_pb'; -import KeyManager from '@/keys/KeyManager'; -import Proxy from '@/network/Proxy'; import * as grpcUtils from '@/grpc/utils'; import * as vaultErrors from '@/vaults/errors'; import * as vaultsUtils from '@/vaults/utils'; diff --git a/tests/client/utils.ts b/tests/client/utils.ts index 247b1da8b..c3cc7d25b 100644 --- a/tests/client/utils.ts +++ b/tests/client/utils.ts @@ -1,16 +1,15 @@ import type { IClientServiceServer } from '@/proto/js/polykey/v1/client_service_grpc_pb'; import type { SessionToken } from '@/sessions/types'; -import type { PolykeyAgent } from '@'; +import type PolykeyAgent from '@/PolykeyAgent'; import type { NodeId } from '@/nodes/types'; import type { Host, Port } from '@/network/types'; import * as grpc from '@grpc/grpc-js'; - import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { ClientServiceService, ClientServiceClient, } from '@/proto/js/polykey/v1/client_service_grpc_pb'; -import { createClientService } from '@/client'; +import createClientService from '@/client/service'; import PolykeyClient from '@/PolykeyClient'; import { promisify } from '@/utils'; import * as grpcUtils from '@/grpc/utils'; diff --git a/tests/grpc/GRPCClient.test.ts b/tests/grpc/GRPCClient.test.ts index a4f83a1e0..de8618005 100644 --- a/tests/grpc/GRPCClient.test.ts +++ b/tests/grpc/GRPCClient.test.ts @@ -10,9 +10,10 @@ import path from 'path'; import fs from 'fs'; import { DB } from '@matrixai/db'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import { utils as keysUtils } from '@/keys'; -import { Session, SessionManager } from '@/sessions'; -import { errors as grpcErrors } from '@/grpc'; +import Session from '@/sessions/Session'; +import SessionManager from '@/sessions/SessionManager'; +import * as keysUtils from '@/keys/utils'; +import * as grpcErrors from '@/grpc/errors'; import * as clientUtils from '@/client/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as utils from './utils'; diff --git a/tests/grpc/GRPCServer.test.ts b/tests/grpc/GRPCServer.test.ts index 2c62b70f9..9b5c54809 100644 --- a/tests/grpc/GRPCServer.test.ts +++ b/tests/grpc/GRPCServer.test.ts @@ -5,11 +5,13 @@ import path from 'path'; import fs from 'fs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; -import { GRPCServer, utils as grpcUtils } from '@/grpc'; -import { KeyManager, utils as keysUtils } from '@/keys'; -import { SessionManager } from '@/sessions'; +import GRPCServer from '@/grpc/GRPCServer'; +import KeyManager from '@/keys/KeyManager'; +import SessionManager from '@/sessions/SessionManager'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as grpcErrors from '@/grpc/errors'; +import * as grpcUtils from '@/grpc/utils'; +import * as keysUtils from '@/keys/utils'; import * as clientUtils from '@/client/utils'; import * as testGrpcUtils from './utils'; import * as testUtils from '../utils'; diff --git a/tests/grpc/utils/GRPCClientTest.ts b/tests/grpc/utils/GRPCClientTest.ts index c4b55b1d1..9cb176377 100644 --- a/tests/grpc/utils/GRPCClientTest.ts +++ b/tests/grpc/utils/GRPCClientTest.ts @@ -1,5 +1,5 @@ import type { Interceptor } from '@grpc/grpc-js'; -import type { Session } from '@/sessions'; +import type Session from '@/sessions/Session'; import type { NodeId } from '@/nodes/types'; import type { Host, Port, TLSConfig, ProxyConfig } from '@/network/types'; import type * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; @@ -7,7 +7,8 @@ import type { ClientReadableStream } from '@grpc/grpc-js/build/src/call'; import type { AsyncGeneratorReadableStreamClient } from '@/grpc/types'; import Logger from '@matrixai/logger'; import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; -import { GRPCClient, utils as grpcUtils } from '@/grpc'; +import GRPCClient from '@/grpc/GRPCClient'; +import * as grpcUtils from '@/grpc/utils'; import * as clientUtils from '@/client/utils'; import { TestServiceClient } from '@/proto/js/polykey/v1/test_service_grpc_pb'; diff --git a/tests/grpc/utils/testService.ts b/tests/grpc/utils/testService.ts index 1297c354c..38cd50128 100644 --- a/tests/grpc/utils/testService.ts +++ b/tests/grpc/utils/testService.ts @@ -9,7 +9,8 @@ import type { SessionToken } from '@/sessions/types'; import type { ITestServiceServer } from '@/proto/js/polykey/v1/test_service_grpc_pb'; import Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; -import { utils as grpcUtils, errors as grpcErrors } from '@/grpc'; +import * as grpcUtils from '@/grpc/utils'; +import * as grpcErrors from '@/grpc/errors'; import * as clientUtils from '@/client/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import { sleep } from '@/utils'; From 4478a0627cc591dd2ed80f94e60185d8279739f5 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Sat, 7 May 2022 17:41:51 +1000 Subject: [PATCH 010/137] fix: integrating db changes into ACL --- src/acl/ACL.ts | 719 +++++++++++++++++++++++---------------------- src/locks/Locks.ts | 115 -------- src/locks/index.ts | 1 - 3 files changed, 365 insertions(+), 470 deletions(-) delete mode 100644 src/locks/Locks.ts delete mode 100644 src/locks/index.ts diff --git a/src/acl/ACL.ts b/src/acl/ACL.ts index 02b2868ff..6245ebace 100644 --- a/src/acl/ACL.ts +++ b/src/acl/ACL.ts @@ -5,7 +5,6 @@ import type { Permission, VaultActions, } from './types'; -import type { Locks } from '../locks'; import type { NodeId } from '../nodes/types'; import type { GestaltAction } from '../gestalts/types'; import type { VaultAction, VaultId } from '../vaults/types'; @@ -18,6 +17,7 @@ import { ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { utils as dbUtils } from '@matrixai/db'; +import { Lock, LockBox } from '@matrixai/async-locks'; import { withF } from '@matrixai/resources'; import * as aclUtils from './utils'; import * as aclErrors from './errors'; @@ -46,7 +46,7 @@ class ACL { protected logger: Logger; protected db: DB; - protected locks: Locks; + protected locks: LockBox = new LockBox(); protected aclDbPath: LevelPath = [this.constructor.name]; /** @@ -120,6 +120,23 @@ class ACL { this.logger.info(`Destroyed ${this.constructor.name}`); } + @ready(new aclErrors.ErrorACLNotRunning()) + public async withTransactionF( + ...params: [ + ...keyPaths: Array, + f: (tran: DBTransaction) => Promise, + ] + ): Promise { + const f = params.pop() as (tran: DBTransaction) => Promise; + const lockRequests = (params as Array).map< + [KeyPath, typeof Lock] + >((keyPath) => [keyPath, Lock]); + return withF( + [this.db.transaction(), this.locks.lock(...lockRequests)], + ([tran]) => f(tran), + ); + } + @ready(new aclErrors.ErrorACLNotRunning()) public async sameNodePerm( nodeId1: NodeId, @@ -135,15 +152,8 @@ class ACL { nodeId2.toBuffer(), ] as unknown as KeyPath; if (tran == null) { - return withF( - [ - this.db.transaction(), - this.locks.lockRead( - dbUtils.keyPathToKey(nodeId1Path).toString('binary'), - dbUtils.keyPathToKey(nodeId2Path).toString('binary'), - ), - ], - async ([tran]) => this.sameNodePerm(nodeId1, nodeId2, tran), + return this.withTransactionF(nodeId1Path, nodeId2Path, async (tran) => + this.sameNodePerm(nodeId1, nodeId2, tran), ); } const permId1 = await tran.get(nodeId1Path, true); @@ -157,7 +167,7 @@ class ACL { } @ready(new aclErrors.ErrorACLNotRunning()) - public async getNodePerms(): Promise>> { + public async getNodePerms(tran?: DBTransaction): Promise>> { return await this._transaction(async () => { const permIds: Record< PermissionIdString, @@ -198,7 +208,7 @@ class ACL { } @ready(new aclErrors.ErrorACLNotRunning()) - public async getVaultPerms(): Promise< + public async getVaultPerms(tran?: DBTransaction): Promise< Record> > { return await this._transaction(async () => { @@ -261,22 +271,29 @@ class ACL { * Any node id is acceptable */ @ready(new aclErrors.ErrorACLNotRunning()) - public async getNodePerm(nodeId: NodeId): Promise { - return await this._transaction(async () => { - const permId = await this.db.get( - this.aclNodesDbDomain, - nodeId.toBuffer(), - true, + public async getNodePerm( + nodeId: NodeId, + tran?: DBTransaction, + ): Promise { + const nodeIdPath = [ + ...this.aclNodesDbPath, + nodeId.toBuffer(), + ] as unknown as KeyPath; + if (tran == null) { + return this.withTransactionF(nodeIdPath, async (tran) => + this.getNodePerm(nodeId, tran), ); - if (permId == null) { - return; - } - const perm = (await this.db.get( - this.aclPermsDbDomain, - permId, - )) as Ref; - return perm.object; - }); + } + const permId = await tran.get(nodeIdPath, true); + if (permId == null) { + return; + } + const permIdPath = [ + ...this.aclPermsDbPath, + permId, + ] as unknown as KeyPath; + const perm = (await tran.get(permIdPath)) as Ref; + return perm.object; } /** @@ -287,127 +304,144 @@ class ACL { @ready(new aclErrors.ErrorACLNotRunning()) public async getVaultPerm( vaultId: VaultId, + tran?: DBTransaction, ): Promise> { - return await this._transaction(async () => { - const nodeIds = await this.db.get>( - this.aclVaultsDbDomain, - vaultId.toBuffer(), + const vaultIdPath = [ + ...this.aclVaultsDbPath, + vaultId.toBuffer(), + ] as unknown as KeyPath; + if (tran == null) { + return this.withTransactionF(vaultIdPath, async (tran) => + this.getVaultPerm(vaultId, tran), + ); + } + const nodeIds = await tran.get>( + vaultIdPath + ); + if (nodeIds == null) { + return {}; + } + const perms: Record = {}; + const nodeIdsGc: Set = new Set(); + for (const nodeIdString in nodeIds) { + const nodeId: NodeId = IdInternal.fromString(nodeIdString); + const nodeIdPath = [ + ...this.aclNodesDbPath, + nodeId.toBuffer(), + ] as unknown as KeyPath; + const permId = await tran.get( + nodeIdPath, + true, ); - if (nodeIds == null) { - return {}; + if (permId == null) { + // Invalid node id + nodeIdsGc.add(nodeId); + continue; } - const perms: Record = {}; - const nodeIdsGc: Set = new Set(); - for (const nodeIdString in nodeIds) { - const nodeId: NodeId = IdInternal.fromString(nodeIdString); - const permId = await this.db.get( - this.aclNodesDbDomain, - nodeId.toBuffer(), - true, - ); - if (permId == null) { - // Invalid node id - nodeIdsGc.add(nodeId); - continue; - } - const permRef = (await this.db.get( - this.aclPermsDbDomain, - permId, - )) as Ref; - if (!(vaultId in permRef.object.vaults)) { - // Vault id is missing from the perm - nodeIdsGc.add(nodeId); - continue; - } - perms[nodeId] = permRef.object; + const permIdPath = [ + ...this.aclPermsDbPath, + permId, + ] as unknown as KeyPath; + const permRef = (await tran.get( + permIdPath, + )) as Ref; + if (!(vaultId in permRef.object.vaults)) { + // Vault id is missing from the perm + nodeIdsGc.add(nodeId); + continue; } - if (nodeIdsGc.size > 0) { - // Remove invalid node ids - for (const nodeId of nodeIdsGc) { - delete nodeIds[nodeId]; - } - await this.db.put(this.aclVaultsDbDomain, vaultId.toBuffer(), nodeIds); + perms[nodeId] = permRef.object; + } + if (nodeIdsGc.size > 0) { + // Remove invalid node ids + for (const nodeId of nodeIdsGc) { + delete nodeIds[nodeId]; } - return perms; - }); + await tran.put(vaultIdPath, nodeIds); + } + return perms; } @ready(new aclErrors.ErrorACLNotRunning()) public async setNodeAction( nodeId: NodeId, action: GestaltAction, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - const permId = await this.db.get( - this.aclNodesDbDomain, - nodeId.toBuffer(), - true, + const nodeIdPath = [ + ...this.aclNodesDbPath, + nodeId.toBuffer(), + ] as unknown as KeyPath; + if (tran == null) { + return this.withTransactionF(nodeIdPath, async (tran) => + this.setNodeAction(nodeId, action, tran), ); - const ops: Array = []; - if (permId == null) { - const permId = await this.generatePermId(); - const permRef = { - count: 1, - object: { - gestalt: { - [action]: null, - }, - vaults: {}, - }, - }; - ops.push( - { - type: 'put', - domain: this.aclPermsDbDomain, - key: permId.toBuffer(), - value: permRef, - }, - { - type: 'put', - domain: this.aclNodesDbDomain, - key: nodeId.toBuffer(), - value: permId.toBuffer(), - raw: true, + } + const permId = await tran.get( + nodeIdPath, + true, + ); + if (permId == null) { + const permId = this.generatePermId(); + const permRef = { + count: 1, + object: { + gestalt: { + [action]: null, }, - ); - } else { - const permRef = (await this.db.get( - this.aclPermsDbDomain, - permId, - )) as Ref; - permRef.object.gestalt[action] = null; - ops.push({ - type: 'put', - domain: this.aclPermsDbDomain, - key: permId, - value: permRef, - }); - } - await this.db.batch(ops); - }); + vaults: {}, + }, + }; + const permIdPath = [ + ...this.aclPermsDbPath, + permId.toBuffer(), + ] as unknown as KeyPath; + await tran.put(permIdPath, permRef); + await tran.put(nodeIdPath, permId.toBuffer()); + } else { + const permIdPath = [ + ...this.aclPermsDbPath, + permId, + ] as unknown as KeyPath; + const permRef = (await tran.get( + permIdPath + )) as Ref; + permRef.object.gestalt[action] = null; + await tran.put(permIdPath, permRef); + } } @ready(new aclErrors.ErrorACLNotRunning()) public async unsetNodeAction( nodeId: NodeId, action: GestaltAction, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - const permId = await this.db.get( - this.aclNodesDbDomain, - nodeId.toBuffer(), - true, + const nodeIdPath = [ + ...this.aclNodesDbPath, + nodeId.toBuffer(), + ] as unknown as KeyPath; + if (tran == null) { + return this.withTransactionF(nodeIdPath, async (tran) => + this.unsetNodeAction(nodeId, action, tran), ); - if (permId == null) { - return; - } - const permRef = (await this.db.get( - this.aclPermsDbDomain, - permId, - )) as Ref; - delete permRef.object.gestalt[action]; - await this.db.put(this.aclPermsDbDomain, permId, permRef); - }); + } + const permId = await tran.get( + nodeIdPath, + true, + ); + if (permId == null) { + return; + } + const permIdPath = [ + ...this.aclPermsDbPath, + permId, + ] as unknown as KeyPath; + const permRef = (await tran.get( + permIdPath + )) as Ref; + delete permRef.object.gestalt[action]; + await tran.put(permIdPath, permRef); } @ready(new aclErrors.ErrorACLNotRunning()) @@ -415,55 +449,49 @@ class ACL { vaultId: VaultId, nodeId: NodeId, action: VaultAction, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - const nodeIds = - (await this.db.get>( - this.aclVaultsDbDomain, - vaultId.toBuffer(), - )) ?? {}; - const permId = await this.db.get( - this.aclNodesDbDomain, - nodeId.toBuffer(), - true, + const vaultIdPath = [ + ...this.aclVaultsDbPath, + vaultId.toBuffer(), + ] as unknown as KeyPath; + const nodeIdPath = [ + ...this.aclNodesDbPath, + nodeId.toBuffer(), + ] as unknown as KeyPath; + if (tran == null) { + return this.withTransactionF(vaultIdPath, nodeIdPath, async (tran) => + this.setVaultAction(vaultId, nodeId, action, tran), ); - if (permId == null) { - throw new aclErrors.ErrorACLNodeIdMissing(); - } - nodeIds[nodeId] = null; - const permRef = (await this.db.get( - this.aclPermsDbDomain, - permId, - )) as Ref; - let actions: VaultActions | undefined = permRef.object.vaults[vaultId]; - if (actions == null) { - actions = {}; - permRef.object.vaults[vaultId] = actions; - } - actions[action] = null; - const ops: Array = [ - { - type: 'put', - domain: this.aclPermsDbDomain, - key: permId, - value: permRef, - }, - { - type: 'put', - domain: this.aclNodesDbDomain, - key: nodeId.toBuffer(), - value: permId, - raw: true, - }, - { - type: 'put', - domain: this.aclVaultsDbDomain, - key: vaultId.toBuffer(), - value: nodeIds, - }, - ]; - await this.db.batch(ops); - }); + } + const nodeIds = + (await tran.get>( + vaultIdPath + )) ?? {}; + const permId = await tran.get( + nodeIdPath, + true, + ); + if (permId == null) { + throw new aclErrors.ErrorACLNodeIdMissing(); + } + nodeIds[nodeId] = null; + const permIdPath = [ + ...this.aclPermsDbPath, + permId, + ] as unknown as KeyPath; + const permRef = (await this.db.get( + permIdPath, + )) as Ref; + let actions: VaultActions | undefined = permRef.object.vaults[vaultId]; + if (actions == null) { + actions = {}; + permRef.object.vaults[vaultId] = actions; + } + actions[action] = null; + await tran.put(permIdPath, permRef); + await tran.put(nodeIdPath, permId); + await tran.put(vaultIdPath, nodeIds); } @ready(new aclErrors.ErrorACLNotRunning()) @@ -471,34 +499,47 @@ class ACL { vaultId: VaultId, nodeId: NodeId, action: VaultAction, + tran?: DBTransaction, ): Promise { - await this._transaction(async () => { - const nodeIds = await this.db.get>( - this.aclVaultsDbDomain, - vaultId.toBuffer(), - ); - if (nodeIds == null || !(nodeId in nodeIds)) { - return; - } - const permId = await this.db.get( - this.aclNodesDbDomain, - nodeId.toBuffer(), - true, + const vaultIdPath = [ + ...this.aclVaultsDbPath, + vaultId.toBuffer(), + ] as unknown as KeyPath; + const nodeIdPath = [ + ...this.aclNodesDbPath, + nodeId.toBuffer(), + ] as unknown as KeyPath; + if (tran == null) { + return this.withTransactionF(vaultIdPath, nodeIdPath, async (tran) => + this.unsetVaultAction(vaultId, nodeId, action, tran), ); - if (permId == null) { - return; - } - const permRef = (await this.db.get( - this.aclPermsDbDomain, - permId, - )) as Ref; - const actions: VaultActions | undefined = permRef.object.vaults[vaultId]; - if (actions == null) { - return; - } - delete actions[action]; - await this.db.put(this.aclPermsDbDomain, permId, permRef); - }); + } + const nodeIds = await tran.get>( + vaultIdPath + ); + if (nodeIds == null || !(nodeId in nodeIds)) { + return; + } + const permId = await tran.get( + nodeIdPath, + true, + ); + if (permId == null) { + return; + } + const permIdPath = [ + ...this.aclPermsDbPath, + permId, + ] as unknown as KeyPath; + const permRef = (await tran.get( + permIdPath + )) as Ref; + const actions: VaultActions | undefined = permRef.object.vaults[vaultId]; + if (actions == null) { + return; + } + delete actions[action]; + await tran.put(permIdPath, permRef); } /** @@ -510,24 +551,21 @@ class ACL { public async setNodesPerm( nodeIds: Array, perm: Permission, + tran?: DBTransaction, ): Promise { - await this._transaction(async () => { - const ops = await this.setNodesPermOps(nodeIds, perm); - await this.db.batch(ops); - }); - } - - @ready(new aclErrors.ErrorACLNotRunning()) - public async setNodesPermOps( - nodeIds: Array, - perm: Permission, - ): Promise> { - const ops: Array = []; + const nodeIdPaths = nodeIds.map((nodeId) => [ + ...this.aclNodesDbPath, + nodeId.toBuffer(), + ] as unknown as KeyPath); + if (tran == null) { + return this.withTransactionF(...nodeIdPaths, async (tran) => + this.setNodesPerm(nodeIds, perm, tran), + ); + } const permIdCounts: Record = {}; - for (const nodeId of nodeIds) { - const permIdBuffer = await this.db.get( - this.aclNodesDbDomain, - nodeId.toBuffer(), + for (const nodeIdPath of nodeIdPaths) { + const permIdBuffer = await tran.get( + nodeIdPath, true, ); if (permIdBuffer == null) { @@ -538,196 +576,165 @@ class ACL { } for (const permIdString in permIdCounts) { const permId = IdInternal.fromString(permIdString); - const permRef = (await this.db.get( - this.aclPermsDbDomain, + const permIdPath = [ + ...this.aclPermsDbPath, permId.toBuffer(), + ] as unknown as KeyPath; + const permRef = (await tran.get( + permIdPath, )) as Ref; permRef.count = permRef.count - permIdCounts[permId]; if (permRef.count === 0) { - ops.push({ - type: 'del', - domain: this.aclPermsDbDomain, - key: permId.toBuffer(), - }); + await tran.del(permIdPath); } else { - ops.push({ - type: 'put', - domain: this.aclPermsDbDomain, - key: permId.toBuffer(), - value: permRef, - }); + await tran.put(permIdPath, permRef); } } - const permId = await this.generatePermId(); + const permId = this.generatePermId(); const permRef = { count: nodeIds.length, object: perm, }; - ops.push({ - domain: this.aclPermsDbDomain, - type: 'put', - key: permId.toBuffer(), - value: permRef, - }); - for (const nodeId of nodeIds) { - ops.push({ - domain: this.aclNodesDbDomain, - type: 'put', - key: nodeId.toBuffer(), - value: permId.toBuffer(), - raw: true, - }); + const permIdPath = [ + ...this.aclPermsDbPath, + permId.toBuffer(), + ] as unknown as KeyPath; + await tran.put(permIdPath, permRef); + for (const nodeIdPath of nodeIdPaths) { + await tran.put(nodeIdPath, permId.toBuffer()); } - return ops; - } - - @ready(new aclErrors.ErrorACLNotRunning()) - public async setNodePerm(nodeId: NodeId, perm: Permission): Promise { - await this._transaction(async () => { - const ops = await this.setNodePermOps(nodeId, perm); - await this.db.batch(ops); - }); } @ready(new aclErrors.ErrorACLNotRunning()) - public async setNodePermOps( + public async setNodePerm( nodeId: NodeId, perm: Permission, - ): Promise> { - const permId = await this.db.get( - this.aclNodesDbDomain, + tran?: DBTransaction, + ): Promise { + const nodeIdPath = [ + ...this.aclNodesDbPath, nodeId.toBuffer(), + ] as unknown as KeyPath; + if (tran == null) { + return this.withTransactionF(nodeIdPath, async (tran) => + this.setNodePerm(nodeId, perm, tran), + ); + } + const permId = await tran.get( + nodeIdPath, true, ); - const ops: Array = []; if (permId == null) { - const permId = await this.generatePermId(); + const permId = this.generatePermId(); const permRef = { count: 1, object: perm, }; - ops.push( - { - type: 'put', - domain: this.aclPermsDbDomain, - key: permId.toBuffer(), - value: permRef, - }, - { - type: 'put', - domain: this.aclNodesDbDomain, - key: nodeId.toBuffer(), - value: permId.toBuffer(), - raw: true, - }, - ); + const permIdPath = [ + ...this.aclPermsDbPath, + permId.toBuffer(), + ] as unknown as KeyPath; + await tran.put(permIdPath, permRef); + await tran.put(nodeIdPath, permId.toBuffer()); } else { // The entire gestalt's perm gets replaced, therefore the count stays the same - const permRef = (await this.db.get( - this.aclPermsDbDomain, + const permIdPath = [ + ...this.aclPermsDbPath, permId, + ] as unknown as KeyPath; + const permRef = (await tran.get( + permIdPath, )) as Ref; permRef.object = perm; - ops.push({ - type: 'put', - domain: this.aclPermsDbDomain, - key: permId, - value: permRef, - }); + await tran.put(permIdPath, permRef); } - return ops; } @ready(new aclErrors.ErrorACLNotRunning()) - public async unsetNodePerm(nodeId: NodeId): Promise { - await this._transaction(async () => { - const ops = await this.unsetNodePermOps(nodeId); - await this.db.batch(ops); - }); - } - - @ready(new aclErrors.ErrorACLNotRunning()) - public async unsetNodePermOps(nodeId: NodeId): Promise> { - const permId = await this.db.get( - this.aclNodesDbDomain, + public async unsetNodePerm( + nodeId: NodeId, + tran?: DBTransaction, + ): Promise { + const nodeIdPath = [ + ...this.aclNodesDbPath, nodeId.toBuffer(), + ] as unknown as KeyPath; + if (tran == null) { + return this.withTransactionF(nodeIdPath, async (tran) => + this.unsetNodePerm(nodeId, tran), + ); + } + const permId = await tran.get( + nodeIdPath, true, ); if (permId == null) { - return []; + return; } - const ops: Array = []; - const permRef = (await this.db.get( - this.aclPermsDbDomain, + const permIdPath = [ + ...this.aclNodesDbPath, permId, + ] as unknown as KeyPath; + const permRef = (await tran.get( + permIdPath, )) as Ref; const count = --permRef.count; if (count === 0) { - ops.push({ - type: 'del', - domain: this.aclPermsDbDomain, - key: permId, - }); + await tran.del(permIdPath); } else { - ops.push({ - type: 'put', - domain: this.aclPermsDbDomain, - key: permId, - value: permRef, - }); + await tran.put(permIdPath, permRef); } - ops.push({ - type: 'del', - domain: this.aclNodesDbDomain, - key: nodeId.toBuffer(), - }); + await tran.del(nodeIdPath); // We do not remove the node id from the vaults // they can be removed later upon inspection - return ops; } @ready(new aclErrors.ErrorACLNotRunning()) - public async unsetVaultPerms(vaultId: VaultId): Promise { - await this._transaction(async () => { - const nodeIds = await this.db.get>( - this.aclVaultsDbDomain, - vaultId.toBuffer(), + public async unsetVaultPerms( + vaultId: VaultId, + tran?: DBTransaction, + ): Promise { + const vaultIdPath = [ + ...this.aclVaultsDbPath, + vaultId.toBuffer(), + ] as unknown as KeyPath; + if (tran == null) { + return this.withTransactionF(vaultIdPath, async (tran) => + this.unsetVaultPerms(vaultId, tran), ); - if (nodeIds == null) { - return; - } - const ops: Array = []; - for (const nodeIdString in nodeIds) { - const nodeId: NodeId = IdInternal.fromString(nodeIdString); - const permId = await this.db.get( - this.aclNodesDbDomain, - nodeId.toBuffer(), - true, - ); - // Skip if the nodeId doesn't exist - // this means that it previously been removed - if (permId == null) { - continue; - } - const perm = (await this.db.get( - this.aclPermsDbDomain, - permId, - )) as Ref; - delete perm.object.vaults[vaultId]; - ops.push({ - type: 'put', - domain: this.aclPermsDbDomain, - key: permId, - value: perm, - }); + } + const nodeIds = await tran.get>( + vaultIdPath, + ); + if (nodeIds == null) { + return; + } + for (const nodeIdString in nodeIds) { + const nodeId: NodeId = IdInternal.fromString(nodeIdString); + const nodeIdPath = [ + ...this.aclNodesDbPath, + nodeId.toBuffer(), + ] as unknown as KeyPath; + const permId = await tran.get( + nodeIdPath, + true, + ); + // Skip if the nodeId doesn't exist + // this means that it previously been removed + if (permId == null) { + continue; } - ops.push({ - type: 'del', - domain: this.aclVaultsDbDomain, - key: vaultId.toBuffer(), - }); - await this.db.batch(ops); - }); + const permIdPath = [ + ...this.aclPermsDbPath, + permId, + ] as unknown as KeyPath; + const perm = (await tran.get( + permIdPath, + )) as Ref; + delete perm.object.vaults[vaultId]; + await tran.put(permIdPath, perm); + } + await tran.del(vaultIdPath); } @ready(new aclErrors.ErrorACLNotRunning()) @@ -735,6 +742,7 @@ class ACL { nodeId: NodeId, nodeIdsJoin: Array, perm?: Permission, + tran?: DBTransaction, ): Promise { await this._transaction(async () => { const ops = await this.joinNodePermOps(nodeId, nodeIdsJoin, perm); @@ -747,6 +755,7 @@ class ACL { nodeId: NodeId, nodeIdsJoin: Array, perm?: Permission, + tran?: DBTransaction, ): Promise> { const permId = await this.db.get( this.aclNodesDbDomain, @@ -817,6 +826,7 @@ class ACL { public async joinVaultPerms( vaultId: VaultId, vaultIdsJoin: Array, + tran?: DBTransaction, ): Promise { await this._transaction(async () => { const ops = await this.joinVaultPermsOps(vaultId, vaultIdsJoin); @@ -828,6 +838,7 @@ class ACL { private async joinVaultPermsOps( vaultId: VaultId, vaultIdsJoin: Array, + tran: DBTransaction, ): Promise> { const nodeIds = await this.db.get>( this.aclVaultsDbDomain, diff --git a/src/locks/Locks.ts b/src/locks/Locks.ts deleted file mode 100644 index 2434d30dd..000000000 --- a/src/locks/Locks.ts +++ /dev/null @@ -1,115 +0,0 @@ -import type { ResourceAcquire, ResourceRelease } from '@matrixai/resources'; -import type { NonEmptyArray } from '../types'; -import { RWLockWriter } from '@matrixai/async-locks'; - -/** - * Generic dynamic read-write lock collection - * This enables advisory-locking across all domains - */ -class Locks { - protected _locks: Map; - - get locks(): ReadonlyMap { - return this._locks; - } - - /** - * Read-lock a sequence of ids - * The ids will be sorted before locking to ensure lock-hierarchy - * in order to prevent deadlocks - */ - public lockRead( - ...ids: NonEmptyArray - ): ResourceAcquire> { - return async () => { - ids.sort(); - const locks: Array<[string, ResourceRelease, RWLockWriter]> = []; - for (const id of ids) { - let lock = this._locks.get(id); - if (lock == null) { - lock = new RWLockWriter(); - this._locks.set(id, lock); - } - let lockRelease: ResourceRelease; - try { - [lockRelease] = await lock.acquireRead(); - } catch (e) { - // Release all intermediate locks in reverse order - locks.reverse(); - for (const [id, lockRelease, lock] of locks) { - await lockRelease(); - if (!lock!.isLocked()) { - this._locks.delete(id); - } - } - throw e; - } - locks.push([id, lockRelease, lock]); - } - return [ - async () => { - // Release all locks in reverse order - locks.reverse(); - for (const [id, lockRelease, lock] of locks) { - await lockRelease(); - if (!lock!.isLocked()) { - this._locks.delete(id); - } - } - }, - locks.map(([, , lock]) => lock) as NonEmptyArray, - ]; - }; - } - - /** - * Write-lock a sequence of ids - * The ids will be sorted before locking to ensure lock-hierarchy - * in order to prevent deadlocks - */ - public lockWrite( - ...ids: NonEmptyArray - ): ResourceAcquire> { - return async () => { - ids.sort(); - const locks: Array<[string, ResourceRelease, RWLockWriter]> = []; - for (const id of ids) { - let lock = this._locks.get(id); - if (lock == null) { - lock = new RWLockWriter(); - this._locks.set(id, lock); - } - let lockRelease: ResourceRelease; - try { - [lockRelease] = await lock.acquireWrite(); - } catch (e) { - // Release all intermediate locks in reverse order - locks.reverse(); - for (const [id, lockRelease, lock] of locks) { - await lockRelease(); - if (!lock!.isLocked()) { - this._locks.delete(id); - } - } - throw e; - } - locks.push([id, lockRelease, lock]); - } - return [ - async () => { - // Release all locks in reverse order - locks.reverse(); - for (const [id, lockRelease, lock] of locks) { - await lockRelease(); - if (!lock!.isLocked()) { - this._locks.delete(id); - } - } - }, - locks.map(([, , lock]) => lock) as NonEmptyArray, - ]; - }; - } -} - -export default Locks; diff --git a/src/locks/index.ts b/src/locks/index.ts deleted file mode 100644 index fe97431ee..000000000 --- a/src/locks/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Locks } from './Locks'; From 74b390db103cb6af66469d3d44c609ced04ee525 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Mon, 9 May 2022 16:51:38 +1000 Subject: [PATCH 011/137] fix: changing `es6` to `es2021` in `./eslintrc` --- .eslintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc b/.eslintrc index d53f180f4..c8db5d863 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,7 @@ "env": { "browser": true, "commonjs": true, - "es6": true, + "es2021": true, "node": true, "jest": true }, From 91aeb7303efbef50e1006567bace31f363e8688b Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Mon, 9 May 2022 16:52:06 +1000 Subject: [PATCH 012/137] fix: integrating db changes into ACL --- src/acl/ACL.ts | 642 +++++------ src/discovery/Discovery.ts | 12 +- src/gestalts/GestaltGraph.ts | 1186 +++++++++------------ src/identities/IdentitiesManager.ts | 179 ++-- src/nodes/NodeConnectionManager.ts | 8 +- src/nodes/NodeGraph.ts | 392 +++---- src/nodes/NodeManager.ts | 2 +- src/notifications/NotificationsManager.ts | 90 +- src/sigchain/Sigchain.ts | 2 +- tests/acl/ACL.test.ts | 73 +- tests/gestalts/GestaltGraph.test.ts | 4 +- tests/utils.ts | 210 ++-- 12 files changed, 1226 insertions(+), 1574 deletions(-) diff --git a/src/acl/ACL.ts b/src/acl/ACL.ts index 6245ebace..e97dc6c30 100644 --- a/src/acl/ACL.ts +++ b/src/acl/ACL.ts @@ -1,4 +1,4 @@ -import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; +import type { DB, DBTransaction, LevelPath } from '@matrixai/db'; import type { PermissionId, PermissionIdString, @@ -17,7 +17,6 @@ import { ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { utils as dbUtils } from '@matrixai/db'; -import { Lock, LockBox } from '@matrixai/async-locks'; import { withF } from '@matrixai/resources'; import * as aclUtils from './utils'; import * as aclErrors from './errors'; @@ -46,7 +45,6 @@ class ACL { protected logger: Logger; protected db: DB; - protected locks: LockBox = new LockBox(); protected aclDbPath: LevelPath = [this.constructor.name]; /** @@ -64,31 +62,6 @@ class ACL { */ protected aclVaultsDbPath: LevelPath = [this.constructor.name, 'vaults']; - // Lock across the usages of the DB - // it makes sense to use - // Symbol.for("key") - // symbol for is found in teh global registry, if it doesn't exist, it is added to the global registry and returned - // we can identify our locks by this - // to do this, we should have a global lock system in case we want to LOCK across multiple domains - // then other domains can also ensure those locks are being done as well - // and it is a like a PATH for a specific domain - // we can pass a keyPath - // and we can lock a level path - // well right now it can only be a keypath - // this.acquireLock(key: Buffer) - // and we identify our key buffer into a collection - // we can do a collection struce - // the symbols don't quite make sense, since we cannot attach a lock there anyway - // so we have to do this as well - // if it is not the DB problem we can just do this - // this.acquireLock() - - // KeyPath | string | Buffer - // locking an entire level is an interesting idea - // then you could have a very specific locking system - // No more single mutex - // protected lock: Mutex = new Mutex(); - protected generatePermId: () => PermissionId; constructor({ db, logger }: { db: DB; logger: Logger }) { @@ -122,19 +95,9 @@ class ACL { @ready(new aclErrors.ErrorACLNotRunning()) public async withTransactionF( - ...params: [ - ...keyPaths: Array, - f: (tran: DBTransaction) => Promise, - ] + f: (tran: DBTransaction) => Promise, ): Promise { - const f = params.pop() as (tran: DBTransaction) => Promise; - const lockRequests = (params as Array).map< - [KeyPath, typeof Lock] - >((keyPath) => [keyPath, Lock]); - return withF( - [this.db.transaction(), this.locks.lock(...lockRequests)], - ([tran]) => f(tran), - ); + return withF([this.db.transaction()], ([tran]) => f(tran)); } @ready(new aclErrors.ErrorACLNotRunning()) @@ -143,21 +106,19 @@ class ACL { nodeId2: NodeId, tran?: DBTransaction, ): Promise { - const nodeId1Path = [ - ...this.aclNodesDbPath, - nodeId1.toBuffer(), - ] as unknown as KeyPath; - const nodeId2Path = [ - ...this.aclNodesDbPath, - nodeId2.toBuffer(), - ] as unknown as KeyPath; if (tran == null) { - return this.withTransactionF(nodeId1Path, nodeId2Path, async (tran) => + return this.withTransactionF(async (tran) => this.sameNodePerm(nodeId1, nodeId2, tran), ); } - const permId1 = await tran.get(nodeId1Path, true); - const permId2 = await tran.get(nodeId2Path, true); + const permId1 = await tran.get( + [...this.aclNodesDbPath, nodeId1.toBuffer()], + true, + ); + const permId2 = await tran.get( + [...this.aclNodesDbPath, nodeId2.toBuffer()], + true, + ); if (permId1 != null && permId2 != null) { return IdInternal.fromBuffer(permId1).equals( IdInternal.fromBuffer(permId2), @@ -167,103 +128,92 @@ class ACL { } @ready(new aclErrors.ErrorACLNotRunning()) - public async getNodePerms(tran?: DBTransaction): Promise>> { - return await this._transaction(async () => { - const permIds: Record< - PermissionIdString, - Record - > = {}; - for await (const o of this.aclNodesDb.createReadStream()) { - const nodeId = IdInternal.fromBuffer((o as any).key); - const data = (o as any).value as Buffer; - const permId = IdInternal.fromBuffer( - await this.db.deserializeDecrypt(data, true), - ); - let nodePerm: Record; - if (permId in permIds) { - nodePerm = permIds[permId]; - // Get the first existing perm object - let perm: Permission; - for (const nodeId_ in nodePerm) { - perm = nodePerm[nodeId_]; - break; - } - // All perm objects are shared - nodePerm[nodeId] = perm!; - } else { - const permRef = (await this.db.get( - this.aclPermsDbDomain, - permId.toBuffer(), - )) as Ref; - nodePerm = { [nodeId]: permRef.object }; - permIds[permId] = nodePerm; + public async getNodePerms( + tran?: DBTransaction, + ): Promise>> { + if (tran == null) { + return this.withTransactionF(async (tran) => this.getNodePerms(tran)); + } + const permIds: Record> = {}; + for await (const [k, v] of tran.iterator(undefined, [ + ...this.aclNodesDbPath, + ])) { + const nodeId = IdInternal.fromBuffer(k); + const permId = IdInternal.fromBuffer(v); + let nodePerm: Record; + if (permId in permIds) { + nodePerm = permIds[permId]; + // Get the first existing perm object + let perm: Permission; + for (const nodeId_ in nodePerm) { + perm = nodePerm[nodeId_]; + break; } + // All perm objects are shared + nodePerm[nodeId] = perm!; + } else { + const permRef = (await tran.get( + [...this.aclPermsDbPath, permId.toBuffer()], + false, + )) as Ref; + nodePerm = { [nodeId]: permRef.object }; + permIds[permId] = nodePerm; } - const nodePerms_: Array> = []; - for (const permId in permIds) { - nodePerms_.push(permIds[permId]); - } - return nodePerms_; - }); + } + const nodePerms_: Array> = []; + for (const permId in permIds) { + nodePerms_.push(permIds[permId]); + } + return nodePerms_; } @ready(new aclErrors.ErrorACLNotRunning()) - public async getVaultPerms(tran?: DBTransaction): Promise< - Record> - > { - return await this._transaction(async () => { - const vaultPerms: Record> = {}; - const ops: Array = []; - for await (const o of this.aclVaultsDb.createReadStream()) { - const vaultIdBuffer = (o as any).key as Buffer; - const vaultId = IdInternal.fromBuffer(vaultIdBuffer); - const data = (o as any).value as Buffer; - const nodeIds = await this.db.deserializeDecrypt>( - data, - false, + public async getVaultPerms( + tran?: DBTransaction, + ): Promise>> { + if (tran == null) { + return this.withTransactionF(async (tran) => this.getVaultPerms(tran)); + } + const vaultPerms: Record> = {}; + for await (const [k, v] of tran.iterator(undefined, [ + ...this.aclVaultsDbPath, + ])) { + const vaultId = IdInternal.fromBuffer(k); + const nodeIds = dbUtils.deserialize>(v); + const nodePerm: Record = {}; + const nodeIdsGc: Set = new Set(); + for (const nodeIdString in nodeIds) { + const nodeId: NodeId = IdInternal.fromString(nodeIdString); + const permId = await tran.get( + [...this.aclNodesDbPath, nodeId.toBuffer()], + true, ); - const nodePerm: Record = {}; - const nodeIdsGc: Set = new Set(); - for (const nodeIdString in nodeIds) { - const nodeId: NodeId = IdInternal.fromString(nodeIdString); - const permId = await this.db.get( - this.aclNodesDbDomain, - nodeId.toBuffer(), - true, - ); - if (permId == null) { - // Invalid node id - nodeIdsGc.add(nodeId); - continue; - } - const permRef = (await this.db.get( - this.aclPermsDbDomain, - permId, - )) as Ref; - if (!(vaultId in permRef.object.vaults)) { - // Vault id is missing from the perm - nodeIdsGc.add(nodeId); - continue; - } - nodePerm[nodeId] = permRef.object; + if (permId == null) { + // Invalid node id + nodeIdsGc.add(nodeId); + continue; } - if (nodeIdsGc.size > 0) { - // Remove invalid node ids - for (const nodeId of nodeIdsGc) { - delete nodeIds[nodeId]; - } - ops.push({ - type: 'put', - domain: this.aclVaultsDbDomain, - key: vaultId.toBuffer(), - value: nodeIds, - }); + const permRef = (await tran.get( + [...this.aclPermsDbPath, permId], + false, + )) as Ref; + if (!(vaultId in permRef.object.vaults)) { + // Vault id is missing from the perm + nodeIdsGc.add(nodeId); + continue; } - vaultPerms[vaultId] = nodePerm; + nodePerm[nodeId] = permRef.object; } - await this.db.batch(ops); - return vaultPerms; - }); + if (nodeIdsGc.size > 0) { + // Remove invalid node ids + for (const nodeId of nodeIdsGc) { + delete nodeIds[nodeId]; + } + await tran.put([...this.aclVaultsDbPath, vaultId.toBuffer()], nodeIds); + } + vaultPerms[vaultId] = nodePerm; + } + return vaultPerms; } /** @@ -275,24 +225,22 @@ class ACL { nodeId: NodeId, tran?: DBTransaction, ): Promise { - const nodeIdPath = [ - ...this.aclNodesDbPath, - nodeId.toBuffer(), - ] as unknown as KeyPath; if (tran == null) { - return this.withTransactionF(nodeIdPath, async (tran) => + return this.withTransactionF(async (tran) => this.getNodePerm(nodeId, tran), ); } - const permId = await tran.get(nodeIdPath, true); + const permId = await tran.get( + [...this.aclNodesDbPath, nodeId.toBuffer()], + true, + ); if (permId == null) { return; } - const permIdPath = [ - ...this.aclPermsDbPath, - permId, - ] as unknown as KeyPath; - const perm = (await tran.get(permIdPath)) as Ref; + const perm = (await tran.get( + [...this.aclPermsDbPath, permId], + false, + )) as Ref; return perm.object; } @@ -306,17 +254,14 @@ class ACL { vaultId: VaultId, tran?: DBTransaction, ): Promise> { - const vaultIdPath = [ - ...this.aclVaultsDbPath, - vaultId.toBuffer(), - ] as unknown as KeyPath; if (tran == null) { - return this.withTransactionF(vaultIdPath, async (tran) => + return this.withTransactionF(async (tran) => this.getVaultPerm(vaultId, tran), ); } const nodeIds = await tran.get>( - vaultIdPath + [...this.aclVaultsDbPath, vaultId.toBuffer()], + false, ); if (nodeIds == null) { return {}; @@ -325,12 +270,8 @@ class ACL { const nodeIdsGc: Set = new Set(); for (const nodeIdString in nodeIds) { const nodeId: NodeId = IdInternal.fromString(nodeIdString); - const nodeIdPath = [ - ...this.aclNodesDbPath, - nodeId.toBuffer(), - ] as unknown as KeyPath; const permId = await tran.get( - nodeIdPath, + [...this.aclNodesDbPath, nodeId.toBuffer()], true, ); if (permId == null) { @@ -338,12 +279,9 @@ class ACL { nodeIdsGc.add(nodeId); continue; } - const permIdPath = [ - ...this.aclPermsDbPath, - permId, - ] as unknown as KeyPath; const permRef = (await tran.get( - permIdPath, + [...this.aclPermsDbPath, permId], + false, )) as Ref; if (!(vaultId in permRef.object.vaults)) { // Vault id is missing from the perm @@ -357,7 +295,11 @@ class ACL { for (const nodeId of nodeIdsGc) { delete nodeIds[nodeId]; } - await tran.put(vaultIdPath, nodeIds); + await tran.put( + [...this.aclVaultsDbPath, vaultId.toBuffer()], + nodeIds, + false, + ); } return perms; } @@ -368,17 +310,13 @@ class ACL { action: GestaltAction, tran?: DBTransaction, ): Promise { - const nodeIdPath = [ - ...this.aclNodesDbPath, - nodeId.toBuffer(), - ] as unknown as KeyPath; if (tran == null) { - return this.withTransactionF(nodeIdPath, async (tran) => + return this.withTransactionF(async (tran) => this.setNodeAction(nodeId, action, tran), ); } const permId = await tran.get( - nodeIdPath, + [...this.aclNodesDbPath, nodeId.toBuffer()], true, ); if (permId == null) { @@ -392,22 +330,23 @@ class ACL { vaults: {}, }, }; - const permIdPath = [ - ...this.aclPermsDbPath, + await tran.put( + [...this.aclPermsDbPath, permId.toBuffer()], + permRef, + false, + ); + await tran.put( + [...this.aclNodesDbPath, nodeId.toBuffer()], permId.toBuffer(), - ] as unknown as KeyPath; - await tran.put(permIdPath, permRef); - await tran.put(nodeIdPath, permId.toBuffer()); + true, + ); } else { - const permIdPath = [ - ...this.aclPermsDbPath, - permId, - ] as unknown as KeyPath; const permRef = (await tran.get( - permIdPath + [...this.aclPermsDbPath, permId], + false, )) as Ref; permRef.object.gestalt[action] = null; - await tran.put(permIdPath, permRef); + await tran.put([...this.aclPermsDbPath, permId], permRef, false); } } @@ -417,31 +356,24 @@ class ACL { action: GestaltAction, tran?: DBTransaction, ): Promise { - const nodeIdPath = [ - ...this.aclNodesDbPath, - nodeId.toBuffer(), - ] as unknown as KeyPath; if (tran == null) { - return this.withTransactionF(nodeIdPath, async (tran) => + return this.withTransactionF(async (tran) => this.unsetNodeAction(nodeId, action, tran), ); } const permId = await tran.get( - nodeIdPath, + [...this.aclNodesDbPath, nodeId.toBuffer()], true, ); if (permId == null) { return; } - const permIdPath = [ - ...this.aclPermsDbPath, - permId, - ] as unknown as KeyPath; const permRef = (await tran.get( - permIdPath + [...this.aclPermsDbPath, permId], + false, )) as Ref; delete permRef.object.gestalt[action]; - await tran.put(permIdPath, permRef); + await tran.put([...this.aclPermsDbPath, permId], permRef, false); } @ready(new aclErrors.ErrorACLNotRunning()) @@ -451,37 +383,27 @@ class ACL { action: VaultAction, tran?: DBTransaction, ): Promise { - const vaultIdPath = [ - ...this.aclVaultsDbPath, - vaultId.toBuffer(), - ] as unknown as KeyPath; - const nodeIdPath = [ - ...this.aclNodesDbPath, - nodeId.toBuffer(), - ] as unknown as KeyPath; if (tran == null) { - return this.withTransactionF(vaultIdPath, nodeIdPath, async (tran) => + return this.withTransactionF(async (tran) => this.setVaultAction(vaultId, nodeId, action, tran), ); } const nodeIds = (await tran.get>( - vaultIdPath + [...this.aclVaultsDbPath, vaultId.toBuffer()], + false, )) ?? {}; const permId = await tran.get( - nodeIdPath, + [...this.aclNodesDbPath, nodeId.toBuffer()], true, ); if (permId == null) { throw new aclErrors.ErrorACLNodeIdMissing(); } nodeIds[nodeId] = null; - const permIdPath = [ - ...this.aclPermsDbPath, - permId, - ] as unknown as KeyPath; - const permRef = (await this.db.get( - permIdPath, + const permRef = (await tran.get( + [...this.aclPermsDbPath, permId], + false, )) as Ref; let actions: VaultActions | undefined = permRef.object.vaults[vaultId]; if (actions == null) { @@ -489,9 +411,13 @@ class ACL { permRef.object.vaults[vaultId] = actions; } actions[action] = null; - await tran.put(permIdPath, permRef); - await tran.put(nodeIdPath, permId); - await tran.put(vaultIdPath, nodeIds); + await tran.put([...this.aclPermsDbPath, permId], permRef, false); + await tran.put([...this.aclNodesDbPath, nodeId.toBuffer()], permId, true); + await tran.put( + [...this.aclVaultsDbPath, vaultId.toBuffer()], + nodeIds, + false, + ); } @ready(new aclErrors.ErrorACLNotRunning()) @@ -501,45 +427,35 @@ class ACL { action: VaultAction, tran?: DBTransaction, ): Promise { - const vaultIdPath = [ - ...this.aclVaultsDbPath, - vaultId.toBuffer(), - ] as unknown as KeyPath; - const nodeIdPath = [ - ...this.aclNodesDbPath, - nodeId.toBuffer(), - ] as unknown as KeyPath; if (tran == null) { - return this.withTransactionF(vaultIdPath, nodeIdPath, async (tran) => + return this.withTransactionF(async (tran) => this.unsetVaultAction(vaultId, nodeId, action, tran), ); } const nodeIds = await tran.get>( - vaultIdPath + [...this.aclVaultsDbPath, vaultId.toBuffer()], + false, ); if (nodeIds == null || !(nodeId in nodeIds)) { return; } const permId = await tran.get( - nodeIdPath, + [...this.aclNodesDbPath, nodeId.toBuffer()], true, ); if (permId == null) { return; } - const permIdPath = [ - ...this.aclPermsDbPath, - permId, - ] as unknown as KeyPath; const permRef = (await tran.get( - permIdPath + [...this.aclPermsDbPath, permId], + false, )) as Ref; const actions: VaultActions | undefined = permRef.object.vaults[vaultId]; if (actions == null) { return; } delete actions[action]; - await tran.put(permIdPath, permRef); + await tran.put([...this.aclPermsDbPath, permId], permRef, false); } /** @@ -553,19 +469,15 @@ class ACL { perm: Permission, tran?: DBTransaction, ): Promise { - const nodeIdPaths = nodeIds.map((nodeId) => [ - ...this.aclNodesDbPath, - nodeId.toBuffer(), - ] as unknown as KeyPath); if (tran == null) { - return this.withTransactionF(...nodeIdPaths, async (tran) => + return this.withTransactionF(async (tran) => this.setNodesPerm(nodeIds, perm, tran), ); } const permIdCounts: Record = {}; - for (const nodeIdPath of nodeIdPaths) { + for (const nodeId of nodeIds) { const permIdBuffer = await tran.get( - nodeIdPath, + [...this.aclNodesDbPath, nodeId.toBuffer()], true, ); if (permIdBuffer == null) { @@ -576,18 +488,19 @@ class ACL { } for (const permIdString in permIdCounts) { const permId = IdInternal.fromString(permIdString); - const permIdPath = [ - ...this.aclPermsDbPath, - permId.toBuffer(), - ] as unknown as KeyPath; const permRef = (await tran.get( - permIdPath, + [...this.aclPermsDbPath, permId.toBuffer()], + false, )) as Ref; permRef.count = permRef.count - permIdCounts[permId]; if (permRef.count === 0) { - await tran.del(permIdPath); + await tran.del([...this.aclPermsDbPath, permId.toBuffer()]); } else { - await tran.put(permIdPath, permRef); + await tran.put( + [...this.aclPermsDbPath, permId.toBuffer()], + permRef, + false, + ); } } const permId = this.generatePermId(); @@ -595,13 +508,13 @@ class ACL { count: nodeIds.length, object: perm, }; - const permIdPath = [ - ...this.aclPermsDbPath, - permId.toBuffer(), - ] as unknown as KeyPath; - await tran.put(permIdPath, permRef); - for (const nodeIdPath of nodeIdPaths) { - await tran.put(nodeIdPath, permId.toBuffer()); + await tran.put([...this.aclPermsDbPath, permId.toBuffer()], permRef, false); + for (const nodeId of nodeIds) { + await tran.put( + [...this.aclNodesDbPath, nodeId.toBuffer()], + permId.toBuffer(), + true, + ); } } @@ -611,17 +524,13 @@ class ACL { perm: Permission, tran?: DBTransaction, ): Promise { - const nodeIdPath = [ - ...this.aclNodesDbPath, - nodeId.toBuffer(), - ] as unknown as KeyPath; if (tran == null) { - return this.withTransactionF(nodeIdPath, async (tran) => + return this.withTransactionF(async (tran) => this.setNodePerm(nodeId, perm, tran), ); } const permId = await tran.get( - nodeIdPath, + [...this.aclNodesDbPath, nodeId.toBuffer()], true, ); if (permId == null) { @@ -630,23 +539,24 @@ class ACL { count: 1, object: perm, }; - const permIdPath = [ - ...this.aclPermsDbPath, + await tran.put( + [...this.aclPermsDbPath, permId.toBuffer()], + permRef, + false, + ); + await tran.put( + [...this.aclNodesDbPath, nodeId.toBuffer()], permId.toBuffer(), - ] as unknown as KeyPath; - await tran.put(permIdPath, permRef); - await tran.put(nodeIdPath, permId.toBuffer()); + true, + ); } else { // The entire gestalt's perm gets replaced, therefore the count stays the same - const permIdPath = [ - ...this.aclPermsDbPath, - permId, - ] as unknown as KeyPath; const permRef = (await tran.get( - permIdPath, + [...this.aclPermsDbPath, permId], + false, )) as Ref; permRef.object = perm; - await tran.put(permIdPath, permRef); + await tran.put([...this.aclPermsDbPath, permId], permRef, false); } } @@ -655,36 +565,29 @@ class ACL { nodeId: NodeId, tran?: DBTransaction, ): Promise { - const nodeIdPath = [ - ...this.aclNodesDbPath, - nodeId.toBuffer(), - ] as unknown as KeyPath; if (tran == null) { - return this.withTransactionF(nodeIdPath, async (tran) => + return this.withTransactionF(async (tran) => this.unsetNodePerm(nodeId, tran), ); } const permId = await tran.get( - nodeIdPath, + [...this.aclNodesDbPath, nodeId.toBuffer()], true, ); if (permId == null) { return; } - const permIdPath = [ - ...this.aclNodesDbPath, - permId, - ] as unknown as KeyPath; const permRef = (await tran.get( - permIdPath, + [...this.aclPermsDbPath, permId], + false, )) as Ref; const count = --permRef.count; if (count === 0) { - await tran.del(permIdPath); + await tran.del([...this.aclPermsDbPath, permId]); } else { - await tran.put(permIdPath, permRef); + await tran.put([...this.aclPermsDbPath, permId], permRef, false); } - await tran.del(nodeIdPath); + await tran.del([...this.aclNodesDbPath, nodeId.toBuffer()]); // We do not remove the node id from the vaults // they can be removed later upon inspection } @@ -694,29 +597,22 @@ class ACL { vaultId: VaultId, tran?: DBTransaction, ): Promise { - const vaultIdPath = [ - ...this.aclVaultsDbPath, - vaultId.toBuffer(), - ] as unknown as KeyPath; if (tran == null) { - return this.withTransactionF(vaultIdPath, async (tran) => + return this.withTransactionF(async (tran) => this.unsetVaultPerms(vaultId, tran), ); } const nodeIds = await tran.get>( - vaultIdPath, + [...this.aclVaultsDbPath, vaultId.toBuffer()], + false, ); if (nodeIds == null) { return; } for (const nodeIdString in nodeIds) { const nodeId: NodeId = IdInternal.fromString(nodeIdString); - const nodeIdPath = [ - ...this.aclNodesDbPath, - nodeId.toBuffer(), - ] as unknown as KeyPath; const permId = await tran.get( - nodeIdPath, + [...this.aclNodesDbPath, nodeId.toBuffer()], true, ); // Skip if the nodeId doesn't exist @@ -724,17 +620,14 @@ class ACL { if (permId == null) { continue; } - const permIdPath = [ - ...this.aclPermsDbPath, - permId, - ] as unknown as KeyPath; const perm = (await tran.get( - permIdPath, + [...this.aclPermsDbPath, permId], + false, )) as Ref; delete perm.object.vaults[vaultId]; - await tran.put(permIdPath, perm); + await tran.put([...this.aclPermsDbPath, permId], perm, false); } - await tran.del(vaultIdPath); + await tran.del([...this.aclVaultsDbPath, vaultId.toBuffer()]); } @ready(new aclErrors.ErrorACLNotRunning()) @@ -744,40 +637,29 @@ class ACL { perm?: Permission, tran?: DBTransaction, ): Promise { - await this._transaction(async () => { - const ops = await this.joinNodePermOps(nodeId, nodeIdsJoin, perm); - await this.db.batch(ops); - }); - } - - @ready(new aclErrors.ErrorACLNotRunning()) - public async joinNodePermOps( - nodeId: NodeId, - nodeIdsJoin: Array, - perm?: Permission, - tran?: DBTransaction, - ): Promise> { - const permId = await this.db.get( - this.aclNodesDbDomain, - nodeId.toBuffer(), + if (tran == null) { + return this.withTransactionF(async (tran) => + this.joinNodePerm(nodeId, nodeIdsJoin, perm, tran), + ); + } + const permId = await tran.get( + [...this.aclNodesDbPath, nodeId.toBuffer()], true, ); if (permId == null) { throw new aclErrors.ErrorACLNodeIdMissing(); } - const ops: Array = []; - const permRef = (await this.db.get( - this.aclPermsDbDomain, - permId, + const permRef = (await tran.get( + [...this.aclPermsDbPath, permId], + false, )) as Ref; // Optionally replace the permission record for the target if (perm != null) { permRef.object = perm; } for (const nodeIdJoin of nodeIdsJoin) { - const permIdJoin = await this.db.get( - this.aclNodesDbDomain, - nodeIdJoin.toBuffer(), + const permIdJoin = await tran.get( + [...this.aclNodesDbPath, nodeIdJoin.toBuffer()], true, ); if (permIdJoin === permId) { @@ -785,41 +667,24 @@ class ACL { } ++permRef.count; if (permIdJoin != null) { - const permJoin = (await this.db.get( - this.aclPermsDbDomain, - permIdJoin, + const permJoin = (await tran.get( + [...this.aclPermsDbPath, permIdJoin], + false, )) as Ref; --permJoin.count; if (permJoin.count === 0) { - ops.push({ - type: 'del', - domain: this.aclPermsDbDomain, - key: permIdJoin, - }); + await tran.del([...this.aclPermsDbPath, permIdJoin]); } else { - ops.push({ - type: 'put', - domain: this.aclPermsDbDomain, - key: permIdJoin, - value: permJoin, - }); + await tran.put([...this.aclPermsDbPath, permIdJoin], permJoin, false); } } - ops.push({ - type: 'put', - domain: this.aclNodesDbDomain, - key: nodeIdJoin.toBuffer(), - value: permId, - raw: true, - }); - } - ops.push({ - type: 'put', - domain: this.aclPermsDbDomain, - key: permId, - value: permRef, - }); - return ops; + await tran.put( + [...this.aclNodesDbPath, nodeIdJoin.toBuffer()], + permId, + true, + ); + } + await tran.put([...this.aclPermsDbPath, permId], permRef, false); } @ready(new aclErrors.ErrorACLNotRunning()) @@ -828,32 +693,23 @@ class ACL { vaultIdsJoin: Array, tran?: DBTransaction, ): Promise { - await this._transaction(async () => { - const ops = await this.joinVaultPermsOps(vaultId, vaultIdsJoin); - await this.db.batch(ops); - }); - } - - @ready(new aclErrors.ErrorACLNotRunning()) - private async joinVaultPermsOps( - vaultId: VaultId, - vaultIdsJoin: Array, - tran: DBTransaction, - ): Promise> { - const nodeIds = await this.db.get>( - this.aclVaultsDbDomain, - vaultId.toBuffer(), + if (tran == null) { + return this.withTransactionF(async (tran) => + this.joinVaultPerms(vaultId, vaultIdsJoin, tran), + ); + } + const nodeIds = await tran.get>( + [...this.aclVaultsDbPath, vaultId.toBuffer()], + false, ); if (nodeIds == null) { throw new aclErrors.ErrorACLVaultIdMissing(); } - const ops: Array = []; const nodeIdsGc: Set = new Set(); for (const nodeIdString in nodeIds) { const nodeId: NodeId = IdInternal.fromString(nodeIdString); - const permId = await this.db.get( - this.aclNodesDbDomain, - nodeId.toBuffer(), + const permId = await tran.get( + [...this.aclNodesDbPath, nodeId.toBuffer()], true, ); if (permId == null) { @@ -861,9 +717,9 @@ class ACL { nodeIdsGc.add(nodeId); continue; } - const permRef = (await this.db.get( - this.aclPermsDbDomain, - permId, + const permRef = (await tran.get( + [...this.aclPermsDbPath, permId], + false, )) as Ref; if (!(vaultId in permRef.object.vaults)) { // Vault id is missing from the perm @@ -875,34 +731,26 @@ class ACL { for (const vaultIdJoin of vaultIdsJoin) { permRef.object.vaults[vaultIdJoin] = vaultActions; } - ops.push({ - type: 'put', - domain: this.aclPermsDbDomain, - key: permId, - value: permRef, - }); + await tran.put([...this.aclPermsDbPath, permId], permRef, false); } for (const vaultIdJoin of vaultIdsJoin) { - ops.push({ - type: 'put', - domain: this.aclVaultsDbDomain, - key: vaultIdJoin.toBuffer(), - value: nodeIds, - }); + await tran.put( + [...this.aclVaultsDbPath, vaultIdJoin.toBuffer()], + nodeIds, + false, + ); } if (nodeIdsGc.size > 0) { // Remove invalid node ids for (const nodeId of nodeIdsGc) { delete nodeIds[nodeId]; } - ops.push({ - type: 'put', - domain: this.aclVaultsDbDomain, - key: vaultId.toBuffer(), - value: nodeIds, - }); - } - return ops; + await tran.put( + [...this.aclVaultsDbPath, vaultId.toBuffer()], + nodeIds, + false, + ); + } } } diff --git a/src/discovery/Discovery.ts b/src/discovery/Discovery.ts index 900b6b63f..a6d6c1129 100644 --- a/src/discovery/Discovery.ts +++ b/src/discovery/Discovery.ts @@ -1,5 +1,4 @@ -import type { MutexInterface } from 'async-mutex'; -import type { DB, DBLevel } from '@matrixai/db'; +import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; import type { DiscoveryQueueId, DiscoveryQueueIdGenerator } from './types'; import type { NodeId, NodeInfo } from '../nodes/types'; import type NodeManager from '../nodes/NodeManager'; @@ -18,7 +17,6 @@ import type { Sigchain } from '../sigchain'; import type { KeyManager } from '../keys'; import type { ClaimIdEncoded, Claim, ClaimLinkIdentity } from '../claims/types'; import type { ChainData } from '../sigchain/types'; -import type { ResourceAcquire } from '../utils'; import { Mutex } from 'async-mutex'; import Logger from '@matrixai/logger'; import { @@ -27,6 +25,9 @@ import { status, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { IdInternal } from '@matrixai/id'; +import { withF } from '@matrixai/resources'; +import { Lock, LockBox } from '@matrixai/async-locks'; +import { utils as dbUtils } from '@matrixai/db'; import * as idUtils from '@matrixai/id/dist/utils'; import * as discoveryUtils from './utils'; import * as discoveryErrors from './errors'; @@ -88,9 +89,8 @@ class Discovery { this.discoveryDbDomain, 'queue', ]; - protected discoveryDb: DBLevel; - protected discoveryQueueDb: DBLevel; - protected lock: Mutex = new Mutex(); + protected discoveryDbPath: LevelPath = [this.constructor.name]; + protected discoveryQueueDbPath: LevelPath = [this.constructor.name, 'queue']; protected discoveryQueueIdGenerator: DiscoveryQueueIdGenerator; protected visitedVertices = new Set(); protected discoveryQueue: AsyncGenerator; diff --git a/src/gestalts/GestaltGraph.ts b/src/gestalts/GestaltGraph.ts index 4e9036d7a..0cb613a31 100644 --- a/src/gestalts/GestaltGraph.ts +++ b/src/gestalts/GestaltGraph.ts @@ -1,4 +1,4 @@ -import type { DB, DBLevel, DBOp } from '@matrixai/db'; +import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; import type { Gestalt, GestaltAction, @@ -10,14 +10,15 @@ import type { } from './types'; import type { NodeId, NodeInfo } from '../nodes/types'; import type { IdentityId, IdentityInfo, ProviderId } from '../identities/types'; -import type { ACL } from '../acl'; import type { Permission } from '../acl/types'; -import { Mutex } from 'async-mutex'; +import type ACL from '../acl/ACL'; import Logger from '@matrixai/logger'; import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; +import { utils as dbUtils } from '@matrixai/db'; +import { withF } from '@matrixai/resources'; import * as gestaltsUtils from './utils'; import * as gestaltsErrors from './errors'; import * as aclUtils from '../acl/utils'; @@ -30,22 +31,6 @@ interface GestaltGraph extends CreateDestroyStartStop {} new gestaltsErrors.ErrorGestaltsGraphDestroyed(), ) class GestaltGraph { - protected logger: Logger; - protected db: DB; - protected acl: ACL; - protected graphDbDomain: string = this.constructor.name; - protected graphMatrixDbDomain: Array = [this.graphDbDomain, 'matrix']; - protected graphNodesDbDomain: Array = [this.graphDbDomain, 'nodes']; - protected graphIdentitiesDbDomain: Array = [ - this.graphDbDomain, - 'identities', - ]; - protected graphDb: DBLevel; - protected graphMatrixDb: DBLevel; - protected graphNodesDb: DBLevel; - protected graphIdentitiesDb: DBLevel; - protected lock: Mutex = new Mutex(); - static async createGestaltGraph({ db, acl, @@ -64,38 +49,34 @@ class GestaltGraph { return gestaltGraph; } + protected logger: Logger; + protected db: DB; + protected acl: ACL; + protected gestaltGraphDbPath: LevelPath = [this.constructor.name]; + protected gestaltGraphMatrixDbPath: LevelPath = [ + this.constructor.name, + 'matrix', + ]; + protected gestaltGraphNodesDbPath: LevelPath = [ + this.constructor.name, + 'nodes', + ]; + protected gestaltGraphIdentitiesDbPath: LevelPath = [ + this.constructor.name, + 'identities', + ]; + constructor({ db, acl, logger }: { db: DB; acl: ACL; logger: Logger }) { this.logger = logger; this.db = db; this.acl = acl; } - get locked(): boolean { - return this.lock.isLocked(); - } - public async start({ fresh = false }: { fresh?: boolean } = {}) { this.logger.info(`Starting ${this.constructor.name}`); - const graphDb = await this.db.level(this.graphDbDomain); - const graphMatrixDb = await this.db.level( - this.graphMatrixDbDomain[1], - graphDb, - ); - const graphNodesDb = await this.db.level( - this.graphNodesDbDomain[1], - graphDb, - ); - const graphIdentitiesDb = await this.db.level( - this.graphIdentitiesDbDomain[1], - graphDb, - ); if (fresh) { - await graphDb.clear(); + await this.db.clear(this.gestaltGraphDbPath); } - this.graphDb = graphDb; - this.graphMatrixDb = graphMatrixDb; - this.graphNodesDb = graphNodesDb; - this.graphIdentitiesDb = graphIdentitiesDb; this.logger.info(`Started ${this.constructor.name}`); } @@ -106,200 +87,173 @@ class GestaltGraph { async destroy() { this.logger.info(`Destroying ${this.constructor.name}`); - const graphDb = await this.db.level(this.graphDbDomain); - await graphDb.clear(); + await this.db.clear(this.gestaltGraphDbPath); this.logger.info(`Destroyed ${this.constructor.name}`); } - /** - * Run several operations within the same lock - * This does not ensure atomicity of the underlying database - * Database atomicity still depends on the underlying operation - */ - public async transaction( - f: (gestaltGraph: GestaltGraph) => Promise, + @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) + public async withTransactionF( + f: (tran: DBTransaction) => Promise, ): Promise { - const release = await this.lock.acquire(); - try { - return await f(this); - } finally { - release(); - } - } - - /** - * Transaction wrapper that will not lock if the operation was executed - * within a transaction context - */ - public async _transaction(f: () => Promise): Promise { - if (this.lock.isLocked()) { - return await f(); - } else { - return await this.transaction(f); - } + return withF([this.db.transaction()], ([tran]) => f(tran)); } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async getGestalts(): Promise> { - return await this._transaction(async () => { - const unvisited: Map = new Map(); - for await (const o of this.graphMatrixDb.createReadStream()) { - const gK = (o as any).key.toString() as GestaltKey; - const data = (o as any).value as Buffer; - const gKs = await this.db.deserializeDecrypt( - data, - false, - ); - unvisited.set(gK, gKs); - } - const gestalts: Array = []; - let gestalt: Gestalt; - for (const gKSet of unvisited) { - gestalt = { - matrix: {}, - nodes: {}, - identities: {}, - }; - const gK = gKSet[0]; - const queue = [gK]; - while (true) { - const vertex = queue.shift(); - if (vertex == null) { - gestalts.push(gestalt); - break; - } - const gId = gestaltsUtils.ungestaltKey(vertex); - const vertexKeys = unvisited.get(vertex); - if (vertexKeys == null) { - // This should not happen - break; - } - gestalt.matrix[vertex] = vertexKeys; - if (gId.type === 'node') { - const nodeInfo = await this.db.get( - this.graphNodesDbDomain, - vertex as GestaltNodeKey, - ); - gestalt.nodes[vertex] = nodeInfo!; - } else if (gId.type === 'identity') { - const identityInfo = await this.db.get( - this.graphIdentitiesDbDomain, - vertex as GestaltIdentityKey, - ); - gestalt.identities[vertex] = identityInfo!; - } - unvisited.delete(vertex); - const neighbours: Array = Object.keys(vertexKeys).filter( - (k: GestaltKey) => unvisited.has(k), - ) as Array; - queue.push(...neighbours); + public async getGestalts(tran?: DBTransaction): Promise> { + if (tran == null) { + return this.withTransactionF(async (tran) => this.getGestalts(tran)); + } + const unvisited: Map = new Map(); + for await (const [k, v] of tran.iterator(undefined, [ + ...this.gestaltGraphMatrixDbPath, + ])) { + const gK = k.toString() as GestaltKey; + const gKs = dbUtils.deserialize(v); + unvisited.set(gK, gKs); + } + const gestalts: Array = []; + let gestalt: Gestalt; + for (const gKSet of unvisited) { + gestalt = { + matrix: {}, + nodes: {}, + identities: {}, + }; + const gK = gKSet[0]; + const queue = [gK]; + while (true) { + const vertex = queue.shift(); + if (vertex == null) { + gestalts.push(gestalt); + break; + } + const gId = gestaltsUtils.ungestaltKey(vertex); + const vertexKeys = unvisited.get(vertex); + if (vertexKeys == null) { + // This should not happen + break; } + gestalt.matrix[vertex] = vertexKeys; + if (gId.type === 'node') { + const vertexPath = [ + ...this.gestaltGraphNodesDbPath, + vertex as GestaltNodeKey, + ] as unknown as KeyPath; + const nodeInfo = await tran.get(vertexPath); + gestalt.nodes[vertex] = nodeInfo!; + } else if (gId.type === 'identity') { + const vertexPath = [ + ...this.gestaltGraphIdentitiesDbPath, + vertex as GestaltIdentityKey, + ] as unknown as KeyPath; + const identityInfo = await tran.get(vertexPath); + gestalt.identities[vertex] = identityInfo!; + } + unvisited.delete(vertex); + const neighbours: Array = Object.keys(vertexKeys).filter( + (k: GestaltKey) => unvisited.has(k), + ) as Array; + queue.push(...neighbours); } - return gestalts; - }); + } + return gestalts; } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async getGestaltByNode(nodeId: NodeId): Promise { + public async getGestaltByNode( + nodeId: NodeId, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getGestaltByNode(nodeId, tran), + ); + } const nodeKey = gestaltsUtils.keyFromNode(nodeId); - return this.getGestaltByKey(nodeKey); + return this.getGestaltByKey(nodeKey, tran); } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) public async getGestaltByIdentity( providerId: ProviderId, identityId: IdentityId, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getGestaltByIdentity(providerId, identityId, tran), + ); + } const identityKey = gestaltsUtils.keyFromIdentity(providerId, identityId); - return this.getGestaltByKey(identityKey); + return this.getGestaltByKey(identityKey, tran); } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async setIdentity(identityInfo: IdentityInfo): Promise { - return await this._transaction(async () => { - const ops = await this.setIdentityOps(identityInfo); - await this.db.batch(ops); - }); - } - - @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async setIdentityOps( + public async setIdentity( identityInfo: IdentityInfo, - ): Promise> { + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.setIdentity(identityInfo, tran), + ); + } const identityKey = gestaltsUtils.keyFromIdentity( identityInfo.providerId, identityInfo.identityId, ); + const identityKeyPath = [ + ...this.gestaltGraphMatrixDbPath, + identityKey, + ] as unknown as KeyPath; const identityKeyKeys = - (await this.db.get( - this.graphMatrixDbDomain, - identityKey, - )) ?? {}; - const ops: Array = [ - { - type: 'put', - domain: this.graphMatrixDbDomain, - key: identityKey, - value: identityKeyKeys, - }, - { - type: 'put', - domain: this.graphIdentitiesDbDomain, - key: identityKey, - value: identityInfo, - }, - ]; - return ops; - } - - @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async unsetIdentity(providerId: ProviderId, identityId: IdentityId) { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const ops = await this.unsetIdentityOps(providerId, identityId); - await this.db.batch(ops); - }); - }); + (await tran.get(identityKeyPath)) ?? {}; + await tran.put(identityKeyPath, identityKeyKeys); + const identityInfoPath = [ + ...this.gestaltGraphIdentitiesDbPath, + identityKey, + ] as unknown as KeyPath; + await tran.put(identityInfoPath, identityInfo); } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async unsetIdentityOps( + public async unsetIdentity( providerId: ProviderId, identityId: IdentityId, + tran?: DBTransaction, ) { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.unsetIdentity(providerId, identityId, tran), + ); + } const identityKey = gestaltsUtils.keyFromIdentity(providerId, identityId); - const identityKeyKeys = await this.db.get( - this.graphMatrixDbDomain, + const identityKeyPath = [ + ...this.gestaltGraphMatrixDbPath, identityKey, - ); - const ops: Array = []; + ] as unknown as KeyPath; + const identityKeyKeys = await tran.get(identityKeyPath); if (identityKeyKeys == null) { - return ops; + return; } - ops.push({ - type: 'del', - domain: this.graphIdentitiesDbDomain, - key: identityKey, - }); + const identityPath = [ + ...this.gestaltGraphIdentitiesDbPath, + identityKey, + ] as unknown as KeyPath; + await tran.del(identityPath); for (const key of Object.keys(identityKeyKeys) as Array) { const gId = gestaltsUtils.ungestaltKey(key); if (gId.type === 'node') { - ops.push( - ...(await this.unlinkNodeAndIdentityOps( - nodesUtils.decodeNodeId(gId.nodeId)!, - providerId, - identityId, - )), + await this.unlinkNodeAndIdentity( + nodesUtils.decodeNodeId(gId.nodeId)!, + providerId, + identityId, + tran, ); } } // Ensure that an empty key set is still deleted - ops.push({ - type: 'del', - domain: this.graphMatrixDbDomain, - key: identityKey, - }); - return ops; + await tran.del(identityKeyPath); } /** @@ -309,53 +263,41 @@ class GestaltGraph { * to a new gestalt permission in the acl */ @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async setNode(nodeInfo: NodeInfo): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const ops = await this.setNodeOps(nodeInfo); - await this.db.batch(ops); - }); - }); - } - - @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async setNodeOps(nodeInfo: NodeInfo): Promise> { + public async setNode( + nodeInfo: NodeInfo, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.setNode(nodeInfo, tran), + ); + } const nodeKey = gestaltsUtils.keyFromNode( nodesUtils.decodeNodeId(nodeInfo.id)!, ); - const ops: Array = []; - let nodeKeyKeys = await this.db.get( - this.graphMatrixDbDomain, + const nodeKeyPath = [ + ...this.gestaltGraphMatrixDbPath, nodeKey, - ); + ] as unknown as KeyPath; + let nodeKeyKeys = await tran.get(nodeKeyPath); if (nodeKeyKeys == null) { nodeKeyKeys = {}; // Sets the gestalt in the acl - ops.push( - ...(await this.acl.setNodePermOps( - nodesUtils.decodeNodeId(nodeInfo.id)!, - { - gestalt: {}, - vaults: {}, - }, - )), + await this.acl.setNodePerm( + nodesUtils.decodeNodeId(nodeInfo.id)!, + { + gestalt: {}, + vaults: {}, + }, + tran, ); } - ops.push( - { - type: 'put', - domain: this.graphMatrixDbDomain, - key: nodeKey, - value: nodeKeyKeys, - }, - { - type: 'put', - domain: this.graphNodesDbDomain, - key: nodeKey, - value: nodeInfo, - }, - ); - return ops; + await tran.put(nodeKeyPath, nodeKeyKeys); + const nodePath = [ + ...this.gestaltGraphNodesDbPath, + nodeKey, + ] as unknown as KeyPath; + await tran.put(nodePath, nodeInfo); } /** @@ -364,81 +306,61 @@ class GestaltGraph { * to the gestalt permission in the acl */ @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async unsetNode(nodeId: NodeId): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const ops = await this.unsetNodeOps(nodeId); - await this.db.batch(ops); - }); - }); - } - - @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async unsetNodeOps(nodeId: NodeId): Promise> { + public async unsetNode(nodeId: NodeId, tran?: DBTransaction): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.unsetNode(nodeId, tran), + ); + } const nodeKey = gestaltsUtils.keyFromNode(nodeId); - const nodeKeyKeys = await this.db.get( - this.graphMatrixDbDomain, + const nodeKeyPath = [ + ...this.gestaltGraphMatrixDbPath, nodeKey, - ); - const ops: Array = []; + ] as unknown as KeyPath; + const nodeKeyKeys = await tran.get(nodeKeyPath); if (nodeKeyKeys == null) { - return ops; + return; } - ops.push({ - type: 'del', - domain: this.graphNodesDbDomain, - key: nodeKey, - }); + const nodePath = [ + ...this.gestaltGraphNodesDbPath, + nodeKey, + ] as unknown as KeyPath; + await tran.del(nodePath); for (const key of Object.keys(nodeKeyKeys) as Array) { const gId = gestaltsUtils.ungestaltKey(key); if (gId.type === 'node') { - ops.push( - ...(await this.unlinkNodeAndNodeOps( - nodeId, - nodesUtils.decodeNodeId(gId.nodeId)!, - )), + await this.unlinkNodeAndNode( + nodeId, + nodesUtils.decodeNodeId(gId.nodeId)!, + tran, ); } else if (gId.type === 'identity') { - ops.push( - ...(await this.unlinkNodeAndIdentityOps( - nodeId, - gId.providerId, - gId.identityId, - )), + await this.unlinkNodeAndIdentity( + nodeId, + gId.providerId, + gId.identityId, + tran, ); } } // Ensure that an empty key set is still deleted - ops.push({ - type: 'del', - domain: this.graphMatrixDbDomain, - key: nodeKey, - }); + await tran.del(nodeKeyPath); // Unsets the gestalt in the acl // this must be done after all unlinking operations - ops.push(...(await this.acl.unsetNodePermOps(nodeId))); - return ops; + await this.acl.unsetNodePerm(nodeId, tran); } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) public async linkNodeAndIdentity( nodeInfo: NodeInfo, identityInfo: IdentityInfo, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const ops = await this.linkNodeAndIdentityOps(nodeInfo, identityInfo); - await this.db.batch(ops); - }); - }); - } - - @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async linkNodeAndIdentityOps( - nodeInfo: NodeInfo, - identityInfo: IdentityInfo, - ): Promise> { - const ops: Array = []; + if (tran == null) { + return this.withTransactionF(async (tran) => + this.linkNodeAndIdentity(nodeInfo, identityInfo, tran), + ); + } const nodeKey = gestaltsUtils.keyFromNode( nodesUtils.decodeNodeId(nodeInfo.id)!, ); @@ -446,14 +368,16 @@ class GestaltGraph { identityInfo.providerId, identityInfo.identityId, ); - let nodeKeyKeys = await this.db.get( - this.graphMatrixDbDomain, + const nodeKeyPath = [ + ...this.gestaltGraphMatrixDbPath, nodeKey, - ); - let identityKeyKeys = await this.db.get( - this.graphMatrixDbDomain, + ] as unknown as KeyPath; + const identityKeyPath = [ + ...this.gestaltGraphMatrixDbPath, identityKey, - ); + ] as unknown as KeyPath; + let nodeKeyKeys = await tran.get(nodeKeyPath); + let identityKeyKeys = await tran.get(identityKeyPath); // If they are already connected we do nothing if ( nodeKeyKeys && @@ -461,7 +385,7 @@ class GestaltGraph { identityKeyKeys && nodeKey in identityKeyKeys ) { - return ops; + return; } let nodeNew = false; if (nodeKeyKeys == null) { @@ -490,14 +414,13 @@ class GestaltGraph { // else // join node gestalt's permission to the identity gestalt if (nodeNew && identityNew) { - ops.push( - ...(await this.acl.setNodePermOps( - nodesUtils.decodeNodeId(nodeInfo.id)!, - { - gestalt: {}, - vaults: {}, - }, - )), + await this.acl.setNodePerm( + nodesUtils.decodeNodeId(nodeInfo.id)!, + { + gestalt: {}, + vaults: {}, + }, + tran, ); } else if ( !nodeNew && @@ -507,6 +430,7 @@ class GestaltGraph { const [, identityNodeKeys] = await this.traverseGestalt( Object.keys(identityKeyKeys) as Array, [identityKey], + tran, ); const identityNodeIds = Array.from(identityNodeKeys, (key) => gestaltsUtils.nodeFromKey(key), @@ -514,32 +438,32 @@ class GestaltGraph { // These must exist const nodePerm = (await this.acl.getNodePerm( nodesUtils.decodeNodeId(nodeInfo.id)!, + tran, )) as Permission; const identityPerm = (await this.acl.getNodePerm( identityNodeIds[0], + tran, )) as Permission; // Union the perms together const permNew = aclUtils.permUnion(nodePerm, identityPerm); // Node perm is updated and identity perm is joined to node perm // this has to be done as 1 call to acl in order to combine ref count update // and the perm record update - ops.push( - ...(await this.acl.joinNodePermOps( - nodesUtils.decodeNodeId(nodeInfo.id)!, - identityNodeIds, - permNew, - )), + await this.acl.joinNodePerm( + nodesUtils.decodeNodeId(nodeInfo.id)!, + identityNodeIds, + permNew, + tran, ); } else if (nodeNew && !identityNew) { if (utils.isEmptyObject(identityKeyKeys)) { - ops.push( - ...(await this.acl.setNodePermOps( - nodesUtils.decodeNodeId(nodeInfo.id)!, - { - gestalt: {}, - vaults: {}, - }, - )), + await this.acl.setNodePerm( + nodesUtils.decodeNodeId(nodeInfo.id)!, + { + gestalt: {}, + vaults: {}, + }, + tran, ); } else { let identityNodeKey: GestaltNodeKey; @@ -548,75 +472,55 @@ class GestaltGraph { break; } const identityNodeId = gestaltsUtils.nodeFromKey(identityNodeKey!); - ops.push( - ...(await this.acl.joinNodePermOps(identityNodeId, [ - nodesUtils.decodeNodeId(nodeInfo.id)!, - ])), + await this.acl.joinNodePerm( + identityNodeId, + [nodesUtils.decodeNodeId(nodeInfo.id)!], + undefined, + tran, ); } } nodeKeyKeys[identityKey] = null; identityKeyKeys[nodeKey] = null; - ops.push( - { - type: 'put', - domain: this.graphMatrixDbDomain, - key: nodeKey, - value: nodeKeyKeys, - }, - { - type: 'put', - domain: this.graphMatrixDbDomain, - key: identityKey, - value: identityKeyKeys, - }, - { - type: 'put', - domain: this.graphNodesDbDomain, - key: nodeKey, - value: nodeInfo, - }, - { - type: 'put', - domain: this.graphIdentitiesDbDomain, - key: identityKey, - value: identityInfo, - }, - ); - return ops; + await tran.put(nodeKeyPath, nodeKeyKeys); + await tran.put(identityKeyPath, identityKeyKeys); + const nodePath = [ + ...this.gestaltGraphNodesDbPath, + nodeKey, + ] as unknown as KeyPath; + await tran.put(nodePath, nodeInfo); + const identityPath = [ + ...this.gestaltGraphIdentitiesDbPath, + identityKey, + ] as unknown as KeyPath; + await tran.put(identityPath, identityInfo); } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) public async linkNodeAndNode( nodeInfo1: NodeInfo, nodeInfo2: NodeInfo, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const ops = await this.linkNodeAndNodeOps(nodeInfo1, nodeInfo2); - await this.db.batch(ops); - }); - }); - } - - @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async linkNodeAndNodeOps( - nodeInfo1: NodeInfo, - nodeInfo2: NodeInfo, - ): Promise> { - const ops: Array = []; + if (tran == null) { + return this.withTransactionF(async (tran) => + this.linkNodeAndNode(nodeInfo1, nodeInfo2, tran), + ); + } const nodeIdEncoded1 = nodesUtils.decodeNodeId(nodeInfo1.id)!; const nodeIdEncoded2 = nodesUtils.decodeNodeId(nodeInfo2.id)!; const nodeKey1 = gestaltsUtils.keyFromNode(nodeIdEncoded1); const nodeKey2 = gestaltsUtils.keyFromNode(nodeIdEncoded2); - let nodeKeyKeys1 = await this.db.get( - this.graphMatrixDbDomain, + const nodeKey1Path = [ + ...this.gestaltGraphMatrixDbPath, nodeKey1, - ); - let nodeKeyKeys2 = await this.db.get( - this.graphMatrixDbDomain, + ] as unknown as KeyPath; + const nodeKey2Path = [ + ...this.gestaltGraphMatrixDbPath, nodeKey2, - ); + ] as unknown as KeyPath; + let nodeKeyKeys1 = await tran.get(nodeKey1Path); + let nodeKeyKeys2 = await tran.get(nodeKey2Path); // If they are already connected we do nothing if ( nodeKeyKeys1 && @@ -624,7 +528,7 @@ class GestaltGraph { nodeKeyKeys2 && nodeKey1 in nodeKeyKeys2 ) { - return ops; + return; } let nodeNew1 = false; if (nodeKeyKeys1 == null) { @@ -647,16 +551,19 @@ class GestaltGraph { // if node 1 is new but node 2 exists // join node 1 gestalt's permission to the node 2 gestalt if (nodeNew1 && nodeNew2) { - ops.push( - ...(await this.acl.setNodesPermOps([nodeIdEncoded1, nodeIdEncoded2], { + await this.acl.setNodesPerm( + [nodeIdEncoded1, nodeIdEncoded2], + { gestalt: {}, vaults: {}, - })), + }, + tran, ); } else if (!nodeNew1 && !nodeNew2) { const [, nodeNodeKeys2] = await this.traverseGestalt( Object.keys(nodeKeyKeys2) as Array, [nodeKey2], + tran, ); const nodeNodeIds2 = Array.from(nodeNodeKeys2, (key) => gestaltsUtils.nodeFromKey(key), @@ -664,60 +571,47 @@ class GestaltGraph { // These must exist const nodePerm1 = (await this.acl.getNodePerm( nodeIdEncoded1, + tran, )) as Permission; const nodePerm2 = (await this.acl.getNodePerm( nodeIdEncoded2, + tran, )) as Permission; // Union the perms together const permNew = aclUtils.permUnion(nodePerm1, nodePerm2); // Node perm 1 is updated and node perm 2 is joined to node perm 2 // this has to be done as 1 call to acl in order to combine ref count update // and the perm record update - ops.push( - ...(await this.acl.joinNodePermOps( - nodeIdEncoded1, - nodeNodeIds2, - permNew, - )), - ); + await this.acl.joinNodePerm(nodeIdEncoded1, nodeNodeIds2, permNew, tran); } else if (nodeNew1 && !nodeNew2) { - ops.push( - ...(await this.acl.joinNodePermOps(nodeIdEncoded2, [nodeIdEncoded1])), + await this.acl.joinNodePerm( + nodeIdEncoded2, + [nodeIdEncoded1], + undefined, + tran, ); } else if (!nodeNew1 && nodeNew2) { - ops.push( - ...(await this.acl.joinNodePermOps(nodeIdEncoded1, [nodeIdEncoded2])), + await this.acl.joinNodePerm( + nodeIdEncoded1, + [nodeIdEncoded2], + undefined, + tran, ); } nodeKeyKeys1[nodeKey2] = null; nodeKeyKeys2[nodeKey1] = null; - ops.push( - { - type: 'put', - domain: this.graphMatrixDbDomain, - key: nodeKey1, - value: nodeKeyKeys1, - }, - { - type: 'put', - domain: this.graphMatrixDbDomain, - key: nodeKey2, - value: nodeKeyKeys2, - }, - { - type: 'put', - domain: this.graphNodesDbDomain, - key: nodeKey1, - value: nodeInfo1, - }, - { - type: 'put', - domain: this.graphNodesDbDomain, - key: nodeKey2, - value: nodeInfo2, - }, - ); - return ops; + await tran.put(nodeKey1Path, nodeKeyKeys1); + await tran.put(nodeKey2Path, nodeKeyKeys2); + const node1Path = [ + ...this.gestaltGraphNodesDbPath, + nodeKey1, + ] as unknown as KeyPath; + await tran.put(node1Path, nodeInfo1); + const node2Path = [ + ...this.gestaltGraphNodesDbPath, + nodeKey2, + ] as unknown as KeyPath; + await tran.put(node2Path, nodeInfo2); } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) @@ -725,56 +619,35 @@ class GestaltGraph { nodeId: NodeId, providerId: ProviderId, identityId: IdentityId, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const ops = await this.unlinkNodeAndIdentityOps( - nodeId, - providerId, - identityId, - ); - await this.db.batch(ops); - }); - }); - } - - @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async unlinkNodeAndIdentityOps( - nodeId: NodeId, - providerId: ProviderId, - identityId: IdentityId, - ): Promise> { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.unlinkNodeAndIdentity(nodeId, providerId, identityId, tran), + ); + } const nodeKey = gestaltsUtils.keyFromNode(nodeId); const identityKey = gestaltsUtils.keyFromIdentity(providerId, identityId); - const nodeKeyKeys = await this.db.get( - this.graphMatrixDbDomain, + const nodeKeyPath = [ + ...this.gestaltGraphMatrixDbPath, nodeKey, - ); - const identityKeyKeys = await this.db.get( - this.graphMatrixDbDomain, + ] as unknown as KeyPath; + const identityKeyPath = [ + ...this.gestaltGraphMatrixDbPath, identityKey, - ); + ] as unknown as KeyPath; + const nodeKeyKeys = await tran.get(nodeKeyPath); + const identityKeyKeys = await tran.get(identityKeyPath); let unlinking = false; - const ops: Array = []; if (nodeKeyKeys && identityKey in nodeKeyKeys) { unlinking = true; delete nodeKeyKeys[identityKey]; - ops.push({ - type: 'put', - domain: this.graphMatrixDbDomain, - key: nodeKey, - value: nodeKeyKeys, - }); + await tran.put(nodeKeyPath, nodeKeyKeys); } if (identityKeyKeys && nodeKey in identityKeyKeys) { unlinking = true; delete identityKeyKeys[nodeKey]; - ops.push({ - type: 'put', - domain: this.graphMatrixDbDomain, - key: identityKey, - value: identityKeyKeys, - }); + await tran.put(identityKeyPath, identityKeyKeys); } if (nodeKeyKeys && identityKeyKeys && unlinking) { // Check if the gestalts have split @@ -783,69 +656,53 @@ class GestaltGraph { await this.traverseGestalt( Object.keys(nodeKeyKeys) as Array, [nodeKey], + tran, ); if (!gestaltIdentityKeys.has(identityKey)) { const nodeIds = Array.from(gestaltNodeKeys, (key) => gestaltsUtils.nodeFromKey(key), ); // It is assumed that an existing gestalt has a permission - const perm = (await this.acl.getNodePerm(nodeId)) as Permission; + const perm = (await this.acl.getNodePerm(nodeId, tran)) as Permission; // This remaps all existing nodes to a new permission - ops.push(...(await this.acl.setNodesPermOps(nodeIds, perm))); + await this.acl.setNodesPerm(nodeIds, perm, tran); } } - return ops; } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) public async unlinkNodeAndNode( nodeId1: NodeId, nodeId2: NodeId, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const ops = await this.unlinkNodeAndNodeOps(nodeId1, nodeId2); - await this.db.batch(ops); - }); - }); - } - - @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async unlinkNodeAndNodeOps( - nodeId1: NodeId, - nodeId2: NodeId, - ): Promise> { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.unlinkNodeAndNode(nodeId1, nodeId2, tran), + ); + } const nodeKey1 = gestaltsUtils.keyFromNode(nodeId1); const nodeKey2 = gestaltsUtils.keyFromNode(nodeId2); - const nodeKeyKeys1 = await this.db.get( - this.graphMatrixDbDomain, + const nodeKey1Path = [ + ...this.gestaltGraphMatrixDbPath, nodeKey1, - ); - const nodeKeyKeys2 = await this.db.get( - this.graphMatrixDbDomain, + ] as unknown as KeyPath; + const nodeKey2Path = [ + ...this.gestaltGraphMatrixDbPath, nodeKey2, - ); + ] as unknown as KeyPath; + const nodeKeyKeys1 = await tran.get(nodeKey1Path); + const nodeKeyKeys2 = await tran.get(nodeKey2Path); let unlinking = false; - const ops: Array = []; if (nodeKeyKeys1 && nodeKey2 in nodeKeyKeys1) { unlinking = true; delete nodeKeyKeys1[nodeKey2]; - ops.push({ - type: 'put', - domain: this.graphMatrixDbDomain, - key: nodeKey1, - value: nodeKeyKeys1, - }); + await tran.put(nodeKey1Path, nodeKeyKeys1); } if (nodeKeyKeys2 && nodeKey1 in nodeKeyKeys2) { unlinking = true; delete nodeKeyKeys2[nodeKey1]; - ops.push({ - type: 'put', - domain: this.graphMatrixDbDomain, - key: nodeKey2, - value: nodeKeyKeys2, - }); + await tran.put(nodeKey2Path, nodeKeyKeys2); } if (nodeKeyKeys1 && nodeKeyKeys2 && unlinking) { // Check if the gestalts have split @@ -853,99 +710,106 @@ class GestaltGraph { const [, gestaltNodeKeys] = await this.traverseGestalt( Object.keys(nodeKeyKeys1) as Array, [nodeKey1], + tran, ); if (!gestaltNodeKeys.has(nodeKey2)) { const nodeIds = Array.from(gestaltNodeKeys, (key) => gestaltsUtils.nodeFromKey(key), ); // It is assumed that an existing gestalt has a permission - const perm = (await this.acl.getNodePerm(nodeId1)) as Permission; + const perm = (await this.acl.getNodePerm(nodeId1, tran)) as Permission; // This remaps all existing nodes to a new permission - ops.push(...(await this.acl.setNodesPermOps(nodeIds, perm))); + await this.acl.setNodesPerm(nodeIds, perm, tran); } } - return ops; } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) public async getGestaltActionsByNode( nodeId: NodeId, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const nodeKey = gestaltsUtils.keyFromNode(nodeId); - if ( - (await this.db.get(this.graphNodesDbDomain, nodeKey)) == - null - ) { - return; - } - const perm = await this.acl.getNodePerm(nodeId); - if (perm == null) { - return; - } - return perm.gestalt; - }); - }); + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getGestaltActionsByNode(nodeId, tran), + ); + } + const nodeKey = gestaltsUtils.keyFromNode(nodeId); + const nodeKeyPath = [ + ...this.gestaltGraphNodesDbPath, + nodeKey, + ] as unknown as KeyPath; + if ((await tran.get(nodeKeyPath)) == null) { + return; + } + const perm = await this.acl.getNodePerm(nodeId, tran); + if (perm == null) { + return; + } + return perm.gestalt; } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) public async getGestaltActionsByIdentity( providerId: ProviderId, identityId: IdentityId, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const identityKey = gestaltsUtils.keyFromIdentity( - providerId, - identityId, - ); - if ( - (await this.db.get( - this.graphIdentitiesDbDomain, - identityKey, - )) == null - ) { - return; - } - const gestaltKeySet = (await this.db.get( - this.graphMatrixDbDomain, - identityKey, - )) as GestaltKeySet; - let nodeId: NodeId | undefined; - for (const nodeKey in gestaltKeySet) { - nodeId = gestaltsUtils.nodeFromKey(nodeKey as GestaltNodeKey); - break; - } - if (nodeId == null) { - return; - } - const perm = await this.acl.getNodePerm(nodeId); - if (perm == null) { - return; - } - return perm.gestalt; - }); - }); + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getGestaltActionsByIdentity(providerId, identityId, tran), + ); + } + const identityKey = gestaltsUtils.keyFromIdentity(providerId, identityId); + const identityKeyPath = [ + ...this.gestaltGraphIdentitiesDbPath, + identityKey, + ] as unknown as KeyPath; + if ((await tran.get(identityKeyPath)) == null) { + return; + } + const gestaltKeyPath = [ + ...this.gestaltGraphMatrixDbPath, + identityKey, + ] as unknown as KeyPath; + const gestaltKeySet = (await tran.get( + gestaltKeyPath, + )) as GestaltKeySet; + let nodeId: NodeId | undefined; + for (const nodeKey in gestaltKeySet) { + nodeId = gestaltsUtils.nodeFromKey(nodeKey as GestaltNodeKey); + break; + } + if (nodeId == null) { + return; + } + const perm = await this.acl.getNodePerm(nodeId, tran); + if (perm == null) { + return; + } + return perm.gestalt; } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) public async setGestaltActionByNode( nodeId: NodeId, action: GestaltAction, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const nodeKey = gestaltsUtils.keyFromNode(nodeId); - if ( - (await this.db.get(this.graphNodesDbDomain, nodeKey)) == - null - ) { - throw new gestaltsErrors.ErrorGestaltsGraphNodeIdMissing(); - } - await this.acl.setNodeAction(nodeId, action); - }); - }); + if (tran == null) { + return this.withTransactionF(async (tran) => + this.setGestaltActionByNode(nodeId, action, tran), + ); + } + const nodeKey = gestaltsUtils.keyFromNode(nodeId); + const nodeKeyPath = [ + ...this.gestaltGraphNodesDbPath, + nodeKey, + ] as unknown as KeyPath; + if ((await tran.get(nodeKeyPath)) == null) { + throw new gestaltsErrors.ErrorGestaltsGraphNodeIdMissing(); + } + await this.acl.setNodeAction(nodeId, action, tran); } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) @@ -953,56 +817,58 @@ class GestaltGraph { providerId: ProviderId, identityId: IdentityId, action: GestaltAction, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const identityKey = gestaltsUtils.keyFromIdentity( - providerId, - identityId, - ); - if ( - (await this.db.get( - this.graphIdentitiesDbDomain, - identityKey, - )) == null - ) { - throw new gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing(); - } - const gestaltKeySet = (await this.db.get( - this.graphMatrixDbDomain, - identityKey, - )) as GestaltKeySet; - let nodeId: NodeId | undefined; - for (const nodeKey in gestaltKeySet) { - nodeId = gestaltsUtils.nodeFromKey(nodeKey as GestaltNodeKey); - break; - } - // If there are no linked nodes, this cannot proceed - if (nodeId == null) { - throw new gestaltsErrors.ErrorGestaltsGraphNodeIdMissing(); - } - await this.acl.setNodeAction(nodeId, action); - }); - }); + if (tran == null) { + return this.withTransactionF(async (tran) => + this.setGestaltActionByIdentity(providerId, identityId, action, tran), + ); + } + const identityKey = gestaltsUtils.keyFromIdentity(providerId, identityId); + const identityKeyPath = [ + ...this.gestaltGraphIdentitiesDbPath, + identityKey, + ] as unknown as KeyPath; + if ((await tran.get(identityKeyPath)) == null) { + throw new gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing(); + } + const gestaltKeyPath = [ + ...this.gestaltGraphMatrixDbPath, + identityKey, + ] as unknown as KeyPath; + const gestaltKeySet = (await tran.get(gestaltKeyPath)) as GestaltKeySet; + let nodeId: NodeId | undefined; + for (const nodeKey in gestaltKeySet) { + nodeId = gestaltsUtils.nodeFromKey(nodeKey as GestaltNodeKey); + break; + } + // If there are no linked nodes, this cannot proceed + if (nodeId == null) { + throw new gestaltsErrors.ErrorGestaltsGraphNodeIdMissing(); + } + await this.acl.setNodeAction(nodeId, action, tran); } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) public async unsetGestaltActionByNode( nodeId: NodeId, action: GestaltAction, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const nodeKey = gestaltsUtils.keyFromNode(nodeId); - if ( - (await this.db.get(this.graphNodesDbDomain, nodeKey)) == - null - ) { - throw new gestaltsErrors.ErrorGestaltsGraphNodeIdMissing(); - } - await this.acl.unsetNodeAction(nodeId, action); - }); - }); + if (tran == null) { + return this.withTransactionF(async (tran) => + this.unsetGestaltActionByNode(nodeId, action, tran), + ); + } + const nodeKey = gestaltsUtils.keyFromNode(nodeId); + const nodeKeyPath = [ + ...this.gestaltGraphNodesDbPath, + nodeKey, + ] as unknown as KeyPath; + if ((await tran.get(nodeKeyPath)) == null) { + throw new gestaltsErrors.ErrorGestaltsGraphNodeIdMissing(); + } + await this.acl.unsetNodeAction(nodeId, action, tran); } @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) @@ -1010,92 +876,94 @@ class GestaltGraph { providerId: ProviderId, identityId: IdentityId, action: GestaltAction, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - return await this.acl._transaction(async () => { - const identityKey = gestaltsUtils.keyFromIdentity( - providerId, - identityId, - ); - if ( - (await this.db.get( - this.graphIdentitiesDbDomain, - identityKey, - )) == null - ) { - throw new gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing(); - } - const gestaltKeySet = (await this.db.get( - this.graphMatrixDbDomain, - identityKey, - )) as GestaltKeySet; - let nodeId: NodeId | undefined; - for (const nodeKey in gestaltKeySet) { - nodeId = gestaltsUtils.nodeFromKey(nodeKey as GestaltNodeKey); - break; - } - // If there are no linked nodes, this cannot proceed - if (nodeId == null) { - throw new gestaltsErrors.ErrorGestaltsGraphNodeIdMissing(); - } - await this.acl.unsetNodeAction(nodeId, action); - }); - }); + if (tran == null) { + return this.withTransactionF(async (tran) => + this.unsetGestaltActionByIdentity(providerId, identityId, action, tran), + ); + } + const identityKey = gestaltsUtils.keyFromIdentity(providerId, identityId); + const identityKeyPath = [ + ...this.gestaltGraphIdentitiesDbPath, + identityKey, + ] as unknown as KeyPath; + if ((await tran.get(identityKeyPath)) == null) { + throw new gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing(); + } + const gestaltKeyPath = [ + ...this.gestaltGraphMatrixDbPath, + identityKey, + ] as unknown as KeyPath; + const gestaltKeySet = (await tran.get(gestaltKeyPath)) as GestaltKeySet; + let nodeId: NodeId | undefined; + for (const nodeKey in gestaltKeySet) { + nodeId = gestaltsUtils.nodeFromKey(nodeKey as GestaltNodeKey); + break; + } + // If there are no linked nodes, this cannot proceed + if (nodeId == null) { + throw new gestaltsErrors.ErrorGestaltsGraphNodeIdMissing(); + } + await this.acl.unsetNodeAction(nodeId, action, tran); } protected async getGestaltByKey( gK: GestaltKey, + tran: DBTransaction, ): Promise { - return await this._transaction(async () => { - const gestalt: Gestalt = { - matrix: {}, - nodes: {}, - identities: {}, - }; - // We are not using traverseGestalt - // because this requires keeping track of the vertexKeys - const queue = [gK]; - const visited = new Set(); - while (true) { - const vertex = queue.shift(); - if (vertex == null) { - break; - } - const vertexKeys = await this.db.get( - this.graphMatrixDbDomain, - vertex, - ); - if (vertexKeys == null) { - return; - } - const gId = gestaltsUtils.ungestaltKey(vertex); - gestalt.matrix[vertex] = vertexKeys; - if (gId.type === 'node') { - const nodeInfo = await this.db.get( - this.graphNodesDbDomain, - vertex as GestaltNodeKey, - ); - gestalt.nodes[vertex] = nodeInfo!; - } else if (gId.type === 'identity') { - const identityInfo = await this.db.get( - this.graphIdentitiesDbDomain, - vertex as GestaltIdentityKey, - ); - gestalt.identities[vertex] = identityInfo!; - } - visited.add(vertex); - const neighbours: Array = Object.keys(vertexKeys).filter( - (k: GestaltKey) => !visited.has(k), - ) as Array; - queue.push(...neighbours); + const gestalt: Gestalt = { + matrix: {}, + nodes: {}, + identities: {}, + }; + // We are not using traverseGestalt + // because this requires keeping track of the vertexKeys + const queue = [gK]; + const visited = new Set(); + while (true) { + const vertex = queue.shift(); + if (vertex == null) { + break; } - return gestalt; - }); + const vertexPath = [ + ...this.gestaltGraphMatrixDbPath, + vertex, + ] as unknown as KeyPath; + const vertexKeys = await tran.get(vertexPath); + if (vertexKeys == null) { + return; + } + const gId = gestaltsUtils.ungestaltKey(vertex); + gestalt.matrix[vertex] = vertexKeys; + if (gId.type === 'node') { + const nodePath = [ + ...this.gestaltGraphNodesDbPath, + vertex as GestaltNodeKey, + ] as unknown as KeyPath; + const nodeInfo = await tran.get(nodePath); + gestalt.nodes[vertex] = nodeInfo!; + } else if (gId.type === 'identity') { + const identityPath = [ + ...this.gestaltGraphIdentitiesDbPath, + vertex as GestaltIdentityKey, + ] as unknown as KeyPath; + const identityInfo = await tran.get(identityPath); + gestalt.identities[vertex] = identityInfo!; + } + visited.add(vertex); + const neighbours: Array = Object.keys(vertexKeys).filter( + (k: GestaltKey) => !visited.has(k), + ) as Array; + queue.push(...neighbours); + } + return gestalt; } protected async traverseGestalt( queueStart: Array, visitedStart: Array = [], + tran: DBTransaction, ): Promise<[Set, Set, Set]> { const queue = [...queueStart]; const visited = new Set(visitedStart); @@ -1114,10 +982,11 @@ class GestaltGraph { if (vertex == null) { break; } - const vertexKeys = await this.db.get( - this.graphMatrixDbDomain, + const vertexPath = [ + ...this.gestaltGraphMatrixDbPath, vertex, - ); + ] as unknown as KeyPath; + const vertexKeys = await tran.get(vertexPath); if (vertexKeys == null) { break; } @@ -1135,11 +1004,6 @@ class GestaltGraph { } return [visited, visitedNodes, visitedIdentities]; } - - @ready(new gestaltsErrors.ErrorGestaltsGraphNotRunning()) - public async clearDB() { - await this.graphDb.clear(); - } } export default GestaltGraph; diff --git a/src/identities/IdentitiesManager.ts b/src/identities/IdentitiesManager.ts index c007c8883..83c92334e 100644 --- a/src/identities/IdentitiesManager.ts +++ b/src/identities/IdentitiesManager.ts @@ -4,15 +4,14 @@ import type { ProviderTokens, TokenData, } from './types'; -import type { DB, DBLevel } from '@matrixai/db'; +import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; import type Provider from './Provider'; - -import { Mutex } from 'async-mutex'; import Logger from '@matrixai/logger'; import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; +import { withF } from '@matrixai/resources'; import * as identitiesErrors from './errors'; interface IdentitiesManager extends CreateDestroyStartStop {} @@ -21,18 +20,6 @@ interface IdentitiesManager extends CreateDestroyStartStop {} new identitiesErrors.ErrorIdentitiesManagerDestroyed(), ) class IdentitiesManager { - protected logger: Logger; - protected db: DB; - protected identitiesDbDomain: string = this.constructor.name; - protected identitiesTokensDbDomain: Array = [ - this.identitiesDbDomain, - 'tokens', - ]; - protected identitiesDb: DBLevel; - protected identitiesTokensDb: DBLevel; - protected lock: Mutex = new Mutex(); - protected providers: Map = new Map(); - static async createIdentitiesManager({ db, logger = new Logger(this.name), @@ -49,29 +36,29 @@ class IdentitiesManager { return identitiesManager; } + protected logger: Logger; + protected db: DB; + protected identitiesDbPath: LevelPath = [this.constructor.name]; + /** + * Tokens stores ProviderId -> ProviderTokens + */ + protected identitiesTokensDbPath: LevelPath = [ + this.constructor.name, + 'tokens', + ]; + protected providers: Map = new Map(); + constructor({ db, logger }: { db: DB; logger: Logger }) { this.logger = logger; this.db = db; } - get locked(): boolean { - return this.lock.isLocked(); - } - public async start({ fresh = false }: { fresh?: boolean } = {}) { this.logger.info(`Starting ${this.constructor.name}`); - const identitiesDb = await this.db.level(this.identitiesDbDomain); - // Tokens stores ProviderId -> ProviderTokens - const identitiesTokensDb = await this.db.level( - this.identitiesTokensDbDomain[1], - identitiesDb, - ); if (fresh) { - await identitiesDb.clear(); + await this.db.clear(this.identitiesDbPath); this.providers = new Map(); } - this.identitiesDb = identitiesDb; - this.identitiesTokensDb = identitiesTokensDb; this.logger.info(`Started ${this.constructor.name}`); } @@ -82,38 +69,16 @@ class IdentitiesManager { async destroy() { this.logger.info(`Destroying ${this.constructor.name}`); - const identitiesDb = await this.db.level(this.identitiesDbDomain); - await identitiesDb.clear(); + await this.db.clear(this.identitiesDbPath); this.providers = new Map(); this.logger.info(`Destroyed ${this.constructor.name}`); } - /** - * Run several operations within the same lock - * This does not ensure atomicity of the underlying database - * Database atomicity still depends on the underlying operation - */ - public async transaction( - f: (identitiesManager: IdentitiesManager) => Promise, + @ready(new identitiesErrors.ErrorIdentitiesManagerNotRunning()) + public async withTransactionF( + f: (tran: DBTransaction) => Promise, ): Promise { - const release = await this.lock.acquire(); - try { - return await f(this); - } finally { - release(); - } - } - - /** - * Transaction wrapper that will not lock if the operation was executed - * within a transaction context - */ - public async _transaction(f: () => Promise): Promise { - if (this.lock.isLocked()) { - return await f(); - } else { - return await this.transaction(f); - } + return withF([this.db.transaction()], ([tran]) => f(tran)); } @ready(new identitiesErrors.ErrorIdentitiesManagerNotRunning()) @@ -146,34 +111,46 @@ class IdentitiesManager { } @ready(new identitiesErrors.ErrorIdentitiesManagerNotRunning()) - public async getTokens(providerId: ProviderId): Promise { - return await this._transaction(async () => { - const providerTokens = await this.db.get( - this.identitiesTokensDbDomain, - providerId, + public async getTokens( + providerId: ProviderId, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getTokens(providerId, tran), ); - if (providerTokens == null) { - return {}; - } - return providerTokens; - }); + } + const providerIdPath = [ + ...this.identitiesTokensDbPath, + providerId, + ] as unknown as KeyPath; + const providerTokens = await tran.get(providerIdPath); + if (providerTokens == null) { + return {}; + } + return providerTokens; } @ready(new identitiesErrors.ErrorIdentitiesManagerNotRunning()) public async getToken( providerId: ProviderId, identityId: IdentityId, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - const providerTokens = await this.db.get( - this.identitiesTokensDbDomain, - providerId, + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getToken(providerId, identityId, tran), ); - if (providerTokens == null) { - return undefined; - } - return providerTokens[identityId]; - }); + } + const providerIdPath = [ + ...this.identitiesTokensDbPath, + providerId, + ] as unknown as KeyPath; + const providerTokens = await tran.get(providerIdPath); + if (providerTokens == null) { + return undefined; + } + return providerTokens[identityId]; } @ready(new identitiesErrors.ErrorIdentitiesManagerNotRunning()) @@ -181,39 +158,47 @@ class IdentitiesManager { providerId: ProviderId, identityId: IdentityId, tokenData: TokenData, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - const providerTokens = await this.getTokens(providerId); - providerTokens[identityId] = tokenData; - await this.db.put( - this.identitiesTokensDbDomain, - providerId, - providerTokens, + if (tran == null) { + return this.withTransactionF(async (tran) => + this.putToken(providerId, identityId, tokenData, tran), ); - }); + } + const providerTokens = await this.getTokens(providerId); + providerTokens[identityId] = tokenData; + const providerIdPath = [ + ...this.identitiesTokensDbPath, + providerId, + ] as unknown as KeyPath; + await tran.put(providerIdPath, providerTokens); } @ready(new identitiesErrors.ErrorIdentitiesManagerNotRunning()) public async delToken( providerId: ProviderId, identityId: IdentityId, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - const providerTokens = await this.getTokens(providerId); - if (!(identityId in providerTokens)) { - return; - } - delete providerTokens[identityId]; - if (!Object.keys(providerTokens).length) { - await this.db.del(this.identitiesTokensDbDomain, providerId); - return; - } - await this.db.put( - this.identitiesTokensDbDomain, - providerId, - providerTokens, + if (tran == null) { + return this.withTransactionF(async (tran) => + this.delToken(providerId, identityId, tran), ); - }); + } + const providerTokens = await this.getTokens(providerId, tran); + if (!(identityId in providerTokens)) { + return; + } + delete providerTokens[identityId]; + const providerIdPath = [ + ...this.identitiesTokensDbPath, + providerId, + ] as unknown as KeyPath; + if (!Object.keys(providerTokens).length) { + await tran.del(providerIdPath); + return; + } + await tran.put(providerIdPath, providerTokens); } } diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index b7c68dfa9..84e9ddfa9 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -132,7 +132,7 @@ class NodeConnectionManager { return async () => { const connAndLock = await this.getConnection(targetNodeId); // Acquire the read lock and the release function - const release = await connAndLock.lock.acquireRead(); + const release = connAndLock.lock.read(); // Resetting TTL timer connAndLock.timer?.refresh(); // Return tuple of [ResourceRelease, Resource] @@ -241,7 +241,7 @@ class NodeConnectionManager { // Connection already exists, so return if (connection != null) return connAndLock; // Acquire the write (creation) lock - return await lock.withWrite(async () => { + return await lock.withWriteF(async () => { // Once lock is released, check again if the conn now exists connAndLock = this.connections.get( targetNodeId.toString() as NodeIdString, @@ -267,7 +267,7 @@ class NodeConnectionManager { targetNodeId.toString() as NodeIdString, connAndLock, ); - return await lock.withWrite(async () => { + return await lock.withWriteF(async () => { this.logger.info( `no existing entry, creating connection to ${nodesUtils.encodeNodeId( targetNodeId, @@ -360,7 +360,7 @@ class NodeConnectionManager { const lock = connAndLock.lock; // If the connection exists then we lock, destroy and remove it from the map - await lock.withWrite(async () => { + await lock.withWriteF(async () => { // Destroying connection await connection.destroy(); // Destroying TTL timer diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index 4237b5529..f1f12e149 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -1,8 +1,7 @@ -import type { DB, DBLevel, DBOp } from '@matrixai/db'; +import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; import type { NodeId, NodeAddress, NodeBucket } from './types'; import type KeyManager from '../keys/KeyManager'; import type { Host, Hostname, Port } from '../network/types'; -import { Mutex } from 'async-mutex'; import lexi from 'lexicographic-integer'; import Logger from '@matrixai/logger'; import { @@ -10,6 +9,8 @@ import { ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { IdInternal } from '@matrixai/id'; +import { utils as dbUtils } from '@matrixai/db'; +import { withF } from '@matrixai/resources'; import * as nodesUtils from './utils'; import * as nodesErrors from './errors'; @@ -23,21 +24,6 @@ interface NodeGraph extends CreateDestroyStartStop {} new nodesErrors.ErrorNodeGraphDestroyed(), ) class NodeGraph { - // Max number of nodes in each k-bucket (a.k.a. k) - public readonly maxNodesPerBucket: number = 20; - - protected logger: Logger; - protected db: DB; - protected keyManager: KeyManager; - protected nodeGraphDbDomain: string = this.constructor.name; - protected nodeGraphBucketsDbDomain: Array = [ - this.nodeGraphDbDomain, - 'buckets', - ]; - protected nodeGraphDb: DBLevel; - protected nodeGraphBucketsDb: DBLevel; - protected lock: Mutex = new Mutex(); - public static async createNodeGraph({ db, keyManager, @@ -60,6 +46,23 @@ class NodeGraph { return nodeGraph; } + /** + * Max number of nodes in each k-bucket (a.k.a. k) + */ + public readonly maxNodesPerBucket: number = 20; + + protected logger: Logger; + protected db: DB; + protected keyManager: KeyManager; + protected nodeGraphDbPath: LevelPath = [this.constructor.name]; + /** + * Buckets stores NodeBucketIndex -> NodeBucket + */ + protected nodeGraphBucketsDbPath: LevelPath = [ + this.constructor.name, + 'buckets', + ]; + constructor({ db, keyManager, @@ -74,27 +77,15 @@ class NodeGraph { this.keyManager = keyManager; } - get locked(): boolean { - return this.lock.isLocked(); - } - public async start({ fresh = false, }: { fresh?: boolean; } = {}) { this.logger.info(`Starting ${this.constructor.name}`); - const nodeGraphDb = await this.db.level(this.nodeGraphDbDomain); - // Buckets stores NodeBucketIndex -> NodeBucket - const nodeGraphBucketsDb = await this.db.level( - this.nodeGraphBucketsDbDomain[1], - nodeGraphDb, - ); if (fresh) { - await nodeGraphDb.clear(); + await this.db.clear(this.nodeGraphDbPath); } - this.nodeGraphDb = nodeGraphDb; - this.nodeGraphBucketsDb = nodeGraphBucketsDb; this.logger.info(`Started ${this.constructor.name}`); } @@ -105,37 +96,18 @@ class NodeGraph { public async destroy() { this.logger.info(`Destroying ${this.constructor.name}`); - const nodeGraphDb = await this.db.level(this.nodeGraphDbDomain); - await nodeGraphDb.clear(); + await this.db.clear(this.nodeGraphDbPath); this.logger.info(`Destroyed ${this.constructor.name}`); } - /** - * Run several operations within the same lock - * This does not ensure atomicity of the underlying database - * Database atomicity still depends on the underlying operation - */ - public async transaction( - f: (nodeGraph: NodeGraph) => Promise, + @ready(new nodesErrors.ErrorNodeGraphNotRunning()) + public async withTransactionF( + f: (tran: DBTransaction) => Promise, ): Promise { - const release = await this.lock.acquire(); - try { - return await f(this); - } finally { - release(); - } - } - - /** - * Transaction wrapper that will not lock if the operation was executed - * within a transaction context - */ - public async _transaction(f: () => Promise): Promise { - if (this.lock.isLocked()) { - return await f(); - } else { - return await this.transaction(f); - } + return withF( + [this.db.transaction()], + ([tran]) => f(tran), + ); } /** @@ -144,18 +116,24 @@ class NodeGraph { * @returns Node Address of the target node */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async getNode(nodeId: NodeId): Promise { - return await this._transaction(async () => { - const bucketIndex = this.getBucketIndex(nodeId); - const bucket = await this.db.get( - this.nodeGraphBucketsDbDomain, - bucketIndex, + public async getNode(nodeId: NodeId, tran?: DBTransaction): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getNode(nodeId, tran), ); - if (bucket != null && nodeId in bucket) { - return bucket[nodeId].address; - } - return; - }); + } + const bucketIndex = this.getBucketIndex(nodeId); + const bucketPath = [ + ...this.nodeGraphBucketsDbPath, + bucketIndex, + ] as unknown as KeyPath; + const bucket = await tran.get( + bucketPath, + ); + if (bucket != null && nodeId in bucket) { + return bucket[nodeId].address; + } + return; } /** @@ -174,47 +152,51 @@ class NodeGraph { * @param bucketIndex */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async getBucket(bucketIndex: number): Promise { - return await this._transaction(async () => { - const bucket = await this.db.get( - this.nodeGraphBucketsDbDomain, - lexi.pack(bucketIndex, 'hex'), + public async getBucket(bucketIndex: number, tran?: DBTransaction): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getBucket(bucketIndex, tran), ); - // Cast the non-primitive types correctly (ensures type safety when using them) - for (const nodeId in bucket) { - bucket[nodeId].address.host = bucket[nodeId].address.host as - | Host - | Hostname; - bucket[nodeId].address.port = bucket[nodeId].address.port as Port; - bucket[nodeId].lastUpdated = new Date(bucket[nodeId].lastUpdated); - } - return bucket; - }); + } + const bucketPath = [ + ...this.nodeGraphBucketsDbPath, + lexi.pack(bucketIndex, 'hex'), + ] as unknown as KeyPath; + const bucket = await tran.get( + bucketPath, + ); + // Cast the non-primitive types correctly (ensures type safety when using them) + for (const nodeId in bucket) { + bucket[nodeId].address.host = bucket[nodeId].address.host as + | Host + | Hostname; + bucket[nodeId].address.port = bucket[nodeId].address.port as Port; + bucket[nodeId].lastUpdated = new Date(bucket[nodeId].lastUpdated); + } + return bucket; } /** * Sets a node to the bucket database * This may delete an existing node if the bucket is filled up */ - @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async setNode( nodeId: NodeId, nodeAddress: NodeAddress, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - const ops = await this.setNodeOps(nodeId, nodeAddress); - await this.db.batch(ops); - }); - } - - protected async setNodeOps( - nodeId: NodeId, - nodeAddress: NodeAddress, - ): Promise> { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.setNode(nodeId, nodeAddress, tran), + ); + } const bucketIndex = this.getBucketIndex(nodeId); - let bucket = await this.db.get( - this.nodeGraphBucketsDbDomain, + const bucketPath = [ + ...this.nodeGraphBucketsDbPath, bucketIndex, + ] as unknown as KeyPath; + let bucket = await tran.get( + bucketPath, ); if (bucket == null) { bucket = {}; @@ -239,14 +221,7 @@ class NodeGraph { throw new nodesErrors.ErrorNodeGraphOversizedBucket(); } } - return [ - { - type: 'put', - domain: this.nodeGraphBucketsDbDomain, - key: bucketIndex, - value: bucket, - }, - ]; + await tran.put(bucketPath, bucket); } /** @@ -258,38 +233,30 @@ class NodeGraph { public async updateNode( nodeId: NodeId, nodeAddress?: NodeAddress, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - const ops = await this.updateNodeOps(nodeId, nodeAddress); - await this.db.batch(ops); - }); - } - - protected async updateNodeOps( - nodeId: NodeId, - nodeAddress?: NodeAddress, - ): Promise> { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.updateNode(nodeId, nodeAddress, tran), + ); + } const bucketIndex = this.getBucketIndex(nodeId); - const bucket = await this.db.get( - this.nodeGraphBucketsDbDomain, + const bucketPath = [ + ...this.nodeGraphBucketsDbPath, bucketIndex, + ] as unknown as KeyPath; + const bucket = await tran.get( + bucketPath, ); - const ops: Array = []; if (bucket != null && nodeId in bucket) { bucket[nodeId].lastUpdated = new Date(); if (nodeAddress != null) { bucket[nodeId].address = nodeAddress; } - ops.push({ - type: 'put', - domain: this.nodeGraphBucketsDbDomain, - key: bucketIndex, - value: bucket, - }); + await tran.put(bucketPath, bucket); } else { throw new nodesErrors.ErrorNodeGraphNodeIdNotFound(); } - return ops; } /** @@ -297,39 +264,29 @@ class NodeGraph { * @param nodeId */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async unsetNode(nodeId: NodeId): Promise { - return await this._transaction(async () => { - const ops = await this.unsetNodeOps(nodeId); - await this.db.batch(ops); - }); - } - - protected async unsetNodeOps(nodeId: NodeId): Promise> { + public async unsetNode(nodeId: NodeId, tran?: DBTransaction): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.unsetNode(nodeId, tran), + ); + } const bucketIndex = this.getBucketIndex(nodeId); - const bucket = await this.db.get( - this.nodeGraphBucketsDbDomain, + const bucketPath = [ + ...this.nodeGraphBucketsDbPath, bucketIndex, + ] as unknown as KeyPath; + const bucket = await tran.get( + bucketPath ); - const ops: Array = []; if (bucket == null) { - return ops; + return; } delete bucket[nodeId]; if (Object.keys(bucket).length === 0) { - ops.push({ - type: 'del', - domain: this.nodeGraphBucketsDbDomain, - key: bucketIndex, - }); + await tran.del(bucketPath); } else { - ops.push({ - type: 'put', - domain: this.nodeGraphBucketsDbDomain, - key: bucketIndex, - value: bucket, - }); + await tran.put(bucketPath, bucket); } - return ops; } /** @@ -349,19 +306,20 @@ class NodeGraph { * Returns all of the buckets in an array */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async getAllBuckets(): Promise> { - return await this._transaction(async () => { - const buckets: Array = []; - for await (const o of this.nodeGraphBucketsDb.createReadStream()) { - const data = (o as any).value as Buffer; - const bucket = await this.db.deserializeDecrypt( - data, - false, - ); - buckets.push(bucket); - } - return buckets; - }); + public async getAllBuckets(tran?: DBTransaction): Promise> { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getAllBuckets(tran), + ); + } + const buckets: Array = []; + for await (const [v] of tran.iterator({ key: false }, [ + ...this.nodeGraphBucketsDbPath, + ])) { + const bucket = dbUtils.deserialize(v); + buckets.push(bucket); + } + return buckets; } /** @@ -372,63 +330,65 @@ class NodeGraph { * will be removed. */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async refreshBuckets(): Promise { - return await this._transaction(async () => { - const ops: Array = []; - // Get a local copy of all the buckets - const buckets = await this.getAllBuckets(); - // Wrap as a batch operation. We want to rollback if we encounter any - // errors (such that we don't clear the DB without re-adding the nodes) - // 1. Delete every bucket - for await (const k of this.nodeGraphBucketsDb.createKeyStream()) { - const hexBucketIndex = k as string; - ops.push({ - type: 'del', - domain: this.nodeGraphBucketsDbDomain, - key: hexBucketIndex, - }); - } - const tempBuckets: Record = {}; - // 2. Re-add all the nodes from all buckets - for (const b of buckets) { - for (const n of Object.keys(b)) { - const nodeId = IdInternal.fromString(n); - const newIndex = this.getBucketIndex(nodeId); - let expectedBucket = tempBuckets[newIndex]; - // The following is more or less copied from setNodeOps - if (expectedBucket == null) { - expectedBucket = {}; - } - const bucketEntries = Object.entries(expectedBucket); - // Add the old node - expectedBucket[nodeId] = { - address: b[nodeId].address, - lastUpdated: b[nodeId].lastUpdated, - }; - // If, with the old node added, we exceed the limit - if (bucketEntries.length > this.maxNodesPerBucket) { - // Then, with the old node added, find the least active and remove - const leastActive = bucketEntries.reduce((prev, curr) => { - return prev[1].lastUpdated < curr[1].lastUpdated ? prev : curr; - }); - delete expectedBucket[leastActive[0]]; - } - // Add this reconstructed bucket (with old node) into the temp storage - tempBuckets[newIndex] = expectedBucket; + public async refreshBuckets(tran?: DBTransaction): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.refreshBuckets(tran), + ); + } + // Get a local copy of all the buckets + const buckets = await this.getAllBuckets(); + // Wrap as a batch operation. We want to rollback if we encounter any + // errors (such that we don't clear the DB without re-adding the nodes) + // 1. Delete every bucket + for await (const [k] of tran.iterator({ value: false }, [ + ...this.nodeGraphBucketsDbPath, + ])) { + const hexBucketIndex = dbUtils.deserialize(k); + const hexBucketPath = [ + ...this.nodeGraphBucketsDbPath, + hexBucketIndex, + ] as unknown as KeyPath; + await tran.del(hexBucketPath); + } + const tempBuckets: Record = {}; + // 2. Re-add all the nodes from all buckets + for (const b of buckets) { + for (const n of Object.keys(b)) { + const nodeId = IdInternal.fromString(n); + const newIndex = this.getBucketIndex(nodeId); + let expectedBucket = tempBuckets[newIndex]; + // The following is more or less copied from setNodeOps + if (expectedBucket == null) { + expectedBucket = {}; } + const bucketEntries = Object.entries(expectedBucket); + // Add the old node + expectedBucket[nodeId] = { + address: b[nodeId].address, + lastUpdated: b[nodeId].lastUpdated, + }; + // If, with the old node added, we exceed the limit + if (bucketEntries.length > this.maxNodesPerBucket) { + // Then, with the old node added, find the least active and remove + const leastActive = bucketEntries.reduce((prev, curr) => { + return prev[1].lastUpdated < curr[1].lastUpdated ? prev : curr; + }); + delete expectedBucket[leastActive[0]]; + } + // Add this reconstructed bucket (with old node) into the temp storage + tempBuckets[newIndex] = expectedBucket; } - // Now that we've reconstructed all the buckets, perform batch operations - // on a bucket level (i.e. per bucket, instead of per node) - for (const bucketIndex in tempBuckets) { - ops.push({ - type: 'put', - domain: this.nodeGraphBucketsDbDomain, - key: bucketIndex, - value: tempBuckets[bucketIndex], - }); - } - await this.db.batch(ops); - }); + } + // Now that we've reconstructed all the buckets, perform batch operations + // on a bucket level (i.e. per bucket, instead of per node) + for (const bucketIndex in tempBuckets) { + const bucketPath = [ + ...this.nodeGraphBucketsDbPath, + bucketIndex, + ] as unknown as KeyPath; + await tran.put(bucketPath, tempBuckets[bucketIndex]); + } } } diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index b28343667..8035f0bfa 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -10,7 +10,7 @@ import type { ClaimEncoded } from '../claims/types'; import Logger from '@matrixai/logger'; import * as nodesErrors from './errors'; import * as nodesUtils from './utils'; -import { utils as validationUtils } from '../validation'; +import * as validationUtils from '../validation/utils'; import * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb'; import * as claimsErrors from '../claims/errors'; import * as networkErrors from '../network/errors'; diff --git a/src/notifications/NotificationsManager.ts b/src/notifications/NotificationsManager.ts index 44974ae67..b648a2b81 100644 --- a/src/notifications/NotificationsManager.ts +++ b/src/notifications/NotificationsManager.ts @@ -1,27 +1,28 @@ +import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; import type { NotificationId, Notification, NotificationData, NotificationIdGenerator, } from './types'; -import type { ACL } from '../acl'; -import type { DB, DBLevel } from '@matrixai/db'; -import type { KeyManager } from '../keys'; -import type { NodeManager, NodeConnectionManager } from '../nodes'; +import type ACL from '../acl/ACL'; +import type KeyManager from '../keys/KeyManager'; +import type NodeManager from '../nodes/NodeManager'; +import type NodeConnectionManager from '../nodes/NodeConnectionManager'; import type { NodeId } from '../nodes/types'; import Logger from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; -import { Mutex } from 'async-mutex'; import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { utils as idUtils } from '@matrixai/id'; +import { utils as dbUtils } from '@matrixai/db'; +import { withF } from '@matrixai/resources'; import * as notificationsUtils from './utils'; import * as notificationsErrors from './errors'; -import { createNotificationIdGenerator } from './utils'; import * as notificationsPB from '../proto/js/polykey/v1/notifications/notifications_pb'; -import { utils as nodesUtils } from '../nodes'; +import * as nodesUtils from '../nodes/utils'; const MESSAGE_COUNT_KEY = 'numMessages'; @@ -34,27 +35,6 @@ interface NotificationsManager extends CreateDestroyStartStop {} new notificationsErrors.ErrorNotificationsDestroyed(), ) class NotificationsManager { - protected logger: Logger; - protected acl: ACL; - protected db: DB; - protected keyManager: KeyManager; - protected nodeManager: NodeManager; - protected nodeConnectionManager: NodeConnectionManager; - - protected messageCap: number; - - protected notificationsDomain: string = this.constructor.name; - protected notificationsDbDomain: Array = [this.notificationsDomain]; - protected notificationsMessagesDbDomain: Array = [ - this.notificationsDomain, - 'messages', - ]; - protected notificationsDb: DBLevel; - protected notificationsMessagesDb: DBLevel; - protected lock: Mutex = new Mutex(); - - protected notificationIdGenerator: NotificationIdGenerator; - static async createNotificationsManager({ acl, db, @@ -90,6 +70,29 @@ class NotificationsManager { return notificationsManager; } + protected logger: Logger; + protected acl: ACL; + protected db: DB; + protected keyManager: KeyManager; + protected nodeManager: NodeManager; + protected nodeConnectionManager: NodeConnectionManager; + + protected messageCap: number; + + /** + * Top level stores MESSAGE_COUNT_KEY -> number (of messages) + */ + protected notificationsDbPath: LevelPath = [this.constructor.name]; + /** + * Messages stores NotificationId -> string (message) + */ + protected notificationsMessagesDbPath: LevelPath = [ + this.constructor.name, + 'messages', + ]; + + protected notificationIdGenerator: NotificationIdGenerator; + constructor({ acl, db, @@ -116,33 +119,26 @@ class NotificationsManager { this.nodeManager = nodeManager; } - get locked(): boolean { - return this.lock.isLocked(); - } - public async start({ fresh = false, }: { fresh?: boolean } = {}): Promise { this.logger.info(`Starting ${this.constructor.name}`); - // Sub-level stores MESSAGE_COUNT_KEY -> number (of messages) - const notificationsDb = await this.db.level(this.notificationsDomain); - // Sub-sub-level stores NotificationId -> string (message) - const notificationsMessagesDb = await this.db.level( - this.notificationsMessagesDbDomain[1], - notificationsDb, - ); if (fresh) { - await notificationsDb.clear(); + await this.db.clear(this.notificationsDbPath); } - this.notificationsDb = notificationsDb; - this.notificationsMessagesDb = notificationsMessagesDb; - // Getting latest ID and creating ID generator let latestId: NotificationId | undefined; - const keyStream = this.notificationsMessagesDb.createKeyStream({ - limit: 1, - reverse: true, - }); + // for await (const [k] of tran.iterator({ value: false }, [ + // ...this.nodeGraphBucketsDbPath, + // ])) { + // const keyStream = this.notificationsMessagesDb.createKeyStream({ + // limit: 1, + // reverse: true, + // }); + await withF( + [this.db.transaction()], + ([tran]) => async (tran) => tran.iterator({ limit: 1, reverse: true, value: false }, [...this.notificationsMessagesDbPath]) + } for await (const o of keyStream) { latestId = IdInternal.fromBuffer(o as Buffer); } diff --git a/src/sigchain/Sigchain.ts b/src/sigchain/Sigchain.ts index 5d5744bf4..19baf94cf 100644 --- a/src/sigchain/Sigchain.ts +++ b/src/sigchain/Sigchain.ts @@ -8,7 +8,7 @@ import type { ClaimIntermediary, ClaimType, } from '../claims/types'; -import type { KeyManager } from '../keys'; +import type KeyManager from '../keys/KeyManager'; import type { NodeIdEncoded } from '../nodes/types'; import Logger from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; diff --git a/tests/acl/ACL.test.ts b/tests/acl/ACL.test.ts index a75819f2f..a671caf10 100644 --- a/tests/acl/ACL.test.ts +++ b/tests/acl/ACL.test.ts @@ -7,9 +7,10 @@ import path from 'path'; import fs from 'fs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; -import { ACL, errors as aclErrors } from '@/acl'; -import { utils as keysUtils } from '@/keys'; -import { utils as vaultsUtils } from '@/vaults'; +import ACL from '@/acl/ACL'; +import * as aclErrors from '@/acl/errors'; +import * as keysUtils from '@/keys/utils'; +import * as vaultsUtils from '@/vaults/utils'; import * as testUtils from '../utils'; describe(ACL.name, () => { @@ -107,30 +108,18 @@ describe(ACL.name, () => { await expect(acl.setNodesPerm([], {} as Permission)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); - await expect(acl.setNodesPermOps([], {} as Permission)).rejects.toThrow( - aclErrors.ErrorACLNotRunning, - ); await expect(acl.setNodePerm(nodeIdX, {} as Permission)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); - await expect(acl.setNodePermOps(nodeIdX, {} as Permission)).rejects.toThrow( - aclErrors.ErrorACLNotRunning, - ); await expect(acl.unsetNodePerm(nodeIdX)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); - await expect(acl.unsetNodePermOps(nodeIdX)).rejects.toThrow( - aclErrors.ErrorACLNotRunning, - ); await expect(acl.unsetVaultPerms(1 as VaultId)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); await expect(acl.joinNodePerm(nodeIdX, [])).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); - await expect(acl.joinNodePermOps(nodeIdX, [])).rejects.toThrow( - aclErrors.ErrorACLNotRunning, - ); await expect(acl.joinVaultPerms(1 as VaultId, [])).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); @@ -417,35 +406,45 @@ describe(ACL.name, () => { test('transactional operations', async () => { const acl = await ACL.createACL({ db, logger }); const p1 = acl.getNodePerms(); - const p2 = acl.transaction(async (acl) => { - await acl.setNodesPerm([nodeIdG1First, nodeIdG1Second] as Array, { - gestalt: { - notify: null, + const p2 = acl.withTransactionF(async (tran) => { + await acl.setNodesPerm( + [nodeIdG1First, nodeIdG1Second] as Array, + { + gestalt: { + notify: null, + }, + vaults: {}, }, - vaults: {}, - }); - await acl.setNodesPerm([nodeIdG2First, nodeIdG2Second] as Array, { - gestalt: { - notify: null, + tran, + ); + await acl.setNodesPerm( + [nodeIdG2First, nodeIdG2Second] as Array, + { + gestalt: { + notify: null, + }, + vaults: {}, }, - vaults: {}, - }); - await acl.setVaultAction(vaultId1, nodeIdG1First, 'pull'); - await acl.setVaultAction(vaultId1, nodeIdG2First, 'clone'); - await acl.joinNodePerm(nodeIdG1Second, [ - nodeIdG1Third, - nodeIdG1Fourth, - ] as Array); + tran, + ); + await acl.setVaultAction(vaultId1, nodeIdG1First, 'pull', tran); + await acl.setVaultAction(vaultId1, nodeIdG2First, 'clone', tran); + await acl.joinNodePerm( + nodeIdG1Second, + [nodeIdG1Third, nodeIdG1Fourth] as Array, + undefined, + tran, + ); // V3 and v4 joins v1 // this means v3 and v4 now has g1 and g2 permissions - await acl.joinVaultPerms(vaultId1, [vaultId3, vaultId4]); + await acl.joinVaultPerms(vaultId1, [vaultId3, vaultId4], tran); // Removing v3 - await acl.unsetVaultPerms(vaultId3); + await acl.unsetVaultPerms(vaultId3, tran); // Removing g1-second - await acl.unsetNodePerm(nodeIdG1Second); + await acl.unsetNodePerm(nodeIdG1Second, tran); // Unsetting pull just for v1 for g1 - await acl.unsetVaultAction(vaultId1, nodeIdG1First, 'pull'); - return await acl.getNodePerms(); + await acl.unsetVaultAction(vaultId1, nodeIdG1First, 'pull', tran); + return await acl.getNodePerms(tran); }); const p3 = acl.getNodePerms(); const results = await Promise.all([p1, p2, p3]); diff --git a/tests/gestalts/GestaltGraph.test.ts b/tests/gestalts/GestaltGraph.test.ts index fa30c86bd..4b69761ce 100644 --- a/tests/gestalts/GestaltGraph.test.ts +++ b/tests/gestalts/GestaltGraph.test.ts @@ -14,8 +14,8 @@ import path from 'path'; import fs from 'fs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; -import { GestaltGraph } from '@/gestalts'; -import { ACL } from '@/acl'; +import GestaltGraph from '@/gestalts/GestaltGraph'; +import ACL from '@/acl/ACL'; import * as gestaltsErrors from '@/gestalts/errors'; import * as gestaltsUtils from '@/gestalts/utils'; import * as keysUtils from '@/keys/utils'; diff --git a/tests/utils.ts b/tests/utils.ts index 3f446b465..c32329886 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,19 +1,19 @@ -import type { StatusLive } from '@/status/types'; +// Import type { StatusLive } from '@/status/types'; import type { NodeId } from '@/nodes/types'; -import type { Host } from '@/network/types'; +// Import type { Host } from '@/network/types'; import path from 'path'; import fs from 'fs'; import lock from 'fd-lock'; -import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +// Import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; -import PolykeyAgent from '@/PolykeyAgent'; -import Status from '@/status/Status'; -import GRPCClientClient from '@/client/GRPCClientClient'; -import * as clientUtils from '@/client/utils'; +// Import PolykeyAgent from '@/PolykeyAgent'; +// import Status from '@/status/Status'; +// import GRPCClientClient from '@/client/GRPCClientClient'; +// import * as clientUtils from '@/client/utils'; import * as keysUtils from '@/keys/utils'; -import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +// Import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import { sleep } from '@/utils'; -import config from '@/config'; +// Import config from '@/config'; /** * Setup the global keypair @@ -83,105 +83,105 @@ async function setupGlobalKeypair() { * * Ensure client-side side-effects are removed at the end of each test * * Ensure server-side side-effects are removed at the end of each test */ -async function setupGlobalAgent( - logger: Logger = new Logger(setupGlobalAgent.name, LogLevel.WARN, [ - new StreamHandler(), - ]), -) { - const globalAgentPassword = 'password'; - const globalAgentDir = path.join(globalThis.dataDir, 'agent'); - // The references directory will act like our reference count - await fs.promises.mkdir(path.join(globalAgentDir, 'references'), { - recursive: true, - }); - const pid = process.pid.toString(); - // Plus 1 to the reference count - await fs.promises.writeFile(path.join(globalAgentDir, 'references', pid), ''); - const globalAgentLock = await fs.promises.open( - path.join(globalThis.dataDir, 'agent.lock'), - fs.constants.O_WRONLY | fs.constants.O_CREAT, - ); - while (!lock(globalAgentLock.fd)) { - await sleep(1000); - } - const status = new Status({ - statusPath: path.join(globalAgentDir, config.defaults.statusBase), - statusLockPath: path.join(globalAgentDir, config.defaults.statusLockBase), - fs, - }); - let statusInfo = await status.readStatus(); - if (statusInfo == null || statusInfo.status === 'DEAD') { - await PolykeyAgent.createPolykeyAgent({ - password: globalAgentPassword, - nodePath: globalAgentDir, - networkConfig: { - proxyHost: '127.0.0.1' as Host, - forwardHost: '127.0.0.1' as Host, - agentHost: '127.0.0.1' as Host, - clientHost: '127.0.0.1' as Host, - }, - keysConfig: { - rootKeyPairBits: 2048, - }, - seedNodes: {}, // Explicitly no seed nodes on startup - logger, - }); - statusInfo = await status.readStatus(); - } - return { - globalAgentDir, - globalAgentPassword, - globalAgentStatus: statusInfo as StatusLive, - globalAgentClose: async () => { - // Closing the global agent cannot be done in the globalTeardown - // This is due to a sequence of reasons: - // 1. The global agent is not started as a separate process - // 2. Because we need to be able to mock dependencies - // 3. This means it is part of a jest worker process - // 4. Which will block termination of the jest worker process - // 5. Therefore globalTeardown will never get to execute - // 6. The global agent is not part of globalSetup - // 7. Because not all tests need the global agent - // 8. Therefore setupGlobalAgent is lazy and executed by jest worker processes - try { - await fs.promises.rm(path.join(globalAgentDir, 'references', pid)); - // If the references directory is not empty - // there are other processes still using the global agent - try { - await fs.promises.rmdir(path.join(globalAgentDir, 'references')); - } catch (e) { - if (e.code === 'ENOTEMPTY') { - return; - } - throw e; - } - // Stopping may occur in a different jest worker process - // therefore we cannot rely on pkAgent, but instead use GRPC - const statusInfo = (await status.readStatus()) as StatusLive; - const grpcClient = await GRPCClientClient.createGRPCClientClient({ - nodeId: statusInfo.data.nodeId, - host: statusInfo.data.clientHost, - port: statusInfo.data.clientPort, - tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, - logger, - }); - const emptyMessage = new utilsPB.EmptyMessage(); - const meta = clientUtils.encodeAuthFromPassword(globalAgentPassword); - // This is asynchronous - await grpcClient.agentStop(emptyMessage, meta); - await grpcClient.destroy(); - await status.waitFor('DEAD'); - } finally { - lock.unlock(globalAgentLock.fd); - await globalAgentLock.close(); - } - }, - }; -} +// async function setupGlobalAgent( +// logger: Logger = new Logger(setupGlobalAgent.name, LogLevel.WARN, [ +// new StreamHandler(), +// ]), +// ) { +// const globalAgentPassword = 'password'; +// const globalAgentDir = path.join(globalThis.dataDir, 'agent'); +// // The references directory will act like our reference count +// await fs.promises.mkdir(path.join(globalAgentDir, 'references'), { +// recursive: true, +// }); +// const pid = process.pid.toString(); +// // Plus 1 to the reference count +// await fs.promises.writeFile(path.join(globalAgentDir, 'references', pid), ''); +// const globalAgentLock = await fs.promises.open( +// path.join(globalThis.dataDir, 'agent.lock'), +// fs.constants.O_WRONLY | fs.constants.O_CREAT, +// ); +// while (!lock(globalAgentLock.fd)) { +// await sleep(1000); +// } +// const status = new Status({ +// statusPath: path.join(globalAgentDir, config.defaults.statusBase), +// statusLockPath: path.join(globalAgentDir, config.defaults.statusLockBase), +// fs, +// }); +// let statusInfo = await status.readStatus(); +// if (statusInfo == null || statusInfo.status === 'DEAD') { +// await PolykeyAgent.createPolykeyAgent({ +// password: globalAgentPassword, +// nodePath: globalAgentDir, +// networkConfig: { +// proxyHost: '127.0.0.1' as Host, +// forwardHost: '127.0.0.1' as Host, +// agentHost: '127.0.0.1' as Host, +// clientHost: '127.0.0.1' as Host, +// }, +// keysConfig: { +// rootKeyPairBits: 2048, +// }, +// seedNodes: {}, // Explicitly no seed nodes on startup +// logger, +// }); +// statusInfo = await status.readStatus(); +// } +// return { +// globalAgentDir, +// globalAgentPassword, +// globalAgentStatus: statusInfo as StatusLive, +// globalAgentClose: async () => { +// // Closing the global agent cannot be done in the globalTeardown +// // This is due to a sequence of reasons: +// // 1. The global agent is not started as a separate process +// // 2. Because we need to be able to mock dependencies +// // 3. This means it is part of a jest worker process +// // 4. Which will block termination of the jest worker process +// // 5. Therefore globalTeardown will never get to execute +// // 6. The global agent is not part of globalSetup +// // 7. Because not all tests need the global agent +// // 8. Therefore setupGlobalAgent is lazy and executed by jest worker processes +// try { +// await fs.promises.rm(path.join(globalAgentDir, 'references', pid)); +// // If the references directory is not empty +// // there are other processes still using the global agent +// try { +// await fs.promises.rmdir(path.join(globalAgentDir, 'references')); +// } catch (e) { +// if (e.code === 'ENOTEMPTY') { +// return; +// } +// throw e; +// } +// // Stopping may occur in a different jest worker process +// // therefore we cannot rely on pkAgent, but instead use GRPC +// const statusInfo = (await status.readStatus()) as StatusLive; +// const grpcClient = await GRPCClientClient.createGRPCClientClient({ +// nodeId: statusInfo.data.nodeId, +// host: statusInfo.data.clientHost, +// port: statusInfo.data.clientPort, +// tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, +// logger, +// }); +// const emptyMessage = new utilsPB.EmptyMessage(); +// const meta = clientUtils.encodeAuthFromPassword(globalAgentPassword); +// // This is asynchronous +// await grpcClient.agentStop(emptyMessage, meta); +// await grpcClient.destroy(); +// await status.waitFor('DEAD'); +// } finally { +// lock.unlock(globalAgentLock.fd); +// await globalAgentLock.close(); +// } +// }, +// }; +// } function generateRandomNodeId(): NodeId { const random = keysUtils.getRandomBytesSync(16).toString('hex'); return IdInternal.fromString(random); } -export { setupGlobalKeypair, setupGlobalAgent, generateRandomNodeId }; +export { setupGlobalKeypair, generateRandomNodeId }; From abe1c3b1ea3fc9ee961ac4b7c85947b11694c0d4 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 10 May 2022 18:22:50 +1000 Subject: [PATCH 013/137] fix: integrating db changes into vaults --- package-lock.json | 12648 +-------------------------- src/vaults/VaultInternal.ts | 254 +- src/vaults/VaultManager.ts | 511 +- tests/vaults/VaultInternal.test.ts | 126 +- tests/vaults/VaultManager.test.ts | 100 +- tests/vaults/VaultOps.test.ts | 11 +- 6 files changed, 616 insertions(+), 13034 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4ca87586d..4ad9b4ecb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12591 +1,8 @@ { "name": "@matrixai/polykey", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "@matrixai/polykey", - "version": "1.0.0", - "license": "GPL-3.0", - "dependencies": { - "@grpc/grpc-js": "1.3.7", - "@matrixai/async-init": "^1.7.1", - "@matrixai/async-locks": "^2.2.0", - "@matrixai/db": "^3.2.3", - "@matrixai/errors": "^1.0.1", - "@matrixai/id": "^3.3.2", - "@matrixai/logger": "^2.1.0", - "@matrixai/resources": "^1.0.0", - "@matrixai/workers": "^1.3.1", - "ajv": "^7.0.4", - "bip39": "^3.0.3", - "canonicalize": "^1.0.5", - "cheerio": "^1.0.0-rc.5", - "commander": "^8.3.0", - "cross-fetch": "^3.0.6", - "cross-spawn": "^7.0.3", - "encryptedfs": "^3.4.3", - "fast-fuzzy": "^1.10.8", - "fd-lock": "^1.2.0", - "google-protobuf": "^3.14.0", - "ip-num": "^1.3.3-0", - "isomorphic-git": "^1.8.1", - "jose": "^4.3.6", - "lexicographic-integer": "^1.1.0", - "multiformats": "^9.4.8", - "node-forge": "^0.10.0", - "pako": "^1.0.11", - "prompts": "^2.4.1", - "readable-stream": "^3.6.0", - "resource-counter": "^1.2.4", - "threads": "^1.6.5", - "utp-native": "^2.5.3", - "uuid": "^8.3.0" - }, - "bin": { - "pk": "dist/bin/polykey.js", - "polykey": "dist/bin/polykey.js" - }, - "devDependencies": { - "@babel/preset-env": "^7.13.10", - "@types/cross-spawn": "^6.0.2", - "@types/google-protobuf": "^3.7.4", - "@types/jest": "^26.0.20", - "@types/nexpect": "^0.4.31", - "@types/node": "^16.11.7", - "@types/node-forge": "^0.9.7", - "@types/pako": "^1.0.2", - "@types/prompts": "^2.0.13", - "@types/readable-stream": "^2.3.11", - "@types/uuid": "^8.3.0", - "@typescript-eslint/eslint-plugin": "^5.4.0", - "@typescript-eslint/parser": "^5.4.0", - "babel-jest": "^26.6.3", - "eslint": "^7.17.0", - "eslint-config-prettier": "^7.1.0", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-prettier": "^3.3.1", - "grpc_tools_node_protoc_ts": "^5.1.3", - "jest": "^26.6.3", - "jest-mock-process": "^1.4.1", - "jest-mock-props": "^1.9.0", - "mocked-env": "^1.3.5", - "nexpect": "^0.6.0", - "node-gyp-build": "4.4.0", - "pkg": "5.6.0", - "prettier": "^2.2.1", - "ts-jest": "^26.4.4", - "ts-node": "^10.4.0", - "tsconfig-paths": "^3.9.0", - "typedoc": "^0.22.15", - "typescript": "^4.5.2", - "typescript-cached-transpile": "0.0.6" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", - "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.15.8", - "@babel/generator": "^7.15.8", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.8", - "@babel/helpers": "^7.15.4", - "@babel/parser": "^7.15.8", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6", - "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/generator": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", - "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.6", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz", - "integrity": "sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.15.4.tgz", - "integrity": "sha512-P8o7JP2Mzi0SdC6eWr1zF+AEYvrsZa7GSY1lTayjF5XJhVH0kjLYUZPvTMflP7tBgZoe9gIhTa60QwFpqh/E0Q==", - "dev": true, - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", - "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.15.0", - "@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-create-class-features-plugin": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.4.tgz", - "integrity": "sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "regexpu-core": "^4.7.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.15.4.tgz", - "integrity": "sha512-J14f/vq8+hdC2KoWLIQSsGrC9EFBKE4NFts8pfMpymfApds+fPqR30AOUWc4tyr56h9l/GA1Sxv2q3dLZWbQ/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", - "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", - "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", - "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-simple-access": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", - "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "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-remap-async-to-generator": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz", - "integrity": "sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-wrap-function": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", - "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", - "dev": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", - "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.15.4.tgz", - "integrity": "sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "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/helper-wrap-function": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.15.4.tgz", - "integrity": "sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", - "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "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/parser": { - "version": "7.16.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", - "integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.15.4.tgz", - "integrity": "sha512-eBnpsl9tlhPhpI10kU06JHnrYXwg3+V6CaP2idsCXNef0aeslpqyITXQ74Vfk5uHgY7IG7XP0yIH8b42KSzHog==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4", - "@babel/plugin-proposal-optional-chaining": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.8.tgz", - "integrity": "sha512-2Z5F2R2ibINTc63mY7FLqGfEbmofrHU9FitJW1Q7aPaKFhiPvSq6QEt/BoWN5oME3GVyjcRuNNSRbb9LC0CSWA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.15.4", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz", - "integrity": "sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.15.4.tgz", - "integrity": "sha512-M682XWrrLNk3chXCjoPUQWOyYsB93B9z3mRyjtqqYJWDf2mfCdIYgDrA11cgNVhAQieaq6F2fn2f3wI0U4aTjA==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz", - "integrity": "sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz", - "integrity": "sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz", - "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz", - "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz", - "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz", - "integrity": "sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.15.6.tgz", - "integrity": "sha512-qtOHo7A1Vt+O23qEAX+GdBpqaIuD3i9VRrWgCJeq7WO6H2d14EK3q11urj5Te2MAeK97nMiIdRpwd/ST4JFbNg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", - "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz", - "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz", - "integrity": "sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.15.4.tgz", - "integrity": "sha512-X0UTixkLf0PCCffxgu5/1RQyGGbgZuKoI+vXP4iSbJSYwPb7hu06omsFGBvQ9lJEvwgrxHdS8B5nbfcd8GyUNA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-create-class-features-plugin": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz", - "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.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-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "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-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "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-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "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-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-transform-arrow-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", - "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", - "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-transform-async-to-generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", - "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", - "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", - "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-transform-block-scoping": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz", - "integrity": "sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q==", - "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-transform-classes": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.15.4.tgz", - "integrity": "sha512-Yjvhex8GzBmmPQUvpXRPWQ9WnxXgAFuZSrqOK/eJlOGIXwvv8H3UEdUigl1gb/bnjTrln+e8bkZUYCBt/xYlBg==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", - "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", - "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-transform-destructuring": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", - "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", - "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-transform-dotall-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz", - "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz", - "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", - "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-transform-exponentiation-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", - "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.15.4.tgz", - "integrity": "sha512-DRTY9fA751AFBDh2oxydvVm4SYevs5ILTWLs6xKXps4Re/KG5nfUkr+TdHCrRWB8C69TlzVgA9b3RmGWmgN9LA==", - "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-transform-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz", - "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", - "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", - "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-transform-member-expression-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz", - "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", - "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-transform-modules-amd": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz", - "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.4.tgz", - "integrity": "sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-simple-access": "^7.15.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.15.4.tgz", - "integrity": "sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw==", - "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz", - "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz", - "integrity": "sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz", - "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", - "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-transform-object-super": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", - "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.15.4.tgz", - "integrity": "sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ==", - "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-transform-property-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", - "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", - "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-transform-regenerator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", - "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", - "dev": true, - "dependencies": { - "regenerator-transform": "^0.14.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz", - "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", - "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-transform-shorthand-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", - "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", - "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-transform-spread": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.15.8.tgz", - "integrity": "sha512-/daZ8s2tNaRekl9YJa9X4bzjpeRZLt122cpgFnQPLGUe61PH8zMEBmYqKkW5xF5JUEh5buEGXJoQpqBmIbpmEQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", - "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", - "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-transform-template-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", - "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", - "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-transform-typeof-symbol": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", - "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", - "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-transform-unicode-escapes": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz", - "integrity": "sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==", - "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-transform-unicode-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", - "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.8.tgz", - "integrity": "sha512-rCC0wH8husJgY4FPbHsiYyiLxSY8oMDJH7Rl6RQMknbN9oDDHhM9RDFvnGM2MgkbUJzSQB4gtuwygY5mCqGSsA==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.15.4", - "@babel/plugin-proposal-async-generator-functions": "^7.15.8", - "@babel/plugin-proposal-class-properties": "^7.14.5", - "@babel/plugin-proposal-class-static-block": "^7.15.4", - "@babel/plugin-proposal-dynamic-import": "^7.14.5", - "@babel/plugin-proposal-export-namespace-from": "^7.14.5", - "@babel/plugin-proposal-json-strings": "^7.14.5", - "@babel/plugin-proposal-logical-assignment-operators": "^7.14.5", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", - "@babel/plugin-proposal-numeric-separator": "^7.14.5", - "@babel/plugin-proposal-object-rest-spread": "^7.15.6", - "@babel/plugin-proposal-optional-catch-binding": "^7.14.5", - "@babel/plugin-proposal-optional-chaining": "^7.14.5", - "@babel/plugin-proposal-private-methods": "^7.14.5", - "@babel/plugin-proposal-private-property-in-object": "^7.15.4", - "@babel/plugin-proposal-unicode-property-regex": "^7.14.5", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@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-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.14.5", - "@babel/plugin-transform-async-to-generator": "^7.14.5", - "@babel/plugin-transform-block-scoped-functions": "^7.14.5", - "@babel/plugin-transform-block-scoping": "^7.15.3", - "@babel/plugin-transform-classes": "^7.15.4", - "@babel/plugin-transform-computed-properties": "^7.14.5", - "@babel/plugin-transform-destructuring": "^7.14.7", - "@babel/plugin-transform-dotall-regex": "^7.14.5", - "@babel/plugin-transform-duplicate-keys": "^7.14.5", - "@babel/plugin-transform-exponentiation-operator": "^7.14.5", - "@babel/plugin-transform-for-of": "^7.15.4", - "@babel/plugin-transform-function-name": "^7.14.5", - "@babel/plugin-transform-literals": "^7.14.5", - "@babel/plugin-transform-member-expression-literals": "^7.14.5", - "@babel/plugin-transform-modules-amd": "^7.14.5", - "@babel/plugin-transform-modules-commonjs": "^7.15.4", - "@babel/plugin-transform-modules-systemjs": "^7.15.4", - "@babel/plugin-transform-modules-umd": "^7.14.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.9", - "@babel/plugin-transform-new-target": "^7.14.5", - "@babel/plugin-transform-object-super": "^7.14.5", - "@babel/plugin-transform-parameters": "^7.15.4", - "@babel/plugin-transform-property-literals": "^7.14.5", - "@babel/plugin-transform-regenerator": "^7.14.5", - "@babel/plugin-transform-reserved-words": "^7.14.5", - "@babel/plugin-transform-shorthand-properties": "^7.14.5", - "@babel/plugin-transform-spread": "^7.15.8", - "@babel/plugin-transform-sticky-regex": "^7.14.5", - "@babel/plugin-transform-template-literals": "^7.14.5", - "@babel/plugin-transform-typeof-symbol": "^7.14.5", - "@babel/plugin-transform-unicode-escapes": "^7.14.5", - "@babel/plugin-transform-unicode-regex": "^7.14.5", - "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.15.6", - "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.5", - "babel-plugin-polyfill-regenerator": "^0.2.2", - "core-js-compat": "^3.16.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", - "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime/node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "node_modules/@babel/template": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", - "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.15.7", - "to-fast-properties": "^2.0.0" - }, - "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/@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "dev": true, - "dependencies": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - }, - "bin": { - "watch": "cli.js" - }, - "engines": { - "node": ">=0.1.95" - } - }, - "node_modules/@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-consumer": "0.8.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/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/@grpc/grpc-js": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.3.7.tgz", - "integrity": "sha512-CKQVuwuSPh40tgOkR7c0ZisxYRiN05PcKPW72mQL5y++qd7CwBRoaJZvU5xfXnCJDFBmS3qZGQ71Frx6Ofo2XA==", - "dependencies": { - "@types/node": ">=12.12.47" - }, - "engines": { - "node": "^8.13.0 || >=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", - "dev": true - }, - "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/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": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/console/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/@jest/console/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/console/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/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/@jest/core/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/core/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/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.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": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" - }, - "engines": { - "node": ">= 10.14.2" - }, - "optionalDependencies": { - "node-notifier": "^8.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/@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/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/@jest/reporters/node_modules/node-notifier": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", - "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", - "dev": true, - "optional": true, - "dependencies": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" - } - }, - "node_modules/@jest/reporters/node_modules/node-notifier/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@jest/reporters/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/@jest/reporters/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/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/source-map/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/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.6.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": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/@jest/transform/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/transform/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/@jest/transform/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/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/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/@jest/types/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/types/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/@matrixai/async-init": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.7.1.tgz", - "integrity": "sha512-3ELRuEn6AoC3e0b4QccA+NxZl0LilyjYeu6a3Pf9VUVB89EepnNKsk/Afb9qa+B5LvLQwmgHtg4r9VwRpQpnQA==", - "dependencies": { - "@matrixai/async-locks": "^2.2.0", - "@matrixai/errors": "^1.0.1" - } - }, - "node_modules/@matrixai/async-locks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.2.0.tgz", - "integrity": "sha512-i0a551EUMhD1WKpaAyhBUt83ckbOxPB4MlOH8VDzeDyPMAtLI9egCqf3HWOvhN0rSjoH97EmzmfxyAeAgiQzTw==", - "dependencies": { - "@matrixai/errors": "^1.0.1", - "@matrixai/resources": "^1.0.0", - "async-mutex": "^0.3.2" - } - }, - "node_modules/@matrixai/db": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.3.1.tgz", - "integrity": "sha512-EQulm82sBhw1WRhOzzWMoij1SwpjAQHgyokxleTwFHoAnDPMi4WVy4AIxd2lJMPOhhzEFQxCqQmmMYhZWwYAPg==", - "dependencies": { - "@matrixai/async-init": "^1.7.0", - "@matrixai/errors": "^1.0.1", - "@matrixai/logger": "^2.1.0", - "@matrixai/resources": "^1.0.0", - "@matrixai/workers": "^1.3.0", - "@types/abstract-leveldown": "^7.2.0", - "level": "7.0.1", - "threads": "^1.6.5" - } - }, - "node_modules/@matrixai/errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.0.1.tgz", - "integrity": "sha512-9NbIm3rPMkZz+Ma5tfKduVCWfvYzdHlO89u9mBap7FzJqXkl4yoENjMZm5Do6PvhtIYtRcm6+eTgWvHd6pkdGg==", - "dependencies": { - "ts-custom-error": "^3.2.0" - } - }, - "node_modules/@matrixai/id": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@matrixai/id/-/id-3.3.2.tgz", - "integrity": "sha512-gpW56P7jZILPc0oxyNQvZBkEBn30JPGpslOHIcDoKnCZR8VGZXEKX485xy1WE4MBiQHXdGeiYF8A2CluqTnu3w==", - "dependencies": { - "multiformats": "^9.4.8", - "uuid": "^8.3.2" - } - }, - "node_modules/@matrixai/logger": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.1.0.tgz", - "integrity": "sha512-UmLuXi2PJ03v0Scfl57217RPnjEZDRLlpfdIjIwCfju+kofnhhCI9P7OZu3/FgW147vbvSzWCrrtpwJiLROUUA==" - }, - "node_modules/@matrixai/resources": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@matrixai/resources/-/resources-1.0.0.tgz", - "integrity": "sha512-B1ZkySZwOZTIzhK+YTN4HifOTd1dk1ifDUV8/8WgGho2nUZzIMYms7iDmW/ZHUCkqvWupKY6AYvfwnKBOJJnWg==" - }, - "node_modules/@matrixai/workers": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@matrixai/workers/-/workers-1.3.1.tgz", - "integrity": "sha512-AXI37aZ7gSqS5PpUCG7/yfNcnWNYiQUp4yFBY1Z9lKk0zrkQzND1zPjDuJ2E7t6E1a4rwa8vtysj5TVeMCA8jw==", - "dependencies": { - "@matrixai/async-init": "^1.7.0", - "@matrixai/errors": "^1.0.1", - "@matrixai/logger": "^2.1.0", - "threads": "^1.6.5" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "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": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "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/@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, - "node_modules/@types/abstract-leveldown": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", - "integrity": "sha512-q5veSX6zjUy/DlDhR4Y4cU0k2Ar+DT2LUraP00T19WLmTO6Se1djepCCaqU6nQrwcJ5Hyo/CWqxTzrrFg8eqbQ==" - }, - "node_modules/@types/babel__core": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", - "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", - "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.3", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", - "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/cross-spawn": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.2.tgz", - "integrity": "sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/google-protobuf": { - "version": "3.15.5", - "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.5.tgz", - "integrity": "sha512-6bgv24B+A2bo9AfzReeg5StdiijKzwwnRflA8RLd1V4Yv995LeTmo0z69/MPbBDFSiZWdZHQygLo/ccXhMEDgw==", - "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.24", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", - "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", - "dev": true, - "dependencies": { - "jest-diff": "^26.0.0", - "pretty-format": "^26.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "node_modules/@types/nexpect": { - "version": "0.4.31", - "resolved": "https://registry.npmjs.org/@types/nexpect/-/nexpect-0.4.31.tgz", - "integrity": "sha512-Plh9Dlj2AKdsblgF1Pv7s2BjlojqW93d1zIUtK5xVVrUjkZQezyWIOAq0Xfwp0e0SDQ70YmaDqzhoJru2kqVPA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "16.11.29", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.29.tgz", - "integrity": "sha512-9dDdonLyPJQJ/kdOlDxAah+bTI+u2ccF3k62FErhquDuggoCX6piWez7j7o6yNE+rP2IRcZVQ6Tw4N0P38+rWA==" - }, - "node_modules/@types/node-forge": { - "version": "0.9.10", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-0.9.10.tgz", - "integrity": "sha512-+BbPlhZeYs/WETWftQi2LeRx9VviWSwawNo+Pid5qNrSZHb60loYjpph3OrbwXMMseadu9rE9NeK34r4BHT+QQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "dev": true - }, - "node_modules/@types/pako": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.2.tgz", - "integrity": "sha512-8UJl2MjkqqS6ncpLZqRZ5LmGiFBkbYxocD4e4jmBqGvfRG1RS23gKsBQbdtV9O9GvRyjFTiRHRByjSlKCLlmZw==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", - "dev": true - }, - "node_modules/@types/prompts": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.14.tgz", - "integrity": "sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/readable-stream": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.11.tgz", - "integrity": "sha512-0z+/apYJwKFz/RHp6mOMxz/y7xOvWPYPevuCEyAY3gXsjtaac02E26RvxA+I96rfvmVH/dEMGXNvyJfViR1FSQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "safe-buffer": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "15.0.14", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", - "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.4.0.tgz", - "integrity": "sha512-9/yPSBlwzsetCsGEn9j24D8vGQgJkOTr4oMLas/w886ZtzKIs1iyoqFrwsX2fqYEeUwsdBpC21gcjRGo57u0eg==", - "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "5.4.0", - "@typescript-eslint/scope-manager": "5.4.0", - "debug": "^4.3.2", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.2.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.4.0.tgz", - "integrity": "sha512-Nz2JDIQUdmIGd6p33A+naQmwfkU5KVTLb/5lTk+tLVTDacZKoGQisj8UCxk7onJcrgjIvr8xWqkYI+DbI3TfXg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.4.0", - "@typescript-eslint/types": "5.4.0", - "@typescript-eslint/typescript-estree": "5.4.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.4.0.tgz", - "integrity": "sha512-JoB41EmxiYpaEsRwpZEYAJ9XQURPFer8hpkIW9GiaspVLX8oqbqNM8P4EP8HOZg96yaALiLEVWllA2E8vwsIKw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.4.0", - "@typescript-eslint/types": "5.4.0", - "@typescript-eslint/typescript-estree": "5.4.0", - "debug": "^4.3.2" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.4.0.tgz", - "integrity": "sha512-pRxFjYwoi8R+n+sibjgF9iUiAELU9ihPBtHzocyW8v8D8G8KeQvXTsW7+CBYIyTYsmhtNk50QPGLE3vrvhM5KA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.4.0", - "@typescript-eslint/visitor-keys": "5.4.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.4.0.tgz", - "integrity": "sha512-GjXNpmn+n1LvnttarX+sPD6+S7giO+9LxDIGlRl4wK3a7qMWALOHYuVSZpPTfEIklYjaWuMtfKdeByx0AcaThA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.4.0.tgz", - "integrity": "sha512-nhlNoBdhKuwiLMx6GrybPT3SFILm5Gij2YBdPEPFlYNFAXUJWX6QRgvi/lwVoadaQEFsizohs6aFRMqsXI2ewA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.4.0", - "@typescript-eslint/visitor-keys": "5.4.0", - "debug": "^4.3.2", - "globby": "^11.0.4", - "is-glob": "^4.0.3", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.4.0.tgz", - "integrity": "sha512-PVbax7MeE7tdLfW5SA0fs8NGVVr+buMPrcj+CWYWPXsZCH8qZ1THufDzbXm1xrZ2b2PA1iENJ0sRq5fuUtvsJg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.4.0", - "eslint-visitor-keys": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "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/abstract-leveldown": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", - "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", - "dependencies": { - "buffer": "^6.0.3", - "catering": "^2.0.0", - "is-buffer": "^2.0.5", - "level-concat-iterator": "^3.0.0", - "level-supports": "^2.0.1", - "queue-microtask": "^1.2.3" - }, - "engines": { - "node": ">=10" - } - }, - "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-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "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/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": "7.2.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.4.tgz", - "integrity": "sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "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": "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/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/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "node_modules/are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "dev": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "node_modules/are-we-there-yet/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/are-we-there-yet/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/are-we-there-yet/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/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "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/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async-lock": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.3.0.tgz", - "integrity": "sha512-8A7SkiisnEgME2zEedtDYPxUPzdv3x//E7n5IFktPAtMYSEAV7eNJF0rMwrVyUFj6d/8rgajLantbjcNRQYXIg==" - }, - "node_modules/async-mutex": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", - "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", - "dependencies": { - "tslib": "^2.3.1" - } - }, - "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/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/babel-jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", - "dev": true, - "dependencies": { - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/babel-jest/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/babel-jest/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/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "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": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", - "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.14.2" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", - "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.2.2", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz", - "integrity": "sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.16.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz", - "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.2.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.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": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^26.6.2", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dependencies": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "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/big-integer": { - "version": "1.6.50", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.50.tgz", - "integrity": "sha512-+O2uoQWFRo8ysZNo/rjtri2jIwjr3XfeAgRjAUADRqGG+ZITvyn8J1kvXLTaKVr3hhGXk+f23tKfdzmklVM9vQ==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/bip39": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz", - "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==", - "dependencies": { - "@types/node": "11.11.6", - "create-hash": "^1.1.0", - "pbkdf2": "^3.0.9", - "randombytes": "^2.0.1" - } - }, - "node_modules/bip39/node_modules/@types/node": { - "version": "11.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", - "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" - }, - "node_modules/bitset": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/bitset/-/bitset-5.1.1.tgz", - "integrity": "sha512-oKaRp6mzXedJ1Npo86PKhWfDelI6HxxJo+it9nAcBB0HLVvYVp+5i6yj6DT5hfFgo+TS5T57MRWtw8zhwdTs3g==", - "engines": { - "node": "*" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "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" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" - }, - "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.17.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", - "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", - "dev": true, - "dependencies": { - "caniuse-lite": "^1.0.30001265", - "electron-to-chromium": "^1.3.867", - "escalade": "^3.1.1", - "node-releases": "^2.0.0", - "picocolors": "^1.0.0" - }, - "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/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": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "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/caniuse-lite": { - "version": "1.0.30001269", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001269.tgz", - "integrity": "sha512-UOy8okEVs48MyHYgV+RdW1Oiudl1H6KolybD6ZquD0VcrPSgj25omXO1S7rDydjpqaISCwA8Pyx+jUQKZwWO5w==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/canonicalize": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-1.0.5.tgz", - "integrity": "sha512-mAjKJPIyP0xqqv6IAkvso07StOmz6cmGtNDg3pXCSzXVZOqka7StIkAhJl/zHOi4M2CgpYfD6aeRWbnrmtvBEA==" - }, - "node_modules/capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "dependencies": { - "rsvp": "^4.8.4" - }, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/catering": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", - "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", - "engines": { - "node": ">=6" - } - }, - "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/chalk/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/chalk/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/chalk/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/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/check-more-types": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "dependencies": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", - "dependencies": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", - "dev": true - }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clean-git-ref": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", - "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==" - }, - "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/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/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "engines": { - "node": ">=0.10.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/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/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/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": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "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/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "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/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.", - "hasInstallScript": true - }, - "node_modules/core-js-compat": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.18.3.tgz", - "integrity": "sha512-4zP6/y0a2RTHN5bRGT7PTq9lVt3WzvffTNjqnTKsXhkAYNDTkdCLOIfAdOLcQ/7TDdyRj3c+NeHe1NmF1eDScw==", - "dev": true, - "dependencies": { - "browserslist": "^4.17.3", - "semver": "7.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/crc-32": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", - "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", - "dependencies": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - }, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-fetch": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", - "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", - "dependencies": { - "node-fetch": "2.6.1" - } - }, - "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==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "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.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "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/deferred-leveldown": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-7.0.0.tgz", - "integrity": "sha512-QKN8NtuS3BC6m0B8vAnBls44tX1WXAFATUsJlruyAYbZpysWV3siH6o/i3g9DCHauzodksO60bdj5NazNbjCmg==", - "dependencies": { - "abstract-leveldown": "^7.2.0", - "inherits": "^2.0.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defined": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", - "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=" - }, - "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/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "dev": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "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": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/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/diff3": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", - "integrity": "sha1-1OXDpM305f4SEatC5pP8tDIVgPw=" - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "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/domhandler": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.3.871", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.871.tgz", - "integrity": "sha512-qcLvDUPf8DSIMWarHT2ptgcqrYg62n3vPA7vhrOF24d8UNzbUBaHu2CySiENR3nEDzYgaN60071t0F6KLYMQ7Q==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "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/encoding-down": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-7.1.0.tgz", - "integrity": "sha512-ky47X5jP84ryk5EQmvedQzELwVJPjCgXDQZGeb9F6r4PdChByCGHTBrVcF3h8ynKVJ1wVbkxTsDC8zBROPypgQ==", - "dependencies": { - "abstract-leveldown": "^7.2.0", - "inherits": "^2.0.3", - "level-codec": "^10.0.0", - "level-errors": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/encryptedfs": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/encryptedfs/-/encryptedfs-3.4.3.tgz", - "integrity": "sha512-OQqsGw3eNrMdFpiYRX17nMq1NKKebaA0KXyM9IRY9aPOxpaeOwcdvWnOcvvO9wCxZFNxgy/A2SOZdxnhCe3paA==", - "dependencies": { - "@matrixai/async-init": "^1.6.0", - "@matrixai/db": "^1.1.5", - "@matrixai/logger": "^2.1.0", - "@matrixai/workers": "^1.2.5", - "async-mutex": "^0.3.2", - "errno": "^0.1.7", - "lexicographic-integer": "^1.1.0", - "node-forge": "^0.10.0", - "readable-stream": "^3.6.0", - "resource-counter": "^1.2.4", - "threads": "^1.6.5", - "ts-custom-error": "^3.2.0", - "util-callbackify": "^1.0.0" - } - }, - "node_modules/encryptedfs/node_modules/@matrixai/db": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-1.2.1.tgz", - "integrity": "sha512-1W8TORmRX3q3NugZFn0FTgI0mo/n0nWBTXHKXwwPfxtdyNfi18JCj3HVCwWdToOo87ypnS/mqLDIUTSHbF7F3Q==", - "dependencies": { - "@matrixai/async-init": "^1.6.0", - "@matrixai/logger": "^2.1.0", - "@matrixai/workers": "^1.2.5", - "abstract-leveldown": "^7.2.0", - "async-mutex": "^0.3.1", - "level": "7.0.1", - "levelup": "^5.1.1", - "sublevel-prefixer": "^1.0.0", - "subleveldown": "^6.0.1", - "threads": "^1.6.5", - "ts-custom-error": "^3.2.0" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.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/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "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==", - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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/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, - "optional": true, - "engines": { - "node": ">=0.10.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.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "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", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.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.merge": "^4.6.2", - "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": "^6.0.9", - "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-config-prettier": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", - "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", - "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0", - "pkg-dir": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "dependencies": { - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.25.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", - "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.1", - "has": "^1.0.3", - "is-core-module": "^2.8.0", - "is-glob": "^4.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.11.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-plugin-prettier": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", - "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "peerDependencies": { - "eslint": ">=5.0.0", - "prettier": ">=1.13.0" - }, - "peerDependenciesMeta": { - "eslint-config-prettier": { - "optional": true - } - } - }, - "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": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/eslint/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/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/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/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/node_modules/globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/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/eslint/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/eslint/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/eslint/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/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/esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "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.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "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/exec-sh": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", - "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", - "dev": true - }, - "node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/execa/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/execa/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/execa/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/execa/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "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/exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.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==" - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "node_modules/fast-fuzzy": { - "version": "1.10.10", - "resolved": "https://registry.npmjs.org/fast-fuzzy/-/fast-fuzzy-1.10.10.tgz", - "integrity": "sha512-TkXYYQcLyZ5tbDpg3kj5gq7PNl6vQQQEW99/sBpmYYRPcuCaZElm3FpoOOqwL51+1prhjrzsnGAjWgNCG7iVOA==", - "dependencies": { - "graphemesplit": "^2.4.1" - } - }, - "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "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/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "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/fd-lock": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fd-lock/-/fd-lock-1.2.0.tgz", - "integrity": "sha512-Lk/pKH2DldLpG4Yh/sOOY84k5VqNzxHPffGwf1+yYI+/qMXzTPp9KJMX+Wh6n4xqGSA1Mu7JPmaDArfJGw2O/A==", - "hasInstallScript": true, - "dependencies": { - "napi-macros": "^2.0.0", - "node-gyp-build": "^4.2.2" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "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": "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/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.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "node_modules/from2/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/from2/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/from2/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/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs-extra/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "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==" - }, - "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/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "node_modules/gauge/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "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/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/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/google-protobuf": { - "version": "3.18.1", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.18.1.tgz", - "integrity": "sha512-cDqSamZ8rGs+pOzhIsBte7wpezUKg/sggeptDWN5odhnRY/eDLa5VWLeNeQvcfiqjS3yUwgM+6OePCJMB7aWZA==" - }, - "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/graphemesplit": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/graphemesplit/-/graphemesplit-2.4.4.tgz", - "integrity": "sha512-lKrpp1mk1NH26USxC/Asw4OHbhSQf5XfrWZ+CDv/dFVvd1j17kFgMotdJvOesmHkbFX9P9sBfpH8VogxOWLg8w==", - "dependencies": { - "js-base64": "^3.6.0", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true - }, - "node_modules/grpc_tools_node_protoc_ts": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/grpc_tools_node_protoc_ts/-/grpc_tools_node_protoc_ts-5.3.2.tgz", - "integrity": "sha512-7xPSeu8bwjcird3i9R5+9O4BF2Lhv9fMBdeobfUc2Bys9tSVtm/VB3WjTpKV78WlLYJyD94+wL/8hJqaMZ53Hw==", - "dev": true, - "dependencies": { - "google-protobuf": "3.15.8", - "handlebars": "4.7.7" - }, - "bin": { - "protoc-gen-ts": "bin/protoc-gen-ts" - } - }, - "node_modules/grpc_tools_node_protoc_ts/node_modules/google-protobuf": { - "version": "3.15.8", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.15.8.tgz", - "integrity": "sha512-2jtfdqTaSxk0cuBJBtTTWsot4WtR9RVr2rXg7x7OoqiuOKopPrwXpM1G4dXIkLcUNRh3RKzz76C8IOkksZSeOw==", - "dev": true - }, - "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/handlebars/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/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "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/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "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": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, - "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/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "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/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/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/import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", - "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/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==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/into-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", - "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", - "dev": true, - "dependencies": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ip-num": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/ip-num/-/ip-num-1.3.3.tgz", - "integrity": "sha512-1QsiMKglDaemuIktincG1ntr3DvVTV/pU++eyG7vIm4xd+gvtJ9eoB34RRbI9YTqn1U5og16n7+1RgwLhv4RmA==", - "dependencies": { - "big-integer": "^1.6.48" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "optional": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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": "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/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.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-observable": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-2.1.0.tgz", - "integrity": "sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.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-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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/is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "dependencies": { - "call-bind": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "optional": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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=" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isomorphic-git": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.10.1.tgz", - "integrity": "sha512-abbPpKkykIVDJ92rtYoD4AOuT5/7PABHR2fDBrsm7H0r2ZT+MGpPL/FynrEJM6nTcFSieaIDxnHNGhfHO/v+bA==", - "dependencies": { - "async-lock": "^1.1.0", - "clean-git-ref": "^2.0.1", - "crc-32": "^1.2.0", - "diff3": "0.0.3", - "ignore": "^5.1.4", - "minimisted": "^2.0.0", - "pako": "^1.0.10", - "pify": "^4.0.1", - "readable-stream": "^3.4.0", - "sha.js": "^2.4.9", - "simple-get": "^3.0.2" - }, - "bin": { - "isogit": "cli.cjs" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.1.0.tgz", - "integrity": "sha512-OFSPP1Csv3GxruycNA1iRJPnc5pon+N4Q89EUz8KYOFbdsqCoHRh0J8jwRdna5thveVcMTdgY27kUl/lZuAWdw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.0.4.tgz", - "integrity": "sha512-W6jJF9rLGEISGoCyXRqa/JCGQGmmxPO10TMu7izaUTynxvBvTjqzAIIGCK9USBmIbQAaSWD6XJPrM9Pv5INknw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "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.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps/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/istanbul-reports": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", - "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", - "dev": true, - "dependencies": { - "@jest/core": "^26.6.3", - "import-local": "^3.0.2", - "jest-cli": "^26.6.3" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-changed-files": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-changed-files/node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-changed-files/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-changed-files/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/jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-config/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-config/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-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-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-diff/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-diff/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-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-each/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-each/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-environment-jsdom": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", - "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2", - "jsdom": "^16.4.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "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": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.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": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7" - }, - "engines": { - "node": ">= 10.14.2" - }, - "optionalDependencies": { - "fsevents": "^2.1.2" - } - }, - "node_modules/jest-jasmine2": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", - "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^26.6.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-jasmine2/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-jasmine2/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-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", - "dev": true, - "dependencies": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-matcher-utils/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-matcher-utils/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-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-message-util/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-message-util/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-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-mock-process": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jest-mock-process/-/jest-mock-process-1.4.1.tgz", - "integrity": "sha512-ZZUKRlEBizutngoO4KngzN30YoeAYP3nnwimk4cpi9WqLxQUf6SlAPK5p1D9usEpxDS3Uif2MIez3Bq0vGYR+g==", - "dev": true, - "peerDependencies": { - "jest": ">=23.4 <28" - } - }, - "node_modules/jest-mock-props": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/jest-mock-props/-/jest-mock-props-1.9.0.tgz", - "integrity": "sha512-8IlIiZRvovnRuvqcvWZyDv4CyhrUGTbEW/1eKurHr2JY4VhIWQIPlbpt9lqL2nxdGnco+OcgpPBwGYCEeDb2+A==", - "dev": true, - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "jest": ">=24.0.0" - } - }, - "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": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-resolve/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-resolve/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-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.7.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "source-map-support": "^0.5.6", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/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/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-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.4.1" - }, - "bin": { - "jest-runtime": "bin/jest-runtime.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-runtime/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/jest-runtime/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-runtime/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-runtime/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", - "dev": true, - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-snapshot/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-snapshot/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-snapshot/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-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-util/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-util/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-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "leven": "^3.1.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "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/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-validate/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-validate/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-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^26.6.2", - "string-length": "^4.0.1" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest-watcher/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-watcher/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-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/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/jest/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/jest/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/node_modules/jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", - "dev": true, - "dependencies": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "prompts": "^2.0.1", - "yargs": "^15.4.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest/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/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/jest/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jose": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.3.6.tgz", - "integrity": "sha512-A/JgZGUerqG2IMuxkUDBtZ4aTxg/l1Y+pt/QAAYiRAR3EFlxIE0Su0xdpB8tQcPZK5eudB7g1PHCZ5uHatbY+g==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-base64": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.2.tgz", - "integrity": "sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==" - }, - "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.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "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.6", - "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.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", - "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-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "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.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", - "dev": true - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonfile/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "engines": { - "node": ">=6" - } - }, - "node_modules/lazy-ass": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", - "dev": true, - "engines": { - "node": "> 0.8" - } - }, - "node_modules/level": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/level/-/level-7.0.1.tgz", - "integrity": "sha512-w3E64+ALx2eZf8RV5JL4kIcE0BFAvQscRYd1yU4YVqZN9RGTQxXSvH202xvK15yZwFFxRXe60f13LJjcJ//I4Q==", - "dependencies": { - "level-js": "^6.1.0", - "level-packager": "^6.0.1", - "leveldown": "^6.1.0" - }, - "engines": { - "node": ">=10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/level" - } - }, - "node_modules/level-codec": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-10.0.0.tgz", - "integrity": "sha512-QW3VteVNAp6c/LuV6nDjg7XDXx9XHK4abmQarxZmlRSDyXYk20UdaJTSX6yzVvQ4i0JyWSB7jert0DsyD/kk6g==", - "dependencies": { - "buffer": "^6.0.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/level-concat-iterator": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", - "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", - "dependencies": { - "catering": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/level-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-3.0.1.tgz", - "integrity": "sha512-tqTL2DxzPDzpwl0iV5+rBCv65HWbHp6eutluHNcVIftKZlQN//b6GEnZDM2CvGZvzGYMwyPtYppYnydBQd2SMQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/level-iterator-stream": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-5.0.0.tgz", - "integrity": "sha512-wnb1+o+CVFUDdiSMR/ZymE2prPs3cjVLlXuDeSq9Zb8o032XrabGEXcTCsBxprAtseO3qvFeGzh6406z9sOTRA==", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/level-js": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/level-js/-/level-js-6.1.0.tgz", - "integrity": "sha512-i7mPtkZm68aewfv0FnIUWvFUFfoyzIvVKnUmuQGrelEkP72vSPTaA1SGneWWoCV5KZJG4wlzbJLp1WxVNGuc6A==", - "dependencies": { - "abstract-leveldown": "^7.2.0", - "buffer": "^6.0.3", - "inherits": "^2.0.3", - "ltgt": "^2.1.2", - "run-parallel-limit": "^1.1.0" - } - }, - "node_modules/level-option-wrap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/level-option-wrap/-/level-option-wrap-1.1.0.tgz", - "integrity": "sha1-rSDmjZ88IsiJdTHMaqevWWse0Sk=", - "dependencies": { - "defined": "~0.0.0" - } - }, - "node_modules/level-packager": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-6.0.1.tgz", - "integrity": "sha512-8Ezr0XM6hmAwqX9uu8IGzGNkWz/9doyPA8Oo9/D7qcMI6meJC+XhIbNYHukJhIn8OGdlzQs/JPcL9B8lA2F6EQ==", - "dependencies": { - "encoding-down": "^7.1.0", - "levelup": "^5.1.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/level-supports": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", - "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/leveldown": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.1.tgz", - "integrity": "sha512-88c+E+Eizn4CkQOBHwqlCJaTNEjGpaEIikn1S+cINc5E9HEvJ77bqY4JY/HxT5u0caWqsc3P3DcFIKBI1vHt+A==", - "hasInstallScript": true, - "dependencies": { - "abstract-leveldown": "^7.2.0", - "napi-macros": "~2.0.0", - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/levelup": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-5.1.1.tgz", - "integrity": "sha512-0mFCcHcEebOwsQuk00WJwjLI6oCjbBuEYdh/RaRqhjnyVlzqf41T1NnDtCedumZ56qyIh8euLFDqV1KfzTAVhg==", - "dependencies": { - "catering": "^2.0.0", - "deferred-leveldown": "^7.0.0", - "level-errors": "^3.0.1", - "level-iterator-stream": "^5.0.0", - "level-supports": "^2.0.1", - "queue-microtask": "^1.2.3" - }, - "engines": { - "node": ">=10" - } - }, - "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/lexicographic-integer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/lexicographic-integer/-/lexicographic-integer-1.1.0.tgz", - "integrity": "sha1-UsptmYpXLmMitRX1uA45bGBD6bg=" - }, - "node_modules/lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "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/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "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/ltgt": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", - "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=" - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true - }, - "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-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/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/marked": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.14.tgz", - "integrity": "sha512-HL5sSPE/LP6U9qKgngIIPTthuxC0jrfxpYMZ3LdGDD3vTnLs59m2Z7r6+LNDR3ToqEQdkKd6YaaEfJhodJmijQ==", - "dev": true, - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "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/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "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/mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", - "dev": true, - "dependencies": { - "mime-db": "1.50.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/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "node_modules/minimisted": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", - "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", - "dependencies": { - "minimist": "^1.2.5" - } - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "node_modules/mocked-env": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/mocked-env/-/mocked-env-1.3.5.tgz", - "integrity": "sha512-GyYY6ynVOdEoRlaGpaq8UYwdWkvrsU2xRme9B+WPSuJcNjh17+3QIxSYU6zwee0SbehhV6f06VZ4ahjG+9zdrA==", - "dev": true, - "dependencies": { - "check-more-types": "2.24.0", - "debug": "4.3.2", - "lazy-ass": "1.6.0", - "ramda": "0.27.1" - }, - "engines": { - "node": ">=6" - } - }, - "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==" - }, - "node_modules/multiformats": { - "version": "9.4.9", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.4.9.tgz", - "integrity": "sha512-zA84TTJcRfRMpjvYqy63piBbSEdqlIGqNNSpP6kspqtougqjo60PRhIFo+oAxrjkof14WMCImvr7acK6rPpXLw==" - }, - "node_modules/multistream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", - "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", - "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" - } - ], - "dependencies": { - "once": "^1.4.0", - "readable-stream": "^3.6.0" - } - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true - }, - "node_modules/napi-macros": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" - }, - "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/nexpect": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/nexpect/-/nexpect-0.6.0.tgz", - "integrity": "sha512-gG4cO0zoNG+kaPesw516hPVEKLW3YizGU8UWMr5lpkHKOgoTWcu4sPQN7rWVAIL4Ck87zM4N8immPUhYPdDz3g==", - "dev": true, - "dependencies": { - "cross-spawn": "^6.0.5" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nexpect/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/nexpect/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/nexpect/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/nexpect/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nexpect/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nexpect/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/node-abi": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", - "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "dev": true, - "dependencies": { - "semver": "^5.4.1" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "engines": { - "node": "4.x || >=6.0.0" - } - }, - "node_modules/node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/node-gyp-build": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", - "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "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/node-notifier": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-10.0.1.tgz", - "integrity": "sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.5", - "shellwords": "^0.1.1", - "uuid": "^8.3.2", - "which": "^2.0.2" - } - }, - "node_modules/node-notifier/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-releases": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", - "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "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": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/observable-fns": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/observable-fns/-/observable-fns-0.6.1.tgz", - "integrity": "sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==" - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "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/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-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-is-promise": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", - "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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/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/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/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "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/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "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/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "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/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "engines": { - "node": ">=6" - } - }, - "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": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.6.0.tgz", - "integrity": "sha512-mHrAVSQWmHA41RnUmRpC7pK9lNnMfdA16CF3cqOI22a8LZxOQzF7M8YWtA2nfs+d7I0MTDXOtkDsAsFXeCpYjg==", - "dev": true, - "dependencies": { - "@babel/parser": "7.16.2", - "@babel/types": "7.16.0", - "chalk": "^4.1.2", - "escodegen": "^2.0.0", - "fs-extra": "^9.1.0", - "globby": "^11.0.4", - "into-stream": "^6.0.0", - "minimist": "^1.2.5", - "multistream": "^4.1.0", - "pkg-fetch": "3.3.0", - "prebuild-install": "6.1.4", - "progress": "^2.0.3", - "resolve": "^1.20.0", - "stream-meter": "^1.0.4", - "tslib": "2.3.1" - }, - "bin": { - "pkg": "lib-es5/bin.js" - }, - "peerDependencies": { - "node-notifier": ">=9.0.1" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "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/pkg-fetch": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.3.0.tgz", - "integrity": "sha512-xJnIZ1KP+8rNN+VLafwu4tEeV4m8IkFBDdCFqmAJz9K1aiXEtbARmdbEe6HlXWGSVuShSHjFXpfkKRkDBQ5kiA==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "fs-extra": "^9.1.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.6", - "progress": "^2.0.3", - "semver": "^7.3.5", - "tar-fs": "^2.1.1", - "yargs": "^16.2.0" - }, - "bin": { - "pkg-fetch": "lib-es5/bin.js" - } - }, - "node_modules/pkg-fetch/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/pkg-fetch/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/pkg-fetch/node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/pkg-fetch/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pkg-fetch/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/pkg-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "dev": true - }, - "node_modules/pkg-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "dev": true - }, - "node_modules/pkg-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/pkg/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/pkg/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/pkg/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/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prebuild-install": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", - "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", - "dev": true, - "dependencies": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.21.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=6" - } - }, - "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/prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.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/printj": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", - "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==", - "bin": { - "printj": "bin/printj.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "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.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "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=" - }, - "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/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "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==", - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "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/ramda": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", - "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", - "dev": true - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reachdown": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reachdown/-/reachdown-1.1.0.tgz", - "integrity": "sha512-6LsdRe4cZyOjw4NnvbhUd/rGG7WQ9HMopPr+kyL018Uci4kijtxcGR5kVb5Ln13k4PEE+fEFQbjfOvNw7cnXmA==", - "engines": { - "node": ">=6" - } - }, - "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/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/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/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/regexpu-core": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", - "dev": true - }, - "node_modules/regjsparser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "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/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "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/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-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-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", - "dev": true - }, - "node_modules/resource-counter": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/resource-counter/-/resource-counter-1.2.4.tgz", - "integrity": "sha512-DGJChvE5r4smqPE+xYNv9r1u/I9cCfRR5yfm7D6EQckdKqMyVpJ5z0s40yn0EM0puFxHg6mPORrQLQdEbJ/RnQ==", - "dependencies": { - "babel-runtime": "^6.26.0", - "bitset": "^5.0.3" - }, - "engines": { - "node": ">=6.4.0" - } - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "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/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true, - "engines": { - "node": "6.* || >= 7.*" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "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" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/run-parallel-limit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", - "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "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==", - "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/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, - "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/sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "deprecated": "some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added", - "dev": true, - "dependencies": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "bin": { - "sane": "src/cli.js" - }, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/sane/node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/sane/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/sane/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/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/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "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==", - "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==", - "engines": { - "node": ">=8" - } - }, - "node_modules/shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true - }, - "node_modules/shiki": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", - "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", - "dev": true, - "dependencies": { - "jsonc-parser": "^3.0.0", - "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "5.2.0" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", - "dev": true - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "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/simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "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": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "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/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/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-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated", - "dev": true - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", - "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==", - "dev": true - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.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.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "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/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stream-meter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", - "integrity": "sha1-Uq+Vql6nYKJJFxZwTb/5D3Ov3R0=", - "dev": true, - "dependencies": { - "readable-stream": "^2.1.4" - } - }, - "node_modules/stream-meter/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/stream-meter/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/stream-meter/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/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "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": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "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-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/sublevel-prefixer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sublevel-prefixer/-/sublevel-prefixer-1.0.0.tgz", - "integrity": "sha1-TuRZ72Y6yFvyj8ZJ17eWX9ppEHM=" - }, - "node_modules/subleveldown": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/subleveldown/-/subleveldown-6.0.1.tgz", - "integrity": "sha512-Cnf+cn2wISXU2xflY1SFIqfX4hG2d6lFk2P5F8RDQLmiqN9Ir4ExNfUFH6xnmizMseM/t+nMsDUKjN9Kw6ShFA==", - "dependencies": { - "abstract-leveldown": "^7.2.0", - "encoding-down": "^7.1.0", - "inherits": "^2.0.3", - "level-option-wrap": "^1.1.0", - "levelup": "^5.1.1", - "reachdown": "^1.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "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": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "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/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/threads": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/threads/-/threads-1.7.0.tgz", - "integrity": "sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ==", - "dependencies": { - "callsites": "^3.1.0", - "debug": "^4.2.0", - "is-observable": "^2.1.0", - "observable-fns": "^0.6.1" - }, - "funding": { - "url": "https://github.com/andywer/threads.js?sponsor=1" - }, - "optionalDependencies": { - "tiny-worker": ">= 2" - } - }, - "node_modules/throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "dev": true - }, - "node_modules/timeout-refresh": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-1.0.3.tgz", - "integrity": "sha512-Mz0CX4vBGM5lj8ttbIFt7o4ZMxk/9rgudJRh76EvB7xXZMur7T/cjRiH2w4Fmkq0zxf2QpM8IFvOSRn8FEu3gA==" - }, - "node_modules/tiny-inflate": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" - }, - "node_modules/tiny-worker": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tiny-worker/-/tiny-worker-2.3.0.tgz", - "integrity": "sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==", - "optional": true, - "dependencies": { - "esm": "^3.2.25" - } - }, - "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-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/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-custom-error": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.2.0.tgz", - "integrity": "sha512-cBvC2QjtvJ9JfWLvstVnI45Y46Y5dMxIaG1TDMGAD/R87hpvqFL+7LhvUDhnRCfOnx/xitollFWWvUKKKhbN0A==", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/ts-jest": { - "version": "26.5.6", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz", - "integrity": "sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "buffer-from": "1.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^26.1.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" - }, - "peerDependencies": { - "jest": ">=26 <27", - "typescript": ">=3.8 <5.0" - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-node": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", - "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "0.7.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ts-node/node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", - "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/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/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "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.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/typedoc": { - "version": "0.22.15", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.15.tgz", - "integrity": "sha512-CMd1lrqQbFvbx6S9G6fL4HKp3GoIuhujJReWqlIvSb2T26vGai+8Os3Mde7Pn832pXYemd9BMuuYWhFpL5st0Q==", - "dev": true, - "dependencies": { - "glob": "^7.2.0", - "lunr": "^2.3.9", - "marked": "^4.0.12", - "minimatch": "^5.0.1", - "shiki": "^0.10.1" - }, - "bin": { - "typedoc": "bin/typedoc" - }, - "engines": { - "node": ">= 12.10.0" - }, - "peerDependencies": { - "typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x" - } - }, - "node_modules/typedoc/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typedoc/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/typescript": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", - "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/typescript-cached-transpile": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typescript-cached-transpile/-/typescript-cached-transpile-0.0.6.tgz", - "integrity": "sha512-bfPc7YUW0PrVkQHU0xN0ANRuxdPgoYYXtZEW6PNkH5a97/AOM+kPPxSTMZbpWA3BG1do22JUkfC60KoCKJ9VZQ==", - "dev": true, - "dependencies": { - "@types/node": "^12.12.7", - "fs-extra": "^8.1.0", - "tslib": "^1.10.0" - }, - "peerDependencies": { - "typescript": "*" - } - }, - "node_modules/typescript-cached-transpile/node_modules/@types/node": { - "version": "12.20.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.37.tgz", - "integrity": "sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA==", - "dev": true - }, - "node_modules/typescript-cached-transpile/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/typescript-cached-transpile/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/typescript-cached-transpile/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/uglify-js": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz", - "integrity": "sha512-rtPMlmcO4agTUfz10CbgJ1k6UAoXM2gWb3GoMPPZB/+/Ackf8lNWk11K4rYi2D0apgoFRLtQOZhb+/iGNJq26A==", - "dev": true, - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-trie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "node_modules/unicode-trie/node_modules/pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.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/unordered-set": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", - "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==" - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "dev": true - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/util-callbackify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util-callbackify/-/util-callbackify-1.0.0.tgz", - "integrity": "sha512-5vEPPSM6DCHlCpq9FZryeIkY5FQMUqXLUz4yHtU369Z/abWUVdgInPVeINjWJV3Bk9DZhCr+JzGarEByPLsxBQ==", - "dependencies": { - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/utp-native": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/utp-native/-/utp-native-2.5.3.tgz", - "integrity": "sha512-sWTrWYXPhhWJh+cS2baPzhaZc89zwlWCfwSthUjGhLkZztyPhcQllo+XVVCbNGi7dhyRlxkWxN4NKU6FbA9Y8w==", - "hasInstallScript": true, - "dependencies": { - "napi-macros": "^2.0.0", - "node-gyp-build": "^4.2.0", - "readable-stream": "^3.0.2", - "timeout-refresh": "^1.0.0", - "unordered-set": "^2.0.1" - }, - "bin": { - "ucat": "ucat.js" - }, - "engines": { - "node": ">=8.12" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", - "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">=10.10.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/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vscode-oniguruma": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", - "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", - "dev": true - }, - "node_modules/vscode-textmate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", - "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", - "dev": true - }, - "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/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/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-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.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "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==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "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/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, - "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/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "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.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", - "dev": true, - "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/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - } - }, "dependencies": { "@babel/code-frame": { "version": "7.15.8", @@ -14684,8 +2101,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-walk": { "version": "7.2.0", @@ -16301,8 +3717,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-node": { "version": "0.3.6", @@ -18436,22 +5851,19 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/jest-mock-process/-/jest-mock-process-1.4.1.tgz", "integrity": "sha512-ZZUKRlEBizutngoO4KngzN30YoeAYP3nnwimk4cpi9WqLxQUf6SlAPK5p1D9usEpxDS3Uif2MIez3Bq0vGYR+g==", - "dev": true, - "requires": {} + "dev": true }, "jest-mock-props": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/jest-mock-props/-/jest-mock-props-1.9.0.tgz", "integrity": "sha512-8IlIiZRvovnRuvqcvWZyDv4CyhrUGTbEW/1eKurHr2JY4VhIWQIPlbpt9lqL2nxdGnco+OcgpPBwGYCEeDb2+A==", - "dev": true, - "requires": {} + "dev": true }, "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, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "26.0.0", @@ -19582,35 +6994,6 @@ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", "dev": true }, - "node-notifier": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-10.0.1.tgz", - "integrity": "sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.5", - "shellwords": "^0.1.1", - "uuid": "^8.3.2", - "which": "^2.0.2" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, "node-releases": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", @@ -21149,14 +8532,6 @@ } } }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -21196,6 +8571,14 @@ "define-properties": "^1.1.3" } }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -22087,8 +9470,7 @@ "version": "7.5.5", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", - "dev": true, - "requires": {} + "dev": true }, "xml-name-validator": { "version": "3.0.0", diff --git a/src/vaults/VaultInternal.ts b/src/vaults/VaultInternal.ts index 34597b034..ae2adf6cf 100644 --- a/src/vaults/VaultInternal.ts +++ b/src/vaults/VaultInternal.ts @@ -1,7 +1,6 @@ import type { ReadCommitResult } from 'isomorphic-git'; import type { EncryptedFS } from 'encryptedfs'; -import type { DB, DBDomain, DBLevel } from '@matrixai/db'; -import type { ResourceAcquire } from '@matrixai/resources'; +import type { DB, DBTransaction, LevelPath } from '@matrixai/db'; import type { CommitId, CommitLog, @@ -51,35 +50,50 @@ class VaultInternal { vaultId, vaultName, db, - vaultsDb, - vaultsDbDomain, + vaultsDbPath, keyManager, efs, logger = new Logger(this.name), fresh = false, + tran, }: { vaultId: VaultId; vaultName?: VaultName; db: DB; - vaultsDb: DBLevel; - vaultsDbDomain: DBDomain; + vaultsDbPath: LevelPath; keyManager: KeyManager; efs: EncryptedFS; logger?: Logger; fresh?: boolean; + tran?: DBTransaction; }): Promise { + if (tran == null) { + return await db.withTransactionF(async (tran) => + this.createVaultInternal({ + vaultId, + vaultName, + db, + vaultsDbPath, + keyManager, + efs, + logger, + fresh, + tran, + }), + ); + } + const vaultIdEncoded = vaultsUtils.encodeVaultId(vaultId); logger.info(`Creating ${this.name} - ${vaultIdEncoded}`); const vault = new VaultInternal({ vaultId, db, - vaultsDb, - vaultsDbDomain, + vaultsDbPath, keyManager, efs, logger, }); - await vault.start({ fresh, vaultName }); + await vault.start({ fresh, vaultName, tran }); logger.info(`Created ${this.name} - ${vaultIdEncoded}`); return vault; } @@ -89,31 +103,47 @@ class VaultInternal { targetVaultNameOrId, vaultId, db, - vaultsDb, - vaultsDbDomain, + vaultsDbPath, keyManager, nodeConnectionManager, efs, logger = new Logger(this.name), + tran, }: { targetNodeId: NodeId; targetVaultNameOrId: VaultId | VaultName; vaultId: VaultId; db: DB; - vaultsDb: DBLevel; - vaultsDbDomain: DBDomain; + vaultsDbPath: LevelPath; efs: EncryptedFS; keyManager: KeyManager; nodeConnectionManager: NodeConnectionManager; logger?: Logger; + tran?: DBTransaction; }): Promise { + if (tran == null) { + return await db.withTransactionF(async (tran) => + this.cloneVaultInternal({ + targetNodeId, + targetVaultNameOrId, + vaultId, + db, + vaultsDbPath, + keyManager, + nodeConnectionManager, + efs, + logger, + tran, + }), + ); + } + const vaultIdEncoded = vaultsUtils.encodeVaultId(vaultId); logger.info(`Cloning ${this.name} - ${vaultIdEncoded}`); const vault = new VaultInternal({ vaultId, db, - vaultsDb, - vaultsDbDomain, + vaultsDbPath, keyManager, efs, logger, @@ -160,11 +190,10 @@ class VaultInternal { throw e; } - await vault.start({ vaultName }); + await vault.start({ vaultName, tran }); // Setting the remote in the metadata - await vault.db.put( - vault.vaultMetadataDbDomain, - VaultInternal.remoteKey, + await tran.put( + [...vault.vaultMetadataDbPath, VaultInternal.remoteKey], remote, ); logger.info(`Cloned ${this.name} - ${vaultIdEncoded}`); @@ -182,39 +211,29 @@ class VaultInternal { protected logger: Logger; protected db: DB; - protected vaultsDbDomain: DBDomain; - protected vaultsDb: DBLevel; - protected vaultMetadataDbDomain: DBDomain; - protected vaultMetadataDb: DBLevel; + protected vaultsDbPath: LevelPath; + protected vaultMetadataDbPath: LevelPath; protected keyManager: KeyManager; - protected vaultsNamesDomain: DBDomain; + protected vaultsNamesPath: LevelPath; protected efs: EncryptedFS; protected efsVault: EncryptedFS; protected lock: RWLockWriter = new RWLockWriter(); - public readLock: ResourceAcquire = async () => { - const release = await this.lock.acquireRead(); - return [async () => release()]; - }; - - public writeLock: ResourceAcquire = async () => { - const release = await this.lock.acquireWrite(); - return [async () => release()]; - }; + public getLock(): RWLockWriter { + return this.lock; + } constructor({ vaultId, db, - vaultsDbDomain, - vaultsDb, + vaultsDbPath, keyManager, efs, logger, }: { vaultId: VaultId; db: DB; - vaultsDbDomain: DBDomain; - vaultsDb: DBLevel; + vaultsDbPath: LevelPath; keyManager: KeyManager; efs: EncryptedFS; logger: Logger; @@ -226,8 +245,7 @@ class VaultInternal { this.vaultDataDir = path.join(vaultIdEncoded, 'data'); this.vaultGitDir = path.join(vaultIdEncoded, '.git'); this.db = db; - this.vaultsDbDomain = vaultsDbDomain; - this.vaultsDb = vaultsDb; + this.vaultsDbPath = vaultsDbPath; this.keyManager = keyManager; this.efs = efs; } @@ -236,27 +254,38 @@ class VaultInternal { * * @param fresh Clears all state before starting * @param vaultName Name of the vault, Only used when creating a new vault + * @param tran */ public async start({ fresh = false, vaultName, + tran, }: { fresh?: boolean; vaultName?: VaultName; + tran?: DBTransaction; } = {}): Promise { + if (tran == null) { + return await this.db.withTransactionF(async (tran) => + this.start_(fresh, tran, vaultName), + ); + } + return await this.start_(fresh, tran, vaultName); + } + + protected async start_( + fresh: boolean, + tran: DBTransaction, + vaultName?: VaultName, + ) { this.logger.info( `Starting ${this.constructor.name} - ${this.vaultIdEncoded}`, ); - this.vaultMetadataDbDomain = [...this.vaultsDbDomain, this.vaultIdEncoded]; - this.vaultsNamesDomain = [...this.vaultsDbDomain, 'names']; - this.vaultMetadataDb = await this.db.level( - this.vaultIdEncoded, - this.vaultsDb, - ); + this.vaultMetadataDbPath = [...this.vaultsDbPath, this.vaultIdEncoded]; + this.vaultsNamesPath = [...this.vaultsDbPath, 'names']; // Let's backup any metadata - if (fresh) { - await this.vaultMetadataDb.clear(); + await tran.clear(this.vaultMetadataDbPath); try { await this.efs.rmdir(this.vaultIdEncoded, { recursive: true, @@ -270,15 +299,15 @@ class VaultInternal { await this.mkdirExists(this.vaultIdEncoded); await this.mkdirExists(this.vaultDataDir); await this.mkdirExists(this.vaultGitDir); - await this.setupMeta({ vaultName }); - await this.setupGit(); + await this.setupMeta({ vaultName, tran }); + await this.setupGit(tran); this.efsVault = await this.efs.chroot(this.vaultDataDir); this.logger.info( `Started ${this.constructor.name} - ${this.vaultIdEncoded}`, ); } - private async mkdirExists(directory: string) { + protected async mkdirExists(directory: string) { try { await this.efs.mkdir(directory, { recursive: true }); } catch (e) { @@ -297,12 +326,20 @@ class VaultInternal { ); } - public async destroy(): Promise { + public async destroy(tran?: DBTransaction): Promise { + if (tran == null) { + return await this.db.withTransactionF(async (tran) => + this.destroy_(tran), + ); + } + return await this.destroy_(tran); + } + + protected async destroy_(tran: DBTransaction) { this.logger.info( `Destroying ${this.constructor.name} - ${this.vaultIdEncoded}`, ); - const vaultDb = await this.db.level(this.vaultIdEncoded, this.vaultsDb); - await vaultDb.clear(); + await tran.clear(this.vaultMetadataDbPath); try { await this.efs.rmdir(this.vaultIdEncoded, { recursive: true, @@ -386,7 +423,7 @@ class VaultInternal { @ready(new vaultsErrors.ErrorVaultNotRunning()) public async readF(f: (fs: FileSystemReadable) => Promise): Promise { - return withF([this.readLock], async () => { + return withF([this.lock.read()], async () => { return await f(this.efsVault); }); } @@ -396,7 +433,7 @@ class VaultInternal { g: (fs: FileSystemReadable) => AsyncGenerator, ): AsyncGenerator { const efsVault = this.efsVault; - return withG([this.readLock], async function* () { + return withG([this.lock.read()], async function* () { return yield* g(efsVault); }); } @@ -404,24 +441,28 @@ class VaultInternal { @ready(new vaultsErrors.ErrorVaultNotRunning()) public async writeF( f: (fs: FileSystemWritable) => Promise, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => this.writeF(f, tran)); + } + // This should really be an internal property // get whether this is remote, and the remote address // if it is, we consider this repo an "attached repo" // this vault is a "mirrored" vault if ( - (await this.db.get( - this.vaultMetadataDbDomain, + (await tran.get([ + ...this.vaultMetadataDbPath, VaultInternal.remoteKey, - )) != null + ])) != null ) { // Mirrored vaults are immutable throw new vaultsErrors.ErrorVaultRemoteDefined(); } - return withF([this.writeLock], async () => { - await this.db.put( - this.vaultMetadataDbDomain, - VaultInternal.dirtyKey, + return withF([this.lock.write()], async () => { + await tran.put( + [...this.vaultMetadataDbPath, VaultInternal.dirtyKey], true, ); try { @@ -433,9 +474,8 @@ class VaultInternal { await this.cleanWorkingDirectory(); throw e; } - await this.db.put( - this.vaultMetadataDbDomain, - VaultInternal.dirtyKey, + await tran.put( + [...this.vaultMetadataDbPath, VaultInternal.dirtyKey], false, ); }); @@ -444,18 +484,25 @@ class VaultInternal { @ready(new vaultsErrors.ErrorVaultNotRunning()) public writeG( g: (fs: FileSystemWritable) => AsyncGenerator, + tran?: DBTransaction, ): AsyncGenerator { + if (tran == null) { + return this.db.withTransactionG((tran) => this.writeG(g, tran)); + } + const efsVault = this.efsVault; - const db = this.db; - const vaultDbDomain = this.vaultMetadataDbDomain; + const vaultMetadataDbPath = this.vaultMetadataDbPath; const createCommit = () => this.createCommit(); const cleanWorkingDirectory = () => this.cleanWorkingDirectory(); - return withG([this.writeLock], async function* () { - if ((await db.get(vaultDbDomain, VaultInternal.remoteKey)) != null) { + return withG([this.lock.write()], async function* () { + if ( + (await tran.get([...vaultMetadataDbPath, VaultInternal.remoteKey])) != + null + ) { // Mirrored vaults are immutable throw new vaultsErrors.ErrorVaultRemoteDefined(); } - await db.put(vaultDbDomain, VaultInternal.dirtyKey, true); + await tran.put([...vaultMetadataDbPath, VaultInternal.dirtyKey], true); let result; // Do what you need to do here, create the commit @@ -472,7 +519,7 @@ class VaultInternal { await cleanWorkingDirectory(); throw e; } - await db.put(vaultDbDomain, VaultInternal.dirtyKey, false); + await tran.put([...vaultMetadataDbPath, VaultInternal.dirtyKey], false); return result; }); } @@ -482,20 +529,33 @@ class VaultInternal { nodeConnectionManager, pullNodeId, pullVaultNameOrId, + tran, }: { nodeConnectionManager: NodeConnectionManager; pullNodeId?: NodeId; pullVaultNameOrId?: VaultId | VaultName; - }) { + tran?: DBTransaction; + }): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.pullVault({ + nodeConnectionManager, + pullNodeId, + pullVaultNameOrId, + tran, + }), + ); + } + // This error flag will contain the error returned by the cloning grpc stream let error; // Keeps track of whether the metadata needs changing to avoid unnecessary db ops // 0 = no change, 1 = change with vault Id, 2 = change with vault name let metaChange = 0; - const remoteInfo = await this.db.get( - this.vaultMetadataDbDomain, + const remoteInfo = await tran.get([ + ...this.vaultMetadataDbPath, VaultInternal.remoteKey, - ); + ]); if (remoteInfo == null) throw new vaultsErrors.ErrorVaultRemoteUndefined(); if (pullNodeId == null) { @@ -530,7 +590,7 @@ class VaultInternal { pullVaultNameOrId!, 'pull', ); - await withF([this.writeLock], async () => { + await withF([this.lock.write()], async () => { await git.pull({ fs: this.efs, http: { request }, @@ -563,9 +623,8 @@ class VaultInternal { if (metaChange === 2) { remoteInfo.remoteVault = vaultsUtils.encodeVaultId(remoteVaultId); } - await this.db.put( - this.vaultMetadataDbDomain, - VaultInternal.remoteKey, + await tran.put( + [...this.vaultMetadataDbPath, VaultInternal.remoteKey], remoteInfo, ); } @@ -581,8 +640,10 @@ class VaultInternal { */ protected async setupMeta({ vaultName, + tran, }: { vaultName?: VaultName; + tran: DBTransaction; }): Promise { // Setup the vault metadata // and you need to make certain preparations @@ -593,29 +654,27 @@ class VaultInternal { // If this is not existing // setup default vaults db if ( - (await this.db.get( - this.vaultMetadataDbDomain, + (await tran.get([ + ...this.vaultMetadataDbPath, VaultInternal.dirtyKey, - )) == null + ])) == null ) { - await this.db.put( - this.vaultMetadataDbDomain, - VaultInternal.dirtyKey, + await tran.put( + [...this.vaultMetadataDbPath, VaultInternal.dirtyKey], false, ); } // Set up vault Name if ( - (await this.db.get( - this.vaultMetadataDbDomain, + (await tran.get([ + ...this.vaultMetadataDbPath, VaultInternal.nameKey, - )) == null && + ])) == null && vaultName != null ) { - await this.db.put( - this.vaultMetadataDbDomain, - VaultInternal.nameKey, + await tran.put( + [...this.vaultMetadataDbPath, VaultInternal.nameKey], vaultName, ); } @@ -625,7 +684,7 @@ class VaultInternal { // name: string | undefined } - protected async setupGit(): Promise { + protected async setupGit(tran: DBTransaction): Promise { // Initialization is idempotent // It works even with an existing git repository await git.init({ @@ -673,10 +732,10 @@ class VaultInternal { } else { // Checking for dirty if ( - (await this.db.get( - this.vaultMetadataDbDomain, + (await tran.get([ + ...this.vaultMetadataDbPath, VaultInternal.dirtyKey, - )) === true + ])) === true ) { // Force checkout out to the latest commit // This ensures that any uncommitted state is dropped @@ -685,9 +744,8 @@ class VaultInternal { await this.garbageCollectGitObjects(); // Setting dirty back to false - await this.db.put( - this.vaultMetadataDbDomain, - VaultInternal.dirtyKey, + await tran.put( + [...this.vaultMetadataDbPath, VaultInternal.dirtyKey], false, ); } diff --git a/src/vaults/VaultManager.ts b/src/vaults/VaultManager.ts index 571b8879d..beb8a525a 100644 --- a/src/vaults/VaultManager.ts +++ b/src/vaults/VaultManager.ts @@ -1,5 +1,5 @@ -import type { DB, DBDomain, DBLevel } from '@matrixai/db'; -import type { ResourceAcquire } from '@matrixai/resources'; +import type { DB, DBTransaction, LevelPath } from '@matrixai/db'; +import type { ResourceAcquire, ResourceRelease } from '@matrixai/resources'; import type { VaultId, VaultName, @@ -58,6 +58,10 @@ type VaultMetadata = { remoteInfo?: RemoteInfo; }; +// TODO: +// - Check all `tran` parameters and evaluate if they need to be optional or not +// - check all uses of gestaltGraph and ACL for passing tran + interface VaultManager extends CreateDestroyStartStop {} @CreateDestroyStartStop( new vaultsErrors.ErrorVaultManagerRunning(), @@ -120,10 +124,8 @@ class VaultManager { protected nodeConnectionManager: NodeConnectionManager; protected gestaltGraph: GestaltGraph; protected notificationsManager: NotificationsManager; - protected vaultsDbDomain: DBDomain = [this.constructor.name]; - protected vaultsDb: DBLevel; - protected vaultsNamesDbDomain: DBDomain = [...this.vaultsDbDomain, 'names']; - protected vaultsNamesDb: DBLevel; + protected vaultsDbPath: LevelPath = [this.constructor.name]; + protected vaultsNamesDbPath: LevelPath = [this.constructor.name, 'names']; protected vaultsNamesLock: RWLockWriter = new RWLockWriter(); // VaultId -> VaultMetadata protected vaultMap: VaultMap = new Map(); @@ -171,53 +173,50 @@ class VaultManager { }: { fresh?: boolean; } = {}): Promise { - try { - this.logger.info(`Starting ${this.constructor.name}`); - const vaultsDb = await this.db.level(this.vaultsDbDomain[0]); - const vaultsNamesDb = await this.db.level( - this.vaultsNamesDbDomain[1], - vaultsDb, - ); - if (fresh) { - await vaultsDb.clear(); - await this.fs.promises.rm(this.vaultsPath, { - force: true, - recursive: true, - }); - } - await mkdirExists(this.fs, this.vaultsPath); - const vaultKey = await this.setupKey(this.keyBits); - let efs; + await this.db.withTransactionF(async (tran) => { try { - efs = await EncryptedFS.createEncryptedFS({ - dbPath: this.efsPath, - dbKey: vaultKey, - logger: this.logger.getChild('EncryptedFileSystem'), - }); - } catch (e) { - if (e instanceof encryptedFsErrors.ErrorEncryptedFSKey) { - throw new vaultsErrors.ErrorVaultManagerKey(e.message, { cause: e }); + this.logger.info(`Starting ${this.constructor.name}`); + if (fresh) { + await tran.clear(this.vaultsDbPath); + await this.fs.promises.rm(this.vaultsPath, { + force: true, + recursive: true, + }); } - throw new vaultsErrors.ErrorVaultManagerEFS(e.message, { - data: { - errno: e.errno, - syscall: e.syscall, - code: e.code, - path: e.path, - }, - cause: e, - }); + await mkdirExists(this.fs, this.vaultsPath); + const vaultKey = await this.setupKey(this.keyBits, tran); + let efs; + try { + efs = await EncryptedFS.createEncryptedFS({ + dbPath: this.efsPath, + dbKey: vaultKey, + logger: this.logger.getChild('EncryptedFileSystem'), + }); + } catch (e) { + if (e instanceof encryptedFsErrors.ErrorEncryptedFSKey) { + throw new vaultsErrors.ErrorVaultManagerKey(e.message, { + cause: e, + }); + } + throw new vaultsErrors.ErrorVaultManagerEFS(e.message, { + data: { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }, + cause: e, + }); + } + this.vaultKey = vaultKey; + this.efs = efs; + this.logger.info(`Started ${this.constructor.name}`); + } catch (e) { + this.logger.warn(`Failed Starting ${this.constructor.name}`); + await this.efs?.stop(); + throw e; } - this.vaultsDb = vaultsDb; - this.vaultsNamesDb = vaultsNamesDb; - this.vaultKey = vaultKey; - this.efs = efs; - this.logger.info(`Started ${this.constructor.name}`); - } catch (e) { - this.logger.warn(`Failed Starting ${this.constructor.name}`); - await this.efs?.stop(); - throw e; - } + }); } public async stop(): Promise { @@ -225,7 +224,6 @@ class VaultManager { // Iterate over vaults in memory and destroy them, ensuring that // the working directory commit state is saved - for (const [vaultIdString, vaultAndLock] of this.vaultMap) { const vaultId = IdInternal.fromString(vaultIdString); await withF([this.getWriteLock(vaultId)], async () => { @@ -242,11 +240,8 @@ class VaultManager { public async destroy(): Promise { this.logger.info(`Destroying ${this.constructor.name}`); await this.efs.destroy(); - // If the DB was stopped, the existing sublevel `this.vaultsDb` will not be valid - // Therefore we recreate the sublevel here - const vaultsDb = await this.db.level(this.vaultsDbDomain[0]); // Clearing all vaults db data - await vaultsDb.clear(); + await this.db.clear(this.vaultsDbPath); // Is it necessary to remove the vaults domain? await this.fs.promises.rm(this.vaultsPath, { force: true, @@ -263,7 +258,8 @@ class VaultManager { this.efs.unsetWorkerManager(); } - protected getLock(vaultId: VaultId): RWLockWriter { + public getLock(vaultId: VaultId): RWLockWriter { + // Console.log(new Error(vaultId.toMultibase('base32hex')).stack); const vaultIdString = vaultId.toString() as VaultIdString; const vaultAndLock = this.vaultMap.get(vaultIdString); if (vaultAndLock != null) return vaultAndLock.lock; @@ -272,20 +268,14 @@ class VaultManager { return lock; } - protected getReadLock(vaultId: VaultId): ResourceAcquire { + protected getReadLock(vaultId: VaultId): ResourceAcquire { const lock = this.getLock(vaultId); - return async () => { - const release = await lock.acquireRead(); - return [async () => release()]; - }; + return lock.read(); } - protected getWriteLock(vaultId: VaultId): ResourceAcquire { + protected getWriteLock(vaultId: VaultId): ResourceAcquire { const lock = this.getLock(vaultId); - return async () => { - const release = await lock.acquireWrite(); - return [async () => release()]; - }; + return lock.write(); } /** @@ -296,45 +286,51 @@ class VaultManager { // this should actually @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) - public async createVault(vaultName: VaultName): Promise { + public async createVault( + vaultName: VaultName, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.createVault(vaultName, tran), + ); + } // Adding vault to name map const vaultId = await this.generateVaultId(); - await this.vaultsNamesLock.withWrite(async () => { - const vaultIdBuffer = await this.db.get( - this.vaultsNamesDbDomain, - vaultName, + return await this.vaultsNamesLock.withWriteF(async () => { + const vaultIdBuffer = await tran.get( + [...this.vaultsNamesDbPath, vaultName], true, ); // Check if the vault name already exists; if (vaultIdBuffer != null) { throw new vaultsErrors.ErrorVaultsVaultDefined(); } - await this.db.put( - this.vaultsNamesDbDomain, - vaultName, + await tran.put( + [...this.vaultsNamesDbPath, vaultName], vaultId.toBuffer(), true, ); - }); - const lock = new RWLockWriter(); - const vaultIdString = vaultId.toString() as VaultIdString; - this.vaultMap.set(vaultIdString, { lock }); - return await withF([this.getWriteLock(vaultId)], async () => { - // Creating vault - const vault = await VaultInternal.createVaultInternal({ - vaultId, - vaultName, - keyManager: this.keyManager, - efs: this.efs, - logger: this.logger.getChild(VaultInternal.name), - db: this.db, - vaultsDb: this.vaultsDb, - vaultsDbDomain: this.vaultsDbDomain, - fresh: true, + const lock = new RWLockWriter(); + const vaultIdString = vaultId.toString() as VaultIdString; + this.vaultMap.set(vaultIdString, { lock }); + return await withF([this.getWriteLock(vaultId)], async () => { + // Creating vault + const vault = await VaultInternal.createVaultInternal({ + vaultId, + vaultName, + keyManager: this.keyManager, + efs: this.efs, + logger: this.logger.getChild(VaultInternal.name), + db: this.db, + vaultsDbPath: this.vaultsDbPath, + fresh: true, + tran, + }); + // Adding vault to object map + this.vaultMap.set(vaultIdString, { lock, vault }); + return vault.vaultId; }); - // Adding vault to object map - this.vaultMap.set(vaultIdString, { lock, vault }); - return vault.vaultId; }); } @@ -345,26 +341,32 @@ class VaultManager { @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) public async getVaultMeta( vaultId: VaultId, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.getVaultMeta(vaultId, tran), + ); + } + // First check if the metadata exists const vaultIdEncoded = vaultsUtils.encodeVaultId(vaultId); - const vaultDbDomain = [...this.vaultsDbDomain, vaultIdEncoded]; - const vaultDb = await this.db.level(vaultIdEncoded, this.vaultsDb); + const vaultDbPath: LevelPath = [...this.vaultsDbPath, vaultIdEncoded]; // Return if metadata has no data - if ((await this.db.count(vaultDb)) === 0) return; + if ((await tran.count(vaultDbPath)) === 0) return; // Obtain the metadata; - const dirty = (await this.db.get( - vaultDbDomain, + const dirty = (await tran.get([ + ...vaultDbPath, VaultInternal.dirtyKey, - ))!; - const vaultName = (await this.db.get( - vaultDbDomain, + ]))!; + const vaultName = (await tran.get([ + ...vaultDbPath, VaultInternal.nameKey, - ))!; - const remoteInfo = await this.db.get( - vaultDbDomain, + ]))!; + const remoteInfo = await tran.get([ + ...vaultDbPath, VaultInternal.remoteKey, - ); + ]); return { dirty, vaultName, @@ -377,22 +379,31 @@ class VaultManager { * given vault Id */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) - public async destroyVault(vaultId: VaultId) { - const vaultMeta = await this.getVaultMeta(vaultId); + public async destroyVault( + vaultId: VaultId, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.destroyVault(vaultId, tran), + ); + } + + const vaultMeta = await this.getVaultMeta(vaultId, tran); if (vaultMeta == null) return; const vaultName = vaultMeta.vaultName; this.logger.info(`Destroying Vault ${vaultsUtils.encodeVaultId(vaultId)}`); const vaultIdString = vaultId.toString() as VaultIdString; await withF([this.getWriteLock(vaultId)], async () => { - const vault = await this.getVault(vaultId); + const vault = await this.getVault(vaultId, tran); // Destroying vault state and metadata await vault.stop(); - await vault.destroy(); + await vault.destroy(tran); // Removing from map this.vaultMap.delete(vaultIdString); // Removing name->id mapping - await this.vaultsNamesLock.withWrite(async () => { - await this.db.del(this.vaultsNamesDbDomain, vaultName); + await this.vaultsNamesLock.withWriteF(async () => { + await tran.del([...this.vaultsNamesDbPath, vaultName]); }); }); this.logger.info(`Destroyed Vault ${vaultsUtils.encodeVaultId(vaultId)}`); @@ -402,13 +413,22 @@ class VaultManager { * Removes vault from the vault map */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) - public async closeVault(vaultId: VaultId) { - if ((await this.getVaultName(vaultId)) == null) { + public async closeVault( + vaultId: VaultId, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.closeVault(vaultId, tran), + ); + } + + if ((await this.getVaultName(vaultId, tran)) == null) { throw new vaultsErrors.ErrorVaultsVaultUndefined(); } const vaultIdString = vaultId.toString() as VaultIdString; await withF([this.getWriteLock(vaultId)], async () => { - const vault = await this.getVault(vaultId); + const vault = await this.getVault(vaultId, tran); await vault.stop(); this.vaultMap.delete(vaultIdString); }); @@ -419,12 +439,19 @@ class VaultManager { * the vaults stored */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) - public async listVaults(): Promise { + public async listVaults(tran?: DBTransaction): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => this.listVaults(tran)); + } + const vaults: VaultList = new Map(); // Stream of vaultName VaultId key value pairs - for await (const vaultNameBuffer of this.vaultsNamesDb.createKeyStream()) { + for await (const [vaultNameBuffer, vaultIdBuffer] of tran.iterator( + undefined, + this.vaultsNamesDbPath, + )) { const vaultName = vaultNameBuffer.toString() as VaultName; - const vaultId = (await this.getVaultId(vaultName))!; + const vaultId = IdInternal.fromBuffer(vaultIdBuffer); vaults.set(vaultName, vaultId); } return vaults; @@ -437,31 +464,37 @@ class VaultManager { public async renameVault( vaultId: VaultId, newVaultName: VaultName, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.renameVault(vaultId, newVaultName, tran), + ); + } + await withF([this.getWriteLock(vaultId)], async () => { this.logger.info(`Renaming Vault ${vaultsUtils.encodeVaultId(vaultId)}`); // Checking if new name exists - if (await this.getVaultId(newVaultName)) { + if (await this.getVaultId(newVaultName, tran)) { throw new vaultsErrors.ErrorVaultsVaultDefined(); } // Checking if vault exists - const vaultMetadata = await this.getVaultMeta(vaultId); + const vaultMetadata = await this.getVaultMeta(vaultId, tran); if (vaultMetadata == null) { throw new vaultsErrors.ErrorVaultsVaultUndefined(); } const oldVaultName = vaultMetadata.vaultName; // Updating metadata with new name; - const vaultDbDomain = [ - ...this.vaultsDbDomain, + const vaultDbPath = [ + ...this.vaultsDbPath, vaultsUtils.encodeVaultId(vaultId), ]; - await this.db.put(vaultDbDomain, VaultInternal.nameKey, newVaultName); + await tran.put([...vaultDbPath, VaultInternal.nameKey], newVaultName); // Updating name->id map - await this.vaultsNamesLock.withWrite(async () => { - await this.db.del(this.vaultsNamesDbDomain, oldVaultName); - await this.db.put( - this.vaultsNamesDbDomain, - newVaultName, + await this.vaultsNamesLock.withWriteF(async () => { + await tran.del([...this.vaultsNamesDbPath, oldVaultName]); + await tran.put( + [...this.vaultsNamesDbPath, newVaultName], vaultId.toBuffer(), true, ); @@ -473,11 +506,19 @@ class VaultManager { * Retreives the vault Id associated with a vault name */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) - public async getVaultId(vaultName: VaultName): Promise { - return await this.vaultsNamesLock.withWrite(async () => { - const vaultIdBuffer = await this.db.get( - this.vaultsNamesDbDomain, - vaultName, + public async getVaultId( + vaultName: VaultName, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.getVaultId(vaultName, tran), + ); + } + + return await this.vaultsNamesLock.withWriteF(async () => { + const vaultIdBuffer = await tran.get( + [...this.vaultsNamesDbPath, vaultName], true, ); if (vaultIdBuffer == null) return; @@ -489,20 +530,34 @@ class VaultManager { * Retreives the vault name associated with a vault Id */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) - public async getVaultName(vaultId: VaultId): Promise { - const metadata = await this.getVaultMeta(vaultId); + public async getVaultName( + vaultId: VaultId, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.getVaultName(vaultId, tran), + ); + } + const metadata = await this.getVaultMeta(vaultId, tran); return metadata?.vaultName; } /** * Returns a dictionary of VaultActions for each node - * @param vaultId */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) public async getVaultPermission( vaultId: VaultId, + tran?: DBTransaction, ): Promise> { - const rawPermissions = await this.acl.getVaultPerm(vaultId); + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.getVaultPermission(vaultId, tran), + ); + } + + const rawPermissions = await this.acl.getVaultPerm(vaultId, tran); const permissions: Record = {}; // Getting the relevant information for (const nodeId in rawPermissions) { @@ -516,14 +571,24 @@ class VaultManager { * gestalt and send a notification to this gestalt */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) - public async shareVault(vaultId: VaultId, nodeId: NodeId): Promise { - const vaultMeta = await this.getVaultMeta(vaultId); - if (!vaultMeta) throw new vaultsErrors.ErrorVaultsVaultUndefined(); + public async shareVault( + vaultId: VaultId, + nodeId: NodeId, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.shareVault(vaultId, nodeId, tran), + ); + } + + const vaultMeta = await this.getVaultMeta(vaultId, tran); + if (vaultMeta == null) throw new vaultsErrors.ErrorVaultsVaultUndefined(); // Node Id permissions translated to other nodes in // a gestalt by other domains - await this.gestaltGraph.setGestaltActionByNode(nodeId, 'scan'); - await this.acl.setVaultAction(vaultId, nodeId, 'pull'); - await this.acl.setVaultAction(vaultId, nodeId, 'clone'); + await this.gestaltGraph.setGestaltActionByNode(nodeId, 'scan', tran); + await this.acl.setVaultAction(vaultId, nodeId, 'pull', tran); + await this.acl.setVaultAction(vaultId, nodeId, 'clone', tran); await this.notificationsManager.sendNotification(nodeId, { type: 'VaultShare', vaultId: vaultsUtils.encodeVaultId(vaultId), @@ -540,12 +605,22 @@ class VaultManager { * gestalt */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) - public async unshareVault(vaultId: VaultId, nodeId: NodeId): Promise { - const vaultMeta = await this.getVaultMeta(vaultId); + public async unshareVault( + vaultId: VaultId, + nodeId: NodeId, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.unshareVault(vaultId, nodeId, tran), + ); + } + + const vaultMeta = await this.getVaultMeta(vaultId, tran); if (!vaultMeta) throw new vaultsErrors.ErrorVaultsVaultUndefined(); - await this.gestaltGraph.unsetGestaltActionByNode(nodeId, 'scan'); - await this.acl.unsetVaultAction(vaultId, nodeId, 'pull'); - await this.acl.unsetVaultAction(vaultId, nodeId, 'clone'); + await this.gestaltGraph.unsetGestaltActionByNode(nodeId, 'scan', tran); + await this.acl.unsetVaultAction(vaultId, nodeId, 'pull', tran); + await this.acl.unsetVaultAction(vaultId, nodeId, 'clone', tran); } /** @@ -556,7 +631,14 @@ class VaultManager { public async cloneVault( nodeId: NodeId, vaultNameOrId: VaultId | VaultName, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.cloneVault(nodeId, vaultNameOrId, tran), + ); + } + const vaultId = await this.generateVaultId(); const lock = new RWLockWriter(); const vaultIdString = vaultId.toString() as VaultIdString; @@ -571,23 +653,23 @@ class VaultManager { vaultId, db: this.db, nodeConnectionManager: this.nodeConnectionManager, - vaultsDb: this.vaultsDb, - vaultsDbDomain: this.vaultsDbDomain, + vaultsDbPath: this.vaultsDbPath, keyManager: this.keyManager, efs: this.efs, logger: this.logger.getChild(VaultInternal.name), + tran, }); this.vaultMap.set(vaultIdString, { lock, vault }); - const vaultMetadata = (await this.getVaultMeta(vaultId))!; + const vaultMetadata = (await this.getVaultMeta(vaultId, tran))!; const baseVaultName = vaultMetadata.vaultName; // Need to check if the name is taken, 10 attempts let newVaultName = baseVaultName; let attempts = 1; while (true) { - const existingVaultId = await this.db.get( - this.vaultsNamesDbDomain, + const existingVaultId = await tran.get([ + ...this.vaultsNamesDbPath, newVaultName, - ); + ]); if (existingVaultId == null) break; newVaultName = `${baseVaultName}-${attempts}`; if (attempts >= 50) { @@ -598,16 +680,18 @@ class VaultManager { attempts++; } // Set the vaultName -> vaultId mapping - await this.db.put( - this.vaultsNamesDbDomain, - newVaultName, + await tran.put( + [...this.vaultsNamesDbPath, newVaultName], vaultId.toBuffer(), true, ); // Update vault metadata - await this.db.put( - [...this.vaultsDbDomain, vaultsUtils.encodeVaultId(vaultId)], - VaultInternal.nameKey, + await tran.put( + [ + ...this.vaultsDbPath, + vaultsUtils.encodeVaultId(vaultId), + VaultInternal.nameKey, + ], newVaultName, ); this.logger.info( @@ -625,18 +709,27 @@ class VaultManager { vaultId, pullNodeId, pullVaultNameOrId, + tran, }: { vaultId: VaultId; pullNodeId?: NodeId; pullVaultNameOrId?: VaultId | VaultName; + tran?: DBTransaction; }): Promise { - if ((await this.getVaultName(vaultId)) == null) return; + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.pullVault({ vaultId, pullNodeId, pullVaultNameOrId, tran }), + ); + } + + if ((await this.getVaultName(vaultId, tran)) == null) return; await withF([this.getWriteLock(vaultId)], async () => { - const vault = await this.getVault(vaultId); + const vault = await this.getVault(vaultId, tran); await vault.pullVault({ nodeConnectionManager: this.nodeConnectionManager, pullNodeId, pullVaultNameOrId, + tran, }); }); } @@ -646,11 +739,20 @@ class VaultManager { * cloned or pulled from */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) - public async *handleInfoRequest(vaultId: VaultId): AsyncGenerator { + public async *handleInfoRequest( + vaultId: VaultId, + tran?: DBTransaction, + ): AsyncGenerator { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.handleInfoRequest(vaultId, tran), + ); + } + const efs = this.efs; - const vault = await this.getVault(vaultId); + const vault = await this.getVault(vaultId, tran); return yield* withG( - [this.getReadLock(vaultId), vault.readLock], + [this.getReadLock(vaultId), vault.getLock().read()], async function* (): AsyncGenerator { // Adherence to git protocol yield Buffer.from( @@ -679,10 +781,17 @@ class VaultManager { public async handlePackRequest( vaultId: VaultId, body: Buffer, + tran?: DBTransaction, ): Promise<[PassThrough, PassThrough]> { - const vault = await this.getVault(vaultId); + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.handlePackRequest(vaultId, body, tran), + ); + } + + const vault = await this.getVault(vaultId, tran); return await withF( - [this.getReadLock(vaultId), vault.readLock], + [this.getReadLock(vaultId), vault.getLock().read()], async () => { if (body.toString().slice(4, 8) === 'want') { // Parse the request to get the wanted git object @@ -746,14 +855,24 @@ class VaultManager { /** * Returns all the shared vaults for a NodeId. */ - public async *handleScanVaults(nodeId: NodeId): AsyncGenerator<{ + public async *handleScanVaults( + nodeId: NodeId, + tran?: DBTransaction, + ): AsyncGenerator<{ vaultId: VaultId; vaultName: VaultName; vaultPermissions: VaultAction[]; }> { + if (tran == null) { + const fml = (tran) => this.handleScanVaults(nodeId, tran); + return yield* this.db.withTransactionG(async function* (tran) { + return yield* fml(tran); + }); + } + // Checking permission const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); - const permissions = await this.acl.getNodePerm(nodeId); + const permissions = await this.acl.getNodePerm(nodeId, tran); if (permissions == null) { throw new vaultsErrors.ErrorVaultsPermissionDenied( `No permissions found for ${nodeIdEncoded}`, @@ -774,7 +893,7 @@ class VaultManager { vaults[vaultIdString], ) as VaultAction[]; // Getting the vault name - const metadata = await this.getVaultMeta(vaultId); + const metadata = await this.getVaultMeta(vaultId, tran); const vaultName = metadata!.vaultName; const element = { vaultId, @@ -802,7 +921,16 @@ class VaultManager { } @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) - protected async getVault(vaultId: VaultId): Promise { + protected async getVault( + vaultId: VaultId, + tran: DBTransaction, + ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.getVault(vaultId, tran), + ); + } + let vault: VaultInternal | undefined; let lock: RWLockWriter; const vaultIdString = vaultId.toString() as VaultIdString; @@ -814,15 +942,15 @@ class VaultManager { return vault; } // Only lock exists - let release; + let release: ResourceRelease | undefined; try { - release = await lock.acquireWrite(); + [release] = await lock.write()(); ({ vault } = vaultAndLock); if (vault != null) { return vault; } // Only create if the vault state already exists - if ((await this.getVaultMeta(vaultId)) == null) { + if ((await this.getVaultMeta(vaultId, tran)) == null) { throw new vaultsErrors.ErrorVaultsVaultUndefined( `Vault ${vaultsUtils.encodeVaultId(vaultId)} doesn't exist`, ); @@ -833,25 +961,25 @@ class VaultManager { efs: this.efs, logger: this.logger.getChild(VaultInternal.name), db: this.db, - vaultsDb: this.vaultsDb, - vaultsDbDomain: this.vaultsDbDomain, + vaultsDbPath: this.vaultsDbPath, + tran, }); vaultAndLock.vault = vault; this.vaultMap.set(vaultIdString, vaultAndLock); return vault; } finally { - release(); + if (release != null) await release(); } } else { // Neither vault nor lock exists lock = new RWLockWriter(); vaultAndLock = { lock }; this.vaultMap.set(vaultIdString, vaultAndLock); - let release; + let release: ResourceRelease | undefined; try { - release = await lock.acquireWrite(); + [release] = await lock.write()(); // Only create if the vault state already exists - if ((await this.getVaultMeta(vaultId)) == null) { + if ((await this.getVaultMeta(vaultId, tran)) == null) { throw new vaultsErrors.ErrorVaultsVaultUndefined( `Vault ${vaultsUtils.encodeVaultId(vaultId)} doesn't exist`, ); @@ -861,15 +989,15 @@ class VaultManager { keyManager: this.keyManager, efs: this.efs, db: this.db, - vaultsDb: this.vaultsDb, - vaultsDbDomain: this.vaultsDbDomain, + vaultsDbPath: this.vaultsDbPath, logger: this.logger.getChild(VaultInternal.name), + tran, }); vaultAndLock.vault = vault; this.vaultMap.set(vaultIdString, vaultAndLock); return vault; } finally { - release(); + if (release != null) await release(); } } } @@ -880,12 +1008,20 @@ class VaultManager { * Takes a function and runs it with the listed vaults. locking is handled automatically * @param vaultIds List of vault ID for vaults you wish to use * @param f Function you wish to run with the provided vaults + * @param tran */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) public async withVaults( vaultIds: VaultId[], f: (...args: Vault[]) => Promise, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.withVaults(vaultIds, f, tran), + ); + } + // Stages: // 1. Obtain vaults // 2. Call function with vaults while locking the vaults @@ -894,7 +1030,7 @@ class VaultManager { const vaults = await Promise.all( vaultIds.map(async (vaultId) => { - return await this.getVault(vaultId); + return await this.getVault(vaultId, tran); }), ); @@ -909,9 +1045,12 @@ class VaultManager { }); } - protected async setupKey(bits: 128 | 192 | 256): Promise { + protected async setupKey( + bits: 128 | 192 | 256, + tran: DBTransaction, + ): Promise { let key: Buffer | undefined; - key = await this.db.get(this.vaultsDbDomain, 'key', true); + key = await tran.get([...this.vaultsDbPath, 'key'], true); // If the EFS already exists, but the key doesn't, then we have lost the key if (key == null && (await this.existsEFS())) { throw new vaultsErrors.ErrorVaultManagerKey(); @@ -921,7 +1060,7 @@ class VaultManager { } this.logger.info('Generating vaults key'); key = await this.generateKey(bits); - await this.db.put(this.vaultsDbDomain, 'key', key, true); + await tran.put([...this.vaultsDbPath, 'key'], key, true); return key; } diff --git a/tests/vaults/VaultInternal.test.ts b/tests/vaults/VaultInternal.test.ts index 34f03d70c..86c283baf 100644 --- a/tests/vaults/VaultInternal.test.ts +++ b/tests/vaults/VaultInternal.test.ts @@ -1,7 +1,7 @@ import type { VaultId } from '@/vaults/types'; import type { Vault } from '@/vaults/Vault'; import type KeyManager from '@/keys/KeyManager'; -import type { DBDomain, DBLevel } from '@matrixai/db'; +import type { LevelPath } from '@matrixai/db'; import os from 'os'; import path from 'path'; import fs from 'fs'; @@ -35,8 +35,7 @@ describe('VaultInternal', () => { let efs: EncryptedFS; let db: DB; - let vaultsDb: DBLevel; - let vaultsDbDomain: DBDomain; + let vaultsDbPath: LevelPath; const fakeKeyManager = { getNodeId: () => { @@ -79,8 +78,7 @@ describe('VaultInternal', () => { fs: fs, logger: logger, }); - vaultsDbDomain = ['vaults']; - vaultsDb = await db.level(vaultsDbDomain[0]); + vaultsDbPath = ['vaults']; vaultId = vaultsUtils.generateVaultId(); vault = await VaultInternal.createVaultInternal({ @@ -90,8 +88,7 @@ describe('VaultInternal', () => { logger, fresh: true, db, - vaultsDb, - vaultsDbDomain, + vaultsDbPath, vaultName: 'testVault', }); }); @@ -152,8 +149,7 @@ describe('VaultInternal', () => { fresh: false, db, vaultName: 'testVault1', - vaultsDb, - vaultsDbDomain, + vaultsDbPath, }); await vault.readF(async (efs) => { expect((await efs.readFile('secret-1')).toString()).toStrictEqual( @@ -494,8 +490,11 @@ describe('VaultInternal', () => { test('cannot commit when the remote field is set', async () => { // Write remote metadata await db.put( - [...vaultsDbDomain, vaultsUtils.encodeVaultId(vaultId)], - VaultInternal.remoteKey, + [ + ...vaultsDbPath, + vaultsUtils.encodeVaultId(vaultId), + VaultInternal.remoteKey, + ], { remoteNode: '', remoteVault: '' }, ); const commit = (await vault.log(undefined, 1))[0]; @@ -510,30 +509,34 @@ describe('VaultInternal', () => { }), ).rejects.toThrow(vaultsErrors.ErrorVaultRemoteDefined); }); - test('cannot checkout old commits after branching commit', async () => { - await vault.writeF(async (efs) => { - await efs.writeFile('test1', 'testdata1'); - }); - const secondCommit = (await vault.log(undefined, 1))[0].commitId; - await vault.writeF(async (efs) => { - await efs.writeFile('test2', 'testdata2'); - }); - const thirdCommit = (await vault.log(undefined, 1))[0].commitId; - await vault.writeF(async (efs) => { - await efs.writeFile('test3', 'testdata3'); - }); - const fourthCommit = (await vault.log(undefined, 1))[0].commitId; - await vault.version(secondCommit); - await vault.writeF(async (efs) => { - await efs.writeFile('test4', 'testdata4'); - }); - await expect(() => { - return vault.version(thirdCommit); - }).rejects.toThrow(); - await expect(() => { - return vault.version(fourthCommit); - }).rejects.toThrow(); - }); + test( + 'cannot checkout old commits after branching commit', + async () => { + await vault.writeF(async (efs) => { + await efs.writeFile('test1', 'testdata1'); + }); + const secondCommit = (await vault.log(undefined, 1))[0].commitId; + await vault.writeF(async (efs) => { + await efs.writeFile('test2', 'testdata2'); + }); + const thirdCommit = (await vault.log(undefined, 1))[0].commitId; + await vault.writeF(async (efs) => { + await efs.writeFile('test3', 'testdata3'); + }); + const fourthCommit = (await vault.log(undefined, 1))[0].commitId; + await vault.version(secondCommit); + await vault.writeF(async (efs) => { + await efs.writeFile('test4', 'testdata4'); + }); + await expect(() => { + return vault.version(thirdCommit); + }).rejects.toThrow(); + await expect(() => { + return vault.version(fourthCommit); + }).rejects.toThrow(); + }, + global.defaultTimeout, + ); test('can recover from dirty state', async () => { await vault.writeF(async (efs) => { await efs.writeFile('secret-1', 'secret-content'); @@ -547,11 +550,11 @@ describe('VaultInternal', () => { await vaultEFS.writeFile('dirty', 'dirtyData'); await vaultEFS.writeFile('secret-1', 'dirtyData'); // Setting dirty flag true - const vaultMetadataDbDomain = [ - ...vaultsDbDomain, + const vaultMetadataDbPath = [ + ...vaultsDbPath, vaultsUtils.encodeVaultId(vaultId), ]; - await db.put(vaultMetadataDbDomain, VaultInternal.dirtyKey, true); + await db.put([...vaultMetadataDbPath, VaultInternal.dirtyKey], true); // Restarting vault await vault.stop(); @@ -607,11 +610,11 @@ describe('VaultInternal', () => { }); // Setting dirty flag true - const vaultMetadataDbDomain = [ - ...vaultsDbDomain, + const vaultMetadataDbPath = [ + ...vaultsDbPath, vaultsUtils.encodeVaultId(vaultId), ]; - await db.put(vaultMetadataDbDomain, VaultInternal.dirtyKey, true); + await db.put([...vaultMetadataDbPath, VaultInternal.dirtyKey], true); // Restarting vault await vault.stop(); @@ -735,7 +738,7 @@ describe('VaultInternal', () => { // @ts-ignore: kidnap lock const lock = vault.lock; // Hold a write lock - const releaseWrite = await lock.acquireWrite(); + const [releaseWrite] = await lock.write()(); let finished = false; const writeP = vault.writeF(async () => { @@ -743,17 +746,17 @@ describe('VaultInternal', () => { }); await sleep(waitDelay); expect(finished).toBe(false); - releaseWrite(); + await releaseWrite(); await writeP; expect(finished).toBe(true); - const releaseRead = await lock.acquireRead(); + const [releaseRead] = await lock.read()(); finished = false; const writeP2 = vault.writeF(async () => { finished = true; }); await sleep(waitDelay); - releaseRead(); + await releaseRead(); await writeP2; expect(finished).toBe(true); }); @@ -761,7 +764,7 @@ describe('VaultInternal', () => { // @ts-ignore: kidnap lock const lock = vault.lock; // Hold a write lock - const releaseWrite = await lock.acquireWrite(); + const [releaseWrite] = await lock.write()(); let finished = false; const writeGen = vault.writeG(async function* () { @@ -772,11 +775,11 @@ describe('VaultInternal', () => { const runP = runGen(writeGen); await sleep(waitDelay); expect(finished).toBe(false); - releaseWrite(); + await releaseWrite(); await runP; expect(finished).toBe(true); - const releaseRead = await lock.acquireRead(); + const [releaseRead] = await lock.read()(); finished = false; const writeGen2 = vault.writeG(async function* () { yield; @@ -785,7 +788,7 @@ describe('VaultInternal', () => { }); const runP2 = runGen(writeGen2); await sleep(waitDelay); - releaseRead(); + await releaseRead(); await runP2; expect(finished).toBe(true); }); @@ -793,7 +796,7 @@ describe('VaultInternal', () => { // @ts-ignore: kidnap lock const lock = vault.lock; // Hold a write lock - const releaseWrite = await lock.acquireWrite(); + const [releaseWrite] = await lock.write()(); let finished = false; const writeP = vault.readF(async () => { @@ -801,7 +804,7 @@ describe('VaultInternal', () => { }); await sleep(waitDelay); expect(finished).toBe(false); - releaseWrite(); + await releaseWrite(); await writeP; expect(finished).toBe(true); }); @@ -809,7 +812,7 @@ describe('VaultInternal', () => { // @ts-ignore: kidnap lock const lock = vault.lock; // Hold a write lock - const releaseWrite = await lock.acquireWrite(); + const [releaseWrite] = await lock.write()(); let finished = false; const writeGen = vault.readG(async function* () { yield; @@ -819,7 +822,7 @@ describe('VaultInternal', () => { const runP = runGen(writeGen); await sleep(waitDelay); expect(finished).toBe(false); - releaseWrite(); + await releaseWrite(); await runP; expect(finished).toBe(true); }); @@ -827,7 +830,7 @@ describe('VaultInternal', () => { // @ts-ignore: kidnap lock const lock = vault.lock; // Hold a write lock - const releaseRead = await lock.acquireRead(); + const [releaseRead] = await lock.read()(); const finished: boolean[] = []; const doThing = async () => { finished.push(true); @@ -839,13 +842,13 @@ describe('VaultInternal', () => { vault.readF(doThing), ]); expect(finished.length).toBe(4); - releaseRead(); + await releaseRead(); }); test('readG allows concurrent reads', async () => { // @ts-ignore: kidnap lock const lock = vault.lock; // Hold a write lock - const releaseRead = await lock.acquireRead(); + const [releaseRead] = await lock.read()(); const finished: boolean[] = []; const doThing = async function* () { yield; @@ -859,7 +862,7 @@ describe('VaultInternal', () => { runGen(vault.readG(doThing)), ]); expect(finished.length).toBe(4); - releaseRead(); + await releaseRead(); }); // Life-cycle test('can create with CreateVaultInternal', async () => { @@ -871,8 +874,7 @@ describe('VaultInternal', () => { efs, keyManager: fakeKeyManager, vaultId: vaultId1, - vaultsDb, - vaultsDbDomain, + vaultsDbPath, logger, }); // Data exists for vault now @@ -894,8 +896,7 @@ describe('VaultInternal', () => { efs, keyManager: fakeKeyManager, vaultId: vaultId1, - vaultsDb, - vaultsDbDomain, + vaultsDbPath, logger, }); // Data exists for vault now @@ -914,8 +915,7 @@ describe('VaultInternal', () => { efs, keyManager: fakeKeyManager, vaultId: vaultId1, - vaultsDb, - vaultsDbDomain, + vaultsDbPath, logger, }); diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index 2117ea7a8..61796e807 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -139,44 +139,50 @@ describe('VaultManager', () => { await vaultManager?.destroy(); } }); - test('can create many vaults and open a vault', async () => { - const vaultManager = await VaultManager.createVaultManager({ - vaultsPath, - keyManager: dummyKeyManager, - gestaltGraph: {} as GestaltGraph, - nodeConnectionManager: {} as NodeConnectionManager, - acl: {} as ACL, - notificationsManager: {} as NotificationsManager, - db, - logger: logger.getChild(VaultManager.name), - }); - try { - const vaultNames = [ - 'Vault1', - 'Vault2', - 'Vault3', - 'Vault4', - 'Vault5', - 'Vault6', - 'Vault7', - 'Vault8', - 'Vault9', - 'Vault10', - 'Vault11', - 'Vault12', - 'Vault13', - 'Vault14', - 'Vault15', - ]; - for (const vaultName of vaultNames) { - await vaultManager.createVault(vaultName as VaultName); + test( + 'can create many vaults and open a vault', + async () => { + const vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + keyManager: dummyKeyManager, + gestaltGraph: {} as GestaltGraph, + nodeConnectionManager: {} as NodeConnectionManager, + acl: {} as ACL, + notificationsManager: {} as NotificationsManager, + db, + logger: logger.getChild(VaultManager.name), + }); + try { + const vaultNames = [ + 'Vault1', + 'Vault2', + 'Vault3', + 'Vault4', + 'Vault5', + 'Vault6', + 'Vault7', + 'Vault8', + 'Vault9', + 'Vault10', + 'Vault11', + 'Vault12', + 'Vault13', + 'Vault14', + 'Vault15', + ]; + for (const vaultName of vaultNames) { + await vaultManager.createVault(vaultName as VaultName); + } + expect((await vaultManager.listVaults()).size).toEqual( + vaultNames.length, + ); + } finally { + await vaultManager?.stop(); + await vaultManager?.destroy(); } - expect((await vaultManager.listVaults()).size).toEqual(vaultNames.length); - } finally { - await vaultManager?.stop(); - await vaultManager?.destroy(); - } - }); + }, + global.defaultTimeout * 2, + ); test('can rename a vault', async () => { const vaultManager = await VaultManager.createVaultManager({ vaultsPath, @@ -1302,7 +1308,7 @@ describe('VaultManager', () => { const vaultsMap = vaultManager.vaultMap; const vaultAndLock = vaultsMap.get(vaultId.toString() as VaultIdString); const lock = vaultAndLock!.lock; - const releaseWrite = await lock.acquireWrite(); + const [releaseWrite] = await lock.write()(); // Pulling vault respects VaultManager write lock const pullP = vaultManager.pullVault({ @@ -1329,7 +1335,7 @@ describe('VaultManager', () => { const vault = vaultAndLock!.vault!; // @ts-ignore: kidnap vault lock const vaultLock = vault.lock; - const releaseVaultWrite = await vaultLock.acquireWrite(); + const [releaseVaultWrite] = await vaultLock.write()(); // Pulling vault respects VaultManager write lock gitPullMock.mockClear(); const pullP2 = vaultManager.pullVault({ @@ -1586,7 +1592,7 @@ describe('VaultManager', () => { const vaultAndLock = vaultMap.get(vaultId.toString() as VaultIdString)!; const lock = vaultAndLock.lock; const vault = vaultAndLock.vault!; - const release = await lock.acquireWrite(); + const [release] = await lock.write()(); // Try to destroy const closeP = vaultManager.closeVault(vaultId); await sleep(1000); @@ -1596,7 +1602,7 @@ describe('VaultManager', () => { vaultMap.get(vaultId.toString() as VaultIdString)!.vault, ).toBeDefined(); // Release the lock - release(); + await release(); await closeP; expect(vault[running]).toBe(false); expect(vaultMap.get(vaultId.toString() as VaultIdString)).toBeUndefined(); @@ -1625,7 +1631,7 @@ describe('VaultManager', () => { const vaultAndLock = vaultMap.get(vaultId.toString() as VaultIdString)!; const lock = vaultAndLock.lock; const vault = vaultAndLock.vault!; - const release = await lock.acquireWrite(); + const [release] = await lock.write()(); // Try to destroy const destroyP = vaultManager.destroyVault(vaultId); await sleep(1000); @@ -1635,7 +1641,7 @@ describe('VaultManager', () => { vaultMap.get(vaultId.toString() as VaultIdString)!.vault, ).toBeDefined(); // Release the lock - release(); + await release(); await destroyP; expect(vault[destroyed]).toBe(true); expect(vaultMap.get(vaultId.toString() as VaultIdString)).toBeUndefined(); @@ -1663,7 +1669,7 @@ describe('VaultManager', () => { // Getting and holding the lock const vaultAndLock = vaultMap.get(vaultId.toString() as VaultIdString)!; const lock = vaultAndLock.lock; - const release = await lock.acquireWrite(); + const [release] = await lock.write()(); // Try to use vault let finished = false; const withP = vaultManager.withVaults([vaultId], async () => { @@ -1673,7 +1679,7 @@ describe('VaultManager', () => { // Shouldn't be destroyed expect(finished).toBe(false); // Release the lock - release(); + await release(); await withP; expect(finished).toBe(true); } finally { @@ -1713,6 +1719,7 @@ describe('VaultManager', () => { db, logger: logger.getChild(VaultManager.name), }); + try { await expect( Promise.all([ @@ -1834,8 +1841,7 @@ describe('VaultManager', () => { await vaultManager.stop(); await vaultManager.destroy(); // Vaults DB should be empty - const vaultsDb = await db.level(VaultManager.constructor.name); - expect(await db.count(vaultsDb)).toBe(0); + expect(await db.count([VaultManager.constructor.name])).toBe(0); vaultManager2 = await VaultManager.createVaultManager({ vaultsPath, keyManager: dummyKeyManager, diff --git a/tests/vaults/VaultOps.test.ts b/tests/vaults/VaultOps.test.ts index e376eb306..81e061cd3 100644 --- a/tests/vaults/VaultOps.test.ts +++ b/tests/vaults/VaultOps.test.ts @@ -1,7 +1,7 @@ import type { VaultId } from '@/vaults/types'; import type { Vault } from '@/vaults/Vault'; import type KeyManager from '@/keys/KeyManager'; -import type { DBDomain, DBLevel } from '@matrixai/db'; +import type { LevelPath } from '@matrixai/db'; import fs from 'fs'; import path from 'path'; import os from 'os'; @@ -24,8 +24,7 @@ describe('VaultOps', () => { let vaultInternal: VaultInternal; let vault: Vault; let db: DB; - let vaultsDb: DBLevel; - let vaultsDbDomain: DBDomain; + let vaultsDbPath: LevelPath; const dummyKeyManager = { getNodeId: () => { return testUtils.generateRandomNodeId(); @@ -64,8 +63,7 @@ describe('VaultOps', () => { }, ); db = await DB.createDB({ dbPath: path.join(dataDir, 'db'), logger }); - vaultsDbDomain = ['vaults']; - vaultsDb = await db.level(vaultsDbDomain[0]); + vaultsDbPath = ['vaults']; vaultInternal = await VaultInternal.createVaultInternal({ keyManager: dummyKeyManager, vaultId, @@ -73,8 +71,7 @@ describe('VaultOps', () => { logger: logger.getChild(VaultInternal.name), fresh: true, db, - vaultsDbDomain, - vaultsDb, + vaultsDbPath: vaultsDbPath, vaultName: 'VaultName', }); vault = vaultInternal as Vault; From 8c8f5afff9c540589a1390c040504c47387a1219 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 11 May 2022 13:05:36 +1000 Subject: [PATCH 014/137] fix: integrating db changes into Notifications Note that the `transaction` and `_transaction` methods still need te removed. --- src/notifications/NotificationsManager.ts | 397 +++++++++++----------- 1 file changed, 190 insertions(+), 207 deletions(-) diff --git a/src/notifications/NotificationsManager.ts b/src/notifications/NotificationsManager.ts index b648a2b81..83eca6f7b 100644 --- a/src/notifications/NotificationsManager.ts +++ b/src/notifications/NotificationsManager.ts @@ -1,4 +1,4 @@ -import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; +import type { DB, DBTransaction, LevelPath } from '@matrixai/db'; import type { NotificationId, Notification, @@ -12,13 +12,13 @@ import type NodeConnectionManager from '../nodes/NodeConnectionManager'; import type { NodeId } from '../nodes/types'; import Logger from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; +import { Lock } from '@matrixai/async-locks'; import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { utils as idUtils } from '@matrixai/id'; -import { utils as dbUtils } from '@matrixai/db'; -import { withF } from '@matrixai/resources'; +import * as resources from '@matrixai/resources'; import * as notificationsUtils from './utils'; import * as notificationsErrors from './errors'; import * as notificationsPB from '../proto/js/polykey/v1/notifications/notifications_pb'; @@ -76,8 +76,8 @@ class NotificationsManager { protected keyManager: KeyManager; protected nodeManager: NodeManager; protected nodeConnectionManager: NodeConnectionManager; - protected messageCap: number; + protected lock: Lock = new Lock(); /** * Top level stores MESSAGE_COUNT_KEY -> number (of messages) @@ -122,28 +122,25 @@ class NotificationsManager { public async start({ fresh = false, }: { fresh?: boolean } = {}): Promise { - this.logger.info(`Starting ${this.constructor.name}`); - if (fresh) { - await this.db.clear(this.notificationsDbPath); - } - // Getting latest ID and creating ID generator - let latestId: NotificationId | undefined; - // for await (const [k] of tran.iterator({ value: false }, [ - // ...this.nodeGraphBucketsDbPath, - // ])) { - // const keyStream = this.notificationsMessagesDb.createKeyStream({ - // limit: 1, - // reverse: true, - // }); - await withF( - [this.db.transaction()], - ([tran]) => async (tran) => tran.iterator({ limit: 1, reverse: true, value: false }, [...this.notificationsMessagesDbPath]) - } - for await (const o of keyStream) { - latestId = IdInternal.fromBuffer(o as Buffer); - } - this.notificationIdGenerator = createNotificationIdGenerator(latestId); - this.logger.info(`Started ${this.constructor.name}`); + await this.db.withTransactionF(async (tran) => { + this.logger.info(`Starting ${this.constructor.name}`); + if (fresh) { + await tran.clear(this.notificationsDbPath); + } + + // Getting latest ID and creating ID generator + let latestId: NotificationId | undefined; + const keyIterator = tran.iterator( + { limit: 1, reverse: true }, + this.notificationsMessagesDbPath, + ); + for await (const [key] of keyIterator) { + latestId = IdInternal.fromBuffer(key); + } + this.notificationIdGenerator = + notificationsUtils.createNotificationIdGenerator(latestId); + this.logger.info(`Started ${this.constructor.name}`); + }); } public async stop() { @@ -153,45 +150,21 @@ class NotificationsManager { public async destroy() { this.logger.info(`Destroying ${this.constructor.name}`); - const notificationsDb = await this.db.level(this.notificationsDomain); - await notificationsDb.clear(); + await this.db.withTransactionF(async (tran) => { + await tran.clear(this.notificationsDbPath); + }); this.logger.info(`Destroyed ${this.constructor.name}`); } - /** - * Run several operations within the same lock - * This does not ensure atomicity of the underlying database - * Database atomicity still depends on the underlying operation - */ - public async transaction( - f: (notificationsManager: NotificationsManager) => Promise, - ): Promise { - const release = await this.lock.acquire(); - try { - return await f(this); - } finally { - release(); - } - } - - /** - * Transaction wrapper that will not lock if the operation was executed - * within a transaction context - */ - public async _transaction(f: () => Promise): Promise { - if (this.lock.isLocked()) { - return await f(); - } else { - return await this.transaction(f); - } - } - /** * Send a notification to another node * The `data` parameter must match one of the NotificationData types outlined in ./types */ @ready(new notificationsErrors.ErrorNotificationsNotRunning()) - public async sendNotification(nodeId: NodeId, data: NotificationData) { + public async sendNotification( + nodeId: NodeId, + data: NotificationData, + ): Promise { const notification = { data: data, senderId: nodesUtils.encodeNodeId(this.keyManager.getNodeId()), @@ -213,46 +186,50 @@ class NotificationsManager { * Receive a notification */ @ready(new notificationsErrors.ErrorNotificationsNotRunning()) - public async receiveNotification(notification: Notification) { - await this._transaction(async () => { - const nodePerms = await this.acl.getNodePerm( - nodesUtils.decodeNodeId(notification.senderId)!, - ); - if (nodePerms === undefined) { - throw new notificationsErrors.ErrorNotificationsPermissionsNotFound(); - } - // Only keep the message if the sending node has the correct permissions - if (Object.keys(nodePerms.gestalt).includes('notify')) { - // If the number stored in notificationsDb >= 10000 - let numMessages = await this.db.get( - this.notificationsDbDomain, - MESSAGE_COUNT_KEY, + public async receiveNotification(notification: Notification): Promise { + return await resources.withF( + [this.db.transaction(), this.lock.lock()], + async ([tran]) => { + const nodePerms = await this.acl.getNodePerm( + nodesUtils.decodeNodeId(notification.senderId)!, ); - if (numMessages === undefined) { - numMessages = 0; - await this.db.put(this.notificationsDbDomain, MESSAGE_COUNT_KEY, 0); + if (nodePerms === undefined) { + throw new notificationsErrors.ErrorNotificationsPermissionsNotFound(); } - if (numMessages >= this.messageCap) { - // Remove the oldest notification from notificationsMessagesDb - const oldestId = await this.getOldestNotificationId(); - await this.removeNotification(oldestId!); + // Only keep the message if the sending node has the correct permissions + if (Object.keys(nodePerms.gestalt).includes('notify')) { + // If the number stored in notificationsDb >= 10000 + let numMessages = await tran.get([ + ...this.notificationsDbPath, + MESSAGE_COUNT_KEY, + ]); + if (numMessages === undefined) { + numMessages = 0; + await tran.put([...this.notificationsDbPath, MESSAGE_COUNT_KEY], 0); + } + if (numMessages >= this.messageCap) { + // Remove the oldest notification from notificationsMessagesDb + const oldestId = await this.getOldestNotificationId(tran); + await this.removeNotification(oldestId!, tran); + } + // Store the new notification in notificationsMessagesDb + const notificationId = this.notificationIdGenerator(); + await tran.put( + [ + ...this.notificationsMessagesDbPath, + idUtils.toBuffer(notificationId), + ], + notification, + ); + // Number of messages += 1 + const newNumMessages = numMessages + 1; + await tran.put( + [...this.notificationsDbPath, MESSAGE_COUNT_KEY], + newNumMessages, + ); } - // Store the new notification in notificationsMessagesDb - const notificationId = this.notificationIdGenerator(); - await this.db.put( - this.notificationsMessagesDbDomain, - idUtils.toBuffer(notificationId), - notification, - ); - // Number of messages += 1 - const newNumMessages = numMessages + 1; - await this.db.put( - this.notificationsDbDomain, - MESSAGE_COUNT_KEY, - newNumMessages, - ); - } - }); + }, + ); } /** @@ -268,29 +245,34 @@ class NotificationsManager { number?: number | 'all'; order?: 'newest' | 'oldest'; } = {}): Promise> { - let notificationIds: Array; - if (unread === true) { - notificationIds = await this.getNotificationIds('unread'); - } else { - notificationIds = await this.getNotificationIds('all'); - } + return await resources.withF( + [this.db.transaction(), this.lock.lock()], + async ([tran]) => { + let notificationIds: Array; + if (unread) { + notificationIds = await this.getNotificationIds('unread', tran); + } else { + notificationIds = await this.getNotificationIds('all', tran); + } - if (order === 'newest') { - notificationIds.reverse(); - } + if (order === 'newest') { + notificationIds.reverse(); + } - if (number === 'all' || number > notificationIds.length) { - number = notificationIds.length; - } - notificationIds = notificationIds.slice(0, number); + if (number === 'all' || number > notificationIds.length) { + number = notificationIds.length; + } + notificationIds = notificationIds.slice(0, number); - const notifications: Array = []; - for (const id of notificationIds) { - const notification = await this.readNotificationById(id); - notifications.push(notification!); - } + const notifications: Array = []; + for (const id of notificationIds) { + const notification = await this.readNotificationById(id, tran); + notifications.push(notification!); + } - return notifications; + return notifications; + }, + ); } /** @@ -301,134 +283,135 @@ class NotificationsManager { public async findGestaltInvite( fromNode: NodeId, ): Promise { - const notifications = await this.getNotifications('all'); - for (const notification of notifications) { - if ( - notification.data.type === 'GestaltInvite' && - nodesUtils.decodeNodeId(notification.senderId)!.equals(fromNode) - ) { - return notification; - } - } + return await resources.withF( + [this.db.transaction(), this.lock.lock()], + async ([tran]) => { + const notifications = await this.getNotifications('all', tran); + for (const notification of notifications) { + if ( + notification.data.type === 'GestaltInvite' && + nodesUtils.decodeNodeId(notification.senderId)!.equals(fromNode) + ) { + return notification; + } + } + }, + ); } /** * Removes all notifications */ @ready(new notificationsErrors.ErrorNotificationsNotRunning()) - public async clearNotifications() { - await this._transaction(async () => { - const notificationIds = await this.getNotificationIds('all'); - const numMessages = await this.db.get( - this.notificationsDbDomain, - MESSAGE_COUNT_KEY, - ); - if (numMessages !== undefined) { - for (const id of notificationIds) { - await this.removeNotification(id); + public async clearNotifications(): Promise { + await resources.withF( + [this.db.transaction(), this.lock.lock()], + async ([tran]) => { + const notificationIds = await this.getNotificationIds('all', tran); + const numMessages = await tran.get([ + ...this.notificationsDbPath, + MESSAGE_COUNT_KEY, + ]); + if (numMessages !== undefined) { + for (const id of notificationIds) { + await this.removeNotification(id, tran); + } } - } - }); + }, + ); } - private async readNotificationById( + protected async readNotificationById( notificationId: NotificationId, + tran: DBTransaction, ): Promise { - return await this._transaction(async () => { - const notification = await this.db.get( - this.notificationsMessagesDbDomain, - idUtils.toBuffer(notificationId), - ); - if (notification === undefined) { - return undefined; - } - notification.isRead = true; - await this.db.put( - this.notificationsMessagesDbDomain, - idUtils.toBuffer(notificationId), - notification, - ); - return notification; - }); + const notification = await tran.get([ + ...this.notificationsMessagesDbPath, + idUtils.toBuffer(notificationId), + ]); + if (notification === undefined) { + return undefined; + } + notification.isRead = true; + await tran.put( + [...this.notificationsMessagesDbPath, idUtils.toBuffer(notificationId)], + notification, + ); + return notification; } - private async getNotificationIds( + protected async getNotificationIds( type: 'unread' | 'all', + tran: DBTransaction, ): Promise> { - return await this._transaction(async () => { - const notificationIds: Array = []; - for await (const o of this.notificationsMessagesDb.createReadStream()) { - const notificationId = IdInternal.fromBuffer( - (o as any).key, - ); - const data = (o as any).value as Buffer; - const notification = await this.db.deserializeDecrypt( - data, - false, - ); - if (type === 'all') { + const notificationIds: Array = []; + const messageIterator = tran.iterator({}, this.notificationsMessagesDbPath); + for await (const [key, value] of messageIterator) { + const notificationId = IdInternal.fromBuffer(key); + const notification = JSON.parse(value.toString()) as Notification; + if (type === 'all') { + notificationIds.push(notificationId); + } else if (type === 'unread') { + if (!notification.isRead) { notificationIds.push(notificationId); - } else if (type === 'unread') { - if (notification.isRead === false) { - notificationIds.push(notificationId); - } } } - return notificationIds; - }); + } + return notificationIds; } - private async getNotifications( + protected async getNotifications( type: 'unread' | 'all', + tran: DBTransaction, ): Promise> { - return await this._transaction(async () => { - const notifications: Array = []; - for await (const v of this.notificationsMessagesDb.createValueStream()) { - const data = v as Buffer; - const notification = await this.db.deserializeDecrypt( - data, - false, - ); - if (type === 'all') { + const notifications: Array = []; + // This.notificationsMessagesDb.createValueStream() + for await (const [, value] of tran.iterator( + {}, + this.notificationsMessagesDbPath, + )) { + const notification = JSON.parse(value.toString()) as Notification; + if (type === 'all') { + notifications.push(notification); + } else if (type === 'unread') { + if (!notification.isRead) { notifications.push(notification); - } else if (type === 'unread') { - if (notification.isRead === false) { - notifications.push(notification); - } } } - return notifications; - }); + } + return notifications; } - private async getOldestNotificationId(): Promise { - const notificationIds = await this.getNotificationIds('all'); + protected async getOldestNotificationId( + tran: DBTransaction, + ): Promise { + const notificationIds = await this.getNotificationIds('all', tran); if (notificationIds.length === 0) { return undefined; } return notificationIds[0]; } - private async removeNotification(messageId: NotificationId) { - await this._transaction(async () => { - const numMessages = await this.db.get( - this.notificationsDbDomain, - MESSAGE_COUNT_KEY, - ); - if (numMessages === undefined) { - throw new notificationsErrors.ErrorNotificationsDb(); - } + protected async removeNotification( + messageId: NotificationId, + tran: DBTransaction, + ): Promise { + const numMessages = await tran.get([ + ...this.notificationsDbPath, + MESSAGE_COUNT_KEY, + ]); + if (numMessages === undefined) { + throw new notificationsErrors.ErrorNotificationsDb(); + } - await this.db.del( - this.notificationsMessagesDbDomain, - idUtils.toBuffer(messageId), - ); - await this.db.put( - this.notificationsDbDomain, - MESSAGE_COUNT_KEY, - numMessages - 1, - ); - }); + await tran.del([ + ...this.notificationsMessagesDbPath, + idUtils.toBuffer(messageId), + ]); + await tran.put( + [...this.notificationsDbPath, MESSAGE_COUNT_KEY], + numMessages - 1, + ); } } From fc962a1e9bea05c32e884fb411ff2937753bd8d1 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 11 May 2022 15:17:48 +1000 Subject: [PATCH 015/137] fix: integrating db changes into `Discovery` I opted not to use transactions for the most part. Adding things to the queue has to be handled with locking anyway so I opted to rely on that istead. This still bears testing though. --- src/discovery/Discovery.ts | 486 ++++++++++++++++++------------------- 1 file changed, 234 insertions(+), 252 deletions(-) diff --git a/src/discovery/Discovery.ts b/src/discovery/Discovery.ts index a6d6c1129..80b4b43f7 100644 --- a/src/discovery/Discovery.ts +++ b/src/discovery/Discovery.ts @@ -1,4 +1,4 @@ -import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; +import type { DB, LevelPath } from '@matrixai/db'; import type { DiscoveryQueueId, DiscoveryQueueIdGenerator } from './types'; import type { NodeId, NodeInfo } from '../nodes/types'; import type NodeManager from '../nodes/NodeManager'; @@ -17,7 +17,6 @@ import type { Sigchain } from '../sigchain'; import type { KeyManager } from '../keys'; import type { ClaimIdEncoded, Claim, ClaimLinkIdentity } from '../claims/types'; import type { ChainData } from '../sigchain/types'; -import { Mutex } from 'async-mutex'; import Logger from '@matrixai/logger'; import { CreateDestroyStartStop, @@ -25,17 +24,15 @@ import { status, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { IdInternal } from '@matrixai/id'; -import { withF } from '@matrixai/resources'; -import { Lock, LockBox } from '@matrixai/async-locks'; -import { utils as dbUtils } from '@matrixai/db'; +import { Lock } from '@matrixai/async-locks'; import * as idUtils from '@matrixai/id/dist/utils'; import * as discoveryUtils from './utils'; import * as discoveryErrors from './errors'; import * as nodesErrors from '../nodes/errors'; -import * as utils from '../utils'; import * as gestaltsUtils from '../gestalts/utils'; import * as claimsUtils from '../claims/utils'; import * as nodesUtils from '../nodes/utils'; +import { never, promise } from '../utils'; interface Discovery extends CreateDestroyStartStop {} @CreateDestroyStartStop( @@ -93,10 +90,9 @@ class Discovery { protected discoveryQueueDbPath: LevelPath = [this.constructor.name, 'queue']; protected discoveryQueueIdGenerator: DiscoveryQueueIdGenerator; protected visitedVertices = new Set(); - protected discoveryQueue: AsyncGenerator; protected discoveryProcess: Promise; - protected queuePlug: Mutex = new Mutex(); - protected queuePlugRelease: MutexInterface.Releaser | undefined; + protected queuePlug = promise(); + protected lock: Lock = new Lock(); public constructor({ keyManager, @@ -130,60 +126,43 @@ class Discovery { fresh?: boolean; } = {}): Promise { this.logger.info(`Starting ${this.constructor.name}`); - const discoveryDb = await this.db.level(this.discoveryDbDomain); - // Queue stores DiscoveryQueueId -> GestaltKey - const discoveryQueueDb = await this.db.level( - this.discoveryQueueDbDomain[1], - discoveryDb, - ); if (fresh) { - await discoveryDb.clear(); + await this.db.clear(this.discoveryDbPath); } - this.discoveryDb = discoveryDb; - this.discoveryQueueDb = discoveryQueueDb; // Getting latest ID and creating ID generator let latestId: DiscoveryQueueId | undefined; - const keyStream = this.discoveryQueueDb.createKeyStream({ - limit: 1, - reverse: true, - }); - for await (const o of keyStream) { - latestId = IdInternal.fromBuffer(o); + const keyIterator = this.db.iterator( + { limit: 1, reverse: true, values: false }, + this.discoveryQueueDbPath, + ); + for await (const [key] of keyIterator) { + latestId = IdInternal.fromBuffer(key); } this.discoveryQueueIdGenerator = discoveryUtils.createDiscoveryQueueIdGenerator(latestId); - this.discoveryQueue = this.setupDiscoveryQueue(); - this.discoveryProcess = this.runDiscoveryQueue(); + // Starting the queue + this.discoveryProcess = this.setupDiscoveryQueue(); this.logger.info(`Started ${this.constructor.name}`); } public async stop(): Promise { this.logger.info(`Stopping ${this.constructor.name}`); - if (this.queuePlugRelease != null) { - this.queuePlugRelease(); - } - await this.discoveryQueue.return(); + this.queuePlug.resolveP(); await this.discoveryProcess; this.logger.info(`Stopped ${this.constructor.name}`); } - public async destroy() { + public async destroy(): Promise { this.logger.info(`Destroying ${this.constructor.name}`); - const discoveryDb = await this.db.level(this.discoveryDbDomain); - await discoveryDb.clear(); + await this.db.clear(this.discoveryDbPath); this.logger.info(`Destroyed ${this.constructor.name}`); } - public transaction: ResourceAcquire = async () => { - const release = await this.lock.acquire(); - return [async () => release(), this]; - }; - /** * Queues a node for discovery. Internally calls `pushKeyToDiscoveryQueue`. */ @ready(new discoveryErrors.ErrorDiscoveryNotRunning()) - public async queueDiscoveryByNode(nodeId: NodeId) { + public async queueDiscoveryByNode(nodeId: NodeId): Promise { const nodeKey = gestaltsUtils.keyFromNode(nodeId); await this.pushKeyToDiscoveryQueue(nodeKey); } @@ -196,87 +175,192 @@ class Discovery { public async queueDiscoveryByIdentity( providerId: ProviderId, identityId: IdentityId, - ) { + ): Promise { const identityKey = gestaltsUtils.keyFromIdentity(providerId, identityId); await this.pushKeyToDiscoveryQueue(identityKey); } /** - * Generator for the logic of iterating through the Discovery Queue. + * Async function for processing the Discovery Queue */ - public async *setupDiscoveryQueue(): AsyncGenerator { + public async setupDiscoveryQueue(): Promise { while (true) { - if (!(await this.queueIsEmpty())) { - for await (const o of this.discoveryQueueDb.createReadStream()) { - const vertexId = IdInternal.fromBuffer(o.key) as DiscoveryQueueId; - const data = o.value as Buffer; - const vertex = await this.db.deserializeDecrypt( - data, - false, - ); - const vertexGId = gestaltsUtils.ungestaltKey(vertex); - if (vertexGId.type === 'node') { - // The sigchain data of the vertex (containing all cryptolinks) - let vertexChainData: ChainData = {}; - // If the vertex we've found is our own node, we simply get our own chain - const nodeId = nodesUtils.decodeNodeId(vertexGId.nodeId)!; - if (nodeId.equals(this.keyManager.getNodeId())) { - const vertexChainDataEncoded = await this.sigchain.getChainData(); - // Decode all our claims - no need to verify (on our own sigchain) - for (const c in vertexChainDataEncoded) { - const claimId = c as ClaimIdEncoded; - vertexChainData[claimId] = claimsUtils.decodeClaim( - vertexChainDataEncoded[claimId], - ); + // Checking and waiting for items to process + if (await this.queueIsEmpty()) { + if (!(this[status] === 'stopping')) { + this.queuePlug = promise(); + } + await this.queuePlug.p; + } + if (this[status] === 'stopping') { + break; + } + + // Processing queue + for await (const [key, value] of this.db.iterator( + {}, + this.discoveryQueueDbPath, + )) { + const vertexId = IdInternal.fromBuffer(key) as DiscoveryQueueId; + const vertex = await this.db.deserializeDecrypt( + value, + false, + ); + const vertexGId = gestaltsUtils.ungestaltKey(vertex); + switch (vertexGId.type) { + case 'node': + { + // The sigChain data of the vertex (containing all cryptolinks) + let vertexChainData: ChainData = {}; + // If the vertex we've found is our own node, we simply get our own chain + const nodeId = nodesUtils.decodeNodeId(vertexGId.nodeId)!; + if (nodeId.equals(this.keyManager.getNodeId())) { + const vertexChainDataEncoded = + await this.sigchain.getChainData(); + // Decode all our claims - no need to verify (on our own sigChain) + for (const c in vertexChainDataEncoded) { + const claimId = c as ClaimIdEncoded; + vertexChainData[claimId] = claimsUtils.decodeClaim( + vertexChainDataEncoded[claimId], + ); + } + // Otherwise, request the verified chain data from the node + } else { + try { + vertexChainData = await this.nodeManager.requestChainData( + nodeId, + ); + } catch (e) { + this.visitedVertices.add(vertex); + await this.removeKeyFromDiscoveryQueue(vertexId); + this.logger.error( + `Failed to discover ${vertexGId.nodeId} - ${e.toString()}`, + ); + continue; + } } - // Otherwise, request the verified chain data from the node - } else { - try { - vertexChainData = await this.nodeManager.requestChainData( - nodeId, - ); - } catch (e) { - this.visitedVertices.add(vertex); - await this.removeKeyFromDiscoveryQueue(vertexId); - this.logger.error( - `Failed to discover ${vertexGId.nodeId} - ${e.toString()}`, - ); - yield; - continue; + // TODO: for now, the chain data is treated as a 'disjoint' set of + // cryptolink claims from a node to another node/identity + // That is, we have no notion of revocations, or multiple claims to the + // same node/identity. Thus, we simply iterate over this chain of + // cryptolinks. + // Now have the NodeInfo of this vertex + const vertexNodeInfo: NodeInfo = { + id: nodesUtils.encodeNodeId(nodeId), + chain: vertexChainData, + }; + // Iterate over each of the claims in the chain (already verified) + // TODO: because we're iterating over keys in a record, I don't believe + // that this will iterate in lexicographical order of keys. For now, + // this doesn't matter though (because of the previous comment). + for (const claimId in vertexChainData) { + const claim: Claim = vertexChainData[claimId as ClaimIdEncoded]; + // If the claim is to a node + if (claim.payload.data.type === 'node') { + // Get the chain data of the linked node + // Could be node1 or node2 in the claim so get the one that's + // not equal to nodeId from above + const node1Id = nodesUtils.decodeNodeId( + claim.payload.data.node1, + )!; + const node2Id = nodesUtils.decodeNodeId( + claim.payload.data.node2, + )!; + const linkedVertexNodeId = node1Id.equals(nodeId) + ? node2Id + : node1Id; + const linkedVertexGK = + gestaltsUtils.keyFromNode(linkedVertexNodeId); + let linkedVertexChainData: ChainData; + try { + linkedVertexChainData = + await this.nodeManager.requestChainData( + linkedVertexNodeId, + ); + } catch (e) { + if ( + e instanceof nodesErrors.ErrorNodeConnectionDestroyed || + e instanceof nodesErrors.ErrorNodeConnectionTimeout + ) { + if (!this.visitedVertices.has(linkedVertexGK)) { + await this.pushKeyToDiscoveryQueue(linkedVertexGK); + } + this.logger.error( + `Failed to discover ${nodesUtils.encodeNodeId( + linkedVertexNodeId, + )} - ${e.toString()}`, + ); + continue; + } else { + throw e; + } + } + // With this verified chain, we can link + const linkedVertexNodeInfo: NodeInfo = { + id: nodesUtils.encodeNodeId(linkedVertexNodeId), + chain: linkedVertexChainData, + }; + await this.gestaltGraph.linkNodeAndNode( + vertexNodeInfo, + linkedVertexNodeInfo, + ); + // Add this vertex to the queue if it hasn't already been visited + if (!this.visitedVertices.has(linkedVertexGK)) { + await this.pushKeyToDiscoveryQueue(linkedVertexGK); + } + } + // Else the claim is to an identity + if (claim.payload.data.type === 'identity') { + // Attempt to get the identity info on the identity provider + const identityInfo = await this.getIdentityInfo( + claim.payload.data.provider, + claim.payload.data.identity, + ); + // If we can't get identity info, simply skip this claim + if (identityInfo == null) { + continue; + } + // Link the node to the found identity info + await this.gestaltGraph.linkNodeAndIdentity( + vertexNodeInfo, + identityInfo, + ); + // Add this identity vertex to the queue if it is not present + const linkedIdentityGK = gestaltsUtils.keyFromIdentity( + claim.payload.data.provider, + claim.payload.data.identity, + ); + if (!this.visitedVertices.has(linkedIdentityGK)) { + await this.pushKeyToDiscoveryQueue(linkedIdentityGK); + } + } } } - // TODO: for now, the chain data is treated as a 'disjoint' set of - // cryptolink claims from a node to another node/identity - // That is, we have no notion of revocations, or multiple claims to the - // same node/identity. Thus, we simply iterate over this chain of - // cryptolinks. - // Now have the NodeInfo of this vertex - const vertexNodeInfo: NodeInfo = { - id: nodesUtils.encodeNodeId(nodeId), - chain: vertexChainData, - }; - // Iterate over each of the claims in the chain (already verified) - // TODO: because we're iterating over keys in a record, I don't believe - // that this will iterate in lexicographical order of keys. For now, - // this doesn't matter though (because of the previous comment). - for (const claimId in vertexChainData) { - const claim: Claim = vertexChainData[claimId as ClaimIdEncoded]; - // If the claim is to a node - if (claim.payload.data.type === 'node') { - // Get the chain data of the linked node - // Could be node1 or node2 in the claim so get the one that's - // not equal to nodeId from above - const node1Id = nodesUtils.decodeNodeId( - claim.payload.data.node1, - )!; - const node2Id = nodesUtils.decodeNodeId( - claim.payload.data.node2, - )!; - const linkedVertexNodeId = node1Id.equals(nodeId) - ? node2Id - : node1Id; + break; + case 'identity': + { + // If the next vertex is an identity, perform a social discovery + // Firstly get the identity info of this identity + const vertexIdentityInfo = await this.getIdentityInfo( + vertexGId.providerId, + vertexGId.identityId, + ); + // If we don't have identity info, simply skip this vertex + if (vertexIdentityInfo == null) { + continue; + } + // Link the identity with each node from its claims on the provider + // Iterate over each of the claims + for (const id in vertexIdentityInfo.claims) { + const identityClaimId = id as IdentityClaimId; + const claim = vertexIdentityInfo.claims[identityClaimId]; + // Claims on an identity provider will always be node -> identity + // So just cast payload data as such + const data = claim.payload.data as ClaimLinkIdentity; + const linkedVertexNodeId = nodesUtils.decodeNodeId(data.node)!; const linkedVertexGK = gestaltsUtils.keyFromNode(linkedVertexNodeId); + // Get the chain data of this claimed node (so that we can link in GG) let linkedVertexChainData: ChainData; try { linkedVertexChainData = @@ -290,11 +374,8 @@ class Discovery { await this.pushKeyToDiscoveryQueue(linkedVertexGK); } this.logger.error( - `Failed to discover ${nodesUtils.encodeNodeId( - linkedVertexNodeId, - )} - ${e.toString()}`, + `Failed to discover ${data.node} - ${e.toString()}`, ); - yield; continue; } else { throw e; @@ -305,145 +386,41 @@ class Discovery { id: nodesUtils.encodeNodeId(linkedVertexNodeId), chain: linkedVertexChainData, }; - await this.gestaltGraph.linkNodeAndNode( - vertexNodeInfo, + await this.gestaltGraph.linkNodeAndIdentity( linkedVertexNodeInfo, + vertexIdentityInfo, ); - // Add this vertex to the queue if it hasn't already been visited + // Add this vertex to the queue if it is not present if (!this.visitedVertices.has(linkedVertexGK)) { await this.pushKeyToDiscoveryQueue(linkedVertexGK); } } - // Else the claim is to an identity - if (claim.payload.data.type === 'identity') { - // Attempt to get the identity info on the identity provider - const identityInfo = await this.getIdentityInfo( - claim.payload.data.provider, - claim.payload.data.identity, - ); - // If we can't get identity info, simply skip this claim - if (identityInfo == null) { - continue; - } - // Link the node to the found identity info - await this.gestaltGraph.linkNodeAndIdentity( - vertexNodeInfo, - identityInfo, - ); - // Add this identity vertex to the queue if it is not present - const linkedIdentityGK = gestaltsUtils.keyFromIdentity( - claim.payload.data.provider, - claim.payload.data.identity, - ); - if (!this.visitedVertices.has(linkedIdentityGK)) { - await this.pushKeyToDiscoveryQueue(linkedIdentityGK); - } - } - } - } else if (vertexGId.type === 'identity') { - // If the next vertex is an identity, perform a social discovery - // Firstly get the identity info of this identity - const vertexIdentityInfo = await this.getIdentityInfo( - vertexGId.providerId, - vertexGId.identityId, - ); - // If we don't have identity info, simply skip this vertex - if (vertexIdentityInfo == null) { - continue; } - // Link the identity with each node from its claims on the provider - // Iterate over each of the claims - for (const id in vertexIdentityInfo.claims) { - const identityClaimId = id as IdentityClaimId; - const claim = vertexIdentityInfo.claims[identityClaimId]; - // Claims on an identity provider will always be node -> identity - // So just cast payload data as such - const data = claim.payload.data as ClaimLinkIdentity; - const linkedVertexNodeId = nodesUtils.decodeNodeId(data.node)!; - const linkedVertexGK = - gestaltsUtils.keyFromNode(linkedVertexNodeId); - // Get the chain data of this claimed node (so that we can link in GG) - let linkedVertexChainData: ChainData; - try { - linkedVertexChainData = await this.nodeManager.requestChainData( - linkedVertexNodeId, - ); - } catch (e) { - if ( - e instanceof nodesErrors.ErrorNodeConnectionDestroyed || - e instanceof nodesErrors.ErrorNodeConnectionTimeout - ) { - if (!this.visitedVertices.has(linkedVertexGK)) { - await this.pushKeyToDiscoveryQueue(linkedVertexGK); - } - yield; - this.logger.error( - `Failed to discover ${data.node} - ${e.toString()}`, - ); - continue; - } else { - throw e; - } - } - // With this verified chain, we can link - const linkedVertexNodeInfo: NodeInfo = { - id: nodesUtils.encodeNodeId(linkedVertexNodeId), - chain: linkedVertexChainData, - }; - await this.gestaltGraph.linkNodeAndIdentity( - linkedVertexNodeInfo, - vertexIdentityInfo, - ); - // Add this vertex to the queue if it is not present - if (!this.visitedVertices.has(linkedVertexGK)) { - await this.pushKeyToDiscoveryQueue(linkedVertexGK); - } - } - } - this.visitedVertices.add(vertex); - await this.removeKeyFromDiscoveryQueue(vertexId); - yield; + break; + default: + never(); } - } else { - if (!(this[status] === 'stopping')) { - this.queuePlugRelease = await this.queuePlug.acquire(); - } - await this.queuePlug.waitForUnlock(); - } - if (this[status] === 'stopping') { - break; + this.visitedVertices.add(vertex); + await this.removeKeyFromDiscoveryQueue(vertexId); } } } - /** - * Used for iterating over the discovery queue. This method should run - * continuously whenever the Discovery module is started and should be exited - * only during stopping. - */ - protected async runDiscoveryQueue() { - for await (const _ of this.discoveryQueue) { - // Empty - } - } - /** * Simple check for whether the Discovery Queue is empty. Uses a * transaction lock to ensure consistency. */ protected async queueIsEmpty(): Promise { - return await utils.withF([this.transaction], async () => { + return await this.lock.withF(async () => { let nextDiscoveryQueueId: DiscoveryQueueId | undefined; - const keyStream = this.discoveryQueueDb.createKeyStream({ - limit: 1, - }); - for await (const o of keyStream) { - nextDiscoveryQueueId = IdInternal.fromBuffer(o); - } - if (nextDiscoveryQueueId == null) { - return true; + const keyIterator = this.db.iterator( + { limit: 1 }, + this.discoveryQueueDbPath, + ); + for await (const [key] of keyIterator) { + nextDiscoveryQueueId = IdInternal.fromBuffer(key); } - return false; + return nextDiscoveryQueueId == null; }); } @@ -452,25 +429,25 @@ class Discovery { * the queue if it was previously locked (due to being empty) * Will only add the Key if it does not already exist in the queue */ - protected async pushKeyToDiscoveryQueue(gk: GestaltKey) { - await utils.withF([this.transaction], async () => { - const valueStream = this.discoveryQueueDb.createValueStream({}); - for await (const key of valueStream) { - if (key === gk) { - return; + protected async pushKeyToDiscoveryQueue( + gestaltKey: GestaltKey, + ): Promise { + await this.lock.withF(async () => { + await this.db.withTransactionF(async (tran) => { + const valueIterator = tran.iterator({}, this.discoveryQueueDbPath); + for await (const [, value] of valueIterator) { + if (value.toString() === gestaltKey) { + return; + } } - } - const discoveryQueueId = this.discoveryQueueIdGenerator(); - await this.db.put( - this.discoveryQueueDbDomain, - idUtils.toBuffer(discoveryQueueId), - gk, - ); + const discoveryQueueId = this.discoveryQueueIdGenerator(); + await tran.put( + [...this.discoveryQueueDbDomain, idUtils.toBuffer(discoveryQueueId)], + gestaltKey, + ); + }); }); - if (this.queuePlugRelease != null) { - this.queuePlugRelease(); - this.queuePlugRelease = undefined; - } + this.queuePlug.resolveP(); } /** @@ -478,9 +455,14 @@ class Discovery { * only be done after a Key has been discovered in order to remove it from * the beginning of the queue. */ - protected async removeKeyFromDiscoveryQueue(keyId: DiscoveryQueueId) { - await utils.withF([this.transaction], async () => { - await this.db.del(this.discoveryQueueDbDomain, idUtils.toBuffer(keyId)); + protected async removeKeyFromDiscoveryQueue( + keyId: DiscoveryQueueId, + ): Promise { + await this.lock.withF(async () => { + await this.db.del([ + ...this.discoveryQueueDbPath, + idUtils.toBuffer(keyId), + ]); }); } From d33fc5a4648d1427a08ad7bbcdb6b1646d53c217 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 12 May 2022 18:36:24 +1000 Subject: [PATCH 016/137] fix: integrating db changes into `Sigchain` --- src/sigchain/Sigchain.ts | 425 ++++++++++++++------------------ tests/sigchain/Sigchain.test.ts | 9 +- 2 files changed, 191 insertions(+), 243 deletions(-) diff --git a/src/sigchain/Sigchain.ts b/src/sigchain/Sigchain.ts index 19baf94cf..0a7f8bb65 100644 --- a/src/sigchain/Sigchain.ts +++ b/src/sigchain/Sigchain.ts @@ -1,4 +1,4 @@ -import type { DB, DBLevel, DBOp } from '@matrixai/db'; +import type { DB, DBTransaction, LevelPath } from '@matrixai/db'; import type { ChainDataEncoded } from './types'; import type { ClaimData, @@ -12,11 +12,12 @@ import type KeyManager from '../keys/KeyManager'; import type { NodeIdEncoded } from '../nodes/types'; import Logger from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; -import { Mutex } from 'async-mutex'; import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; +import { utils as dbUtils } from '@matrixai/db'; +import { withF } from '@matrixai/resources'; import * as sigchainErrors from './errors'; import * as claimsUtils from '../claims/utils'; @@ -26,30 +27,22 @@ interface Sigchain extends CreateDestroyStartStop {} new sigchainErrors.ErrorSigchainDestroyed(), ) class Sigchain { - public readonly sigchainPath: string; - public readonly sigchainDbPath: string; protected readonly sequenceNumberKey: string = 'prevSequenceNumber'; protected logger: Logger; protected keyManager: KeyManager; protected db: DB; - protected sigchainDbDomain: string = this.constructor.name; - protected sigchainClaimsDbDomain: Array = [ - this.sigchainDbDomain, - 'claims', - ]; - protected sigchainMetadataDbDomain: Array = [ - this.sigchainDbDomain, - 'metadata', - ]; - protected sigchainDb: DBLevel; + // Top-level database for the sigchain domain + protected sigchainDbPath: LevelPath = [this.constructor.name]; // ClaimId (the lexicographic integer of the sequence number) // -> ClaimEncoded (a JWS in General JSON Serialization) - protected sigchainClaimsDb: DBLevel; + protected sigchainClaimsDbPath: LevelPath = [this.constructor.name, 'claims']; // Sub-level database for numerical metadata to be persisted // e.g. "sequenceNumber" -> current sequence number - protected sigchainMetadataDb: DBLevel; - protected lock: Mutex = new Mutex(); + protected sigchainMetadataDbPath: LevelPath = [ + this.constructor.name, + 'metadata', + ]; protected generateClaimId: ClaimIdGenerator; @@ -85,61 +78,37 @@ class Sigchain { this.keyManager = keyManager; } - get locked(): boolean { - return this.lock.isLocked(); - } - public async start({ fresh = false, }: { fresh?: boolean; } = {}): Promise { this.logger.info(`Starting ${this.constructor.name}`); - // Top-level database for the sigchain domain - const sigchainDb = await this.db.level(this.sigchainDbDomain); - // ClaimId (the lexicographic integer of the sequence number) - // -> ClaimEncoded (a JWS in General JSON Serialization) - const sigchainClaimsDb = await this.db.level( - this.sigchainClaimsDbDomain[1], - sigchainDb, - ); - // Sub-level database for numerical metadata to be persisted - // e.g. "sequenceNumber" -> current sequence number - const sigchainMetadataDb = await this.db.level( - this.sigchainMetadataDbDomain[1], - sigchainDb, - ); if (fresh) { - await sigchainDb.clear(); + await this.db.clear(this.sigchainDbPath); } - this.sigchainDb = sigchainDb; - this.sigchainClaimsDb = sigchainClaimsDb; - this.sigchainMetadataDb = sigchainMetadataDb; - // Initialise the sequence number (if not already done). // First claim in the sigchain has a sequence number of 1. // Therefore, with no claims in the sigchain, the previous sequence number // is set to 0. - await this._transaction(async () => { - const sequenceNumber = await this.db.get( - this.sigchainMetadataDbDomain, + await withF([this.db.transaction()], async ([tran]) => { + const sequenceNumber = await tran.get([ + ...this.sigchainMetadataDbPath, this.sequenceNumberKey, - ); + ]); if (sequenceNumber == null) { - await this.db.put( - this.sigchainMetadataDbDomain, - this.sequenceNumberKey, + await tran.put( + [...this.sigchainMetadataDbPath, this.sequenceNumberKey], 0, ); } + // Creating the ID generator + const latestId = await this.getLatestClaimId(tran); + this.generateClaimId = claimsUtils.createClaimIdGenerator( + this.keyManager.getNodeId(), + latestId, + ); }); - - // Creating the ID generator - const latestId = await this.getLatestClaimId(); - this.generateClaimId = claimsUtils.createClaimIdGenerator( - this.keyManager.getNodeId(), - latestId, - ); this.logger.info(`Started ${this.constructor.name}`); } @@ -150,35 +119,15 @@ class Sigchain { public async destroy() { this.logger.info(`Destroying ${this.constructor.name}`); - const sigchainDb = await this.db.level(this.sigchainDbDomain); - await sigchainDb.clear(); + await this.db.clear(this.sigchainDbPath); this.logger.info(`Destroyed ${this.constructor.name}`); } - /** - * Run several operations within the same lock - * This does not ensure atomicity of the underlying database - * Database atomicity still depends on the underlying operation - */ - public async transaction(f: (that: this) => Promise): Promise { - const release = await this.lock.acquire(); - try { - return await f(this); - } finally { - release(); - } - } - - /** - * Transaction wrapper that will not lock if the operation was executed - * within a transaction context - */ - protected async _transaction(f: () => Promise): Promise { - if (this.lock.isLocked()) { - return await f(); - } else { - return await this.transaction(f); - } + @ready(new sigchainErrors.ErrorSigchainNotRunning()) + public async withTransactionF( + f: (tran: DBTransaction) => Promise, + ): Promise { + return withF([this.db.transaction()], ([tran]) => f(tran)); } /** @@ -220,36 +169,28 @@ class Sigchain { @ready(new sigchainErrors.ErrorSigchainNotRunning()) public async addClaim( claimData: ClaimData, + tran?: DBTransaction, ): Promise<[ClaimId, ClaimEncoded]> { - return await this._transaction(async () => { - const prevSequenceNumber = await this.getSequenceNumber(); - const newSequenceNumber = prevSequenceNumber + 1; - - const claim = await this.createClaim({ - hPrev: await this.getHashPrevious(), - seq: newSequenceNumber, - data: claimData, - }); - - // Add the claim to the sigchain database, and update the sequence number - const claimId = this.generateClaimId(); - const ops: Array = [ - { - type: 'put', - domain: this.sigchainClaimsDbDomain, - key: claimId.toBuffer(), - value: claim, - }, - { - type: 'put', - domain: this.sigchainMetadataDbDomain, - key: this.sequenceNumberKey, - value: newSequenceNumber, - }, - ]; - await this.db.batch(ops); - return [claimId, claim]; + if (tran == null) { + return this.withTransactionF(async (tran) => + this.addClaim(claimData, tran), + ); + } + const prevSequenceNumber = await this.getSequenceNumber(tran); + const newSequenceNumber = prevSequenceNumber + 1; + const claim = await this.createClaim({ + hPrev: await this.getHashPrevious(tran), + seq: newSequenceNumber, + data: claimData, }); + // Add the claim to the sigchain database, and update the sequence number + const claimId = this.generateClaimId(); + await tran.put([...this.sigchainClaimsDbPath, claimId.toBuffer()], claim); + await tran.put( + [...this.sigchainMetadataDbPath, this.sequenceNumberKey], + newSequenceNumber, + ); + return [claimId, claim]; } /** @@ -261,34 +202,33 @@ class Sigchain { * an exception could be thrown. */ @ready(new sigchainErrors.ErrorSigchainNotRunning()) - public async addExistingClaim(claim: ClaimEncoded): Promise { - await this._transaction(async () => { - const decodedClaim = claimsUtils.decodeClaim(claim); - const prevSequenceNumber = await this.getSequenceNumber(); - const expectedSequenceNumber = prevSequenceNumber + 1; - // Ensure the sequence number and hash are correct before appending - if (decodedClaim.payload.seq !== expectedSequenceNumber) { - throw new sigchainErrors.ErrorSigchainInvalidSequenceNum(); - } - if (decodedClaim.payload.hPrev !== (await this.getHashPrevious())) { - throw new sigchainErrors.ErrorSigchainInvalidHash(); - } - const ops: Array = [ - { - type: 'put', - domain: this.sigchainClaimsDbDomain, - key: this.generateClaimId().toBuffer(), - value: claim, - }, - { - type: 'put', - domain: this.sigchainMetadataDbDomain, - key: this.sequenceNumberKey, - value: expectedSequenceNumber, - }, - ]; - await this.db.batch(ops); - }); + public async addExistingClaim( + claim: ClaimEncoded, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.addExistingClaim(claim, tran), + ); + } + const decodedClaim = claimsUtils.decodeClaim(claim); + const prevSequenceNumber = await this.getSequenceNumber(tran); + const expectedSequenceNumber = prevSequenceNumber + 1; + // Ensure the sequence number and hash are correct before appending + if (decodedClaim.payload.seq !== expectedSequenceNumber) { + throw new sigchainErrors.ErrorSigchainInvalidSequenceNum(); + } + if (decodedClaim.payload.hPrev !== (await this.getHashPrevious(tran))) { + throw new sigchainErrors.ErrorSigchainInvalidHash(); + } + await tran.put( + [...this.sigchainClaimsDbPath, this.generateClaimId().toBuffer()], + claim, + ); + await tran.put( + [...this.sigchainMetadataDbPath, this.sequenceNumberKey], + expectedSequenceNumber, + ); } /** @@ -298,19 +238,23 @@ class Sigchain { @ready(new sigchainErrors.ErrorSigchainNotRunning()) public async createIntermediaryClaim( claimData: ClaimData, + tran?: DBTransaction, ): Promise { - return await this._transaction(async () => { - const claim = await this.createClaim({ - hPrev: await this.getHashPrevious(), - seq: (await this.getSequenceNumber()) + 1, - data: claimData, - }); - const intermediaryClaim: ClaimIntermediary = { - payload: claim.payload, - signature: claim.signatures[0], - }; - return intermediaryClaim; + if (tran == null) { + return this.withTransactionF(async (tran) => + this.createIntermediaryClaim(claimData, tran), + ); + } + const claim = await this.createClaim({ + hPrev: await this.getHashPrevious(tran), + seq: (await this.getSequenceNumber(tran)) + 1, + data: claimData, }); + const intermediaryClaim: ClaimIntermediary = { + payload: claim.payload, + signature: claim.signatures[0], + }; + return intermediaryClaim; } /** @@ -320,20 +264,18 @@ class Sigchain { * claimUtils.decodeClaim() to decode each claim. */ @ready(new sigchainErrors.ErrorSigchainNotRunning()) - public async getChainData(): Promise { - return await this._transaction(async () => { - const chainData: ChainDataEncoded = {}; - for await (const o of this.sigchainClaimsDb.createReadStream()) { - const claimId = IdInternal.fromBuffer((o as any).key); - const encryptedClaim = (o as any).value; - const claim = await this.db.deserializeDecrypt( - encryptedClaim, - false, - ); - chainData[claimsUtils.encodeClaimId(claimId)] = claim; - } - return chainData; - }); + public async getChainData(tran?: DBTransaction): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => this.getChainData(tran)); + } + const chainData: ChainDataEncoded = {}; + const readIterator = tran.iterator({}, [...this.sigchainClaimsDbPath]); + for await (const [key, value] of readIterator) { + const claimId = IdInternal.fromBuffer(key); + const claim = dbUtils.deserialize(value); + chainData[claimsUtils.encodeClaimId(claimId)] = claim; + } + return chainData; } /** @@ -345,22 +287,25 @@ class Sigchain { * requesting client. */ @ready(new sigchainErrors.ErrorSigchainNotRunning()) - public async getClaims(claimType: ClaimType): Promise> { - return await this._transaction(async () => { - const relevantClaims: Array = []; - for await (const o of this.sigchainClaimsDb.createReadStream()) { - const data = (o as any).value; - const claim = await this.db.deserializeDecrypt( - data, - false, - ); - const decodedClaim = claimsUtils.decodeClaim(claim); - if (decodedClaim.payload.data.type === claimType) { - relevantClaims.push(claim); - } + public async getClaims( + claimType: ClaimType, + tran?: DBTransaction, + ): Promise> { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getClaims(claimType, tran), + ); + } + const relevantClaims: Array = []; + const readIterator = tran.iterator({}, [...this.sigchainClaimsDbPath]); + for await (const [, value] of readIterator) { + const claim = dbUtils.deserialize(value); + const decodedClaim = claimsUtils.decodeClaim(claim); + if (decodedClaim.payload.data.type === claimType) { + relevantClaims.push(claim); } - return relevantClaims; - }); + } + return relevantClaims; } /** @@ -369,37 +314,41 @@ class Sigchain { * @returns previous sequence number */ @ready(new sigchainErrors.ErrorSigchainNotRunning()) - public async getSequenceNumber(): Promise { - return await this._transaction(async () => { - const sequenceNumber = await this.db.get( - this.sigchainMetadataDbDomain, - this.sequenceNumberKey, + public async getSequenceNumber(tran?: DBTransaction): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getSequenceNumber(tran), ); - // Should never be reached: getSigchainDb() has a check whether sigchain - // has been started (where the sequence number is initialised) - if (sequenceNumber === undefined) { - throw new sigchainErrors.ErrorSigchainSequenceNumUndefined(); - } - return sequenceNumber; - }); + } + const sequenceNumber = await tran.get([ + ...this.sigchainMetadataDbPath, + this.sequenceNumberKey, + ]); + // Should never be reached: getSigchainDb() has a check whether sigchain + // has been started (where the sequence number is initialised) + if (sequenceNumber === undefined) { + throw new sigchainErrors.ErrorSigchainSequenceNumUndefined(); + } + return sequenceNumber; } /** * Helper function to compute the hash of the previous claim. */ @ready(new sigchainErrors.ErrorSigchainNotRunning()) - public async getHashPrevious(): Promise { - return await this._transaction(async () => { - const prevSequenceNumber = await this.getLatestClaimId(); - if (prevSequenceNumber == null) { - // If no other claims, then null - return null; - } else { - // Otherwise, create a hash of the previous claim - const previousClaim = await this.getClaim(prevSequenceNumber); - return claimsUtils.hashClaim(previousClaim); - } - }); + public async getHashPrevious(tran?: DBTransaction): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => this.getHashPrevious(tran)); + } + const prevSequenceNumber = await this.getLatestClaimId(tran); + if (prevSequenceNumber == null) { + // If no other claims, then null + return null; + } else { + // Otherwise, create a hash of the previous claim + const previousClaim = await this.getClaim(prevSequenceNumber, tran); + return claimsUtils.hashClaim(previousClaim); + } } /** @@ -408,59 +357,57 @@ class Sigchain { * (otherwise, if you want to check for existence, just use getSigchainDb() * and check if returned value is undefined). * @param claimId the ClaimId of the claim to retrieve + * @param tran * @returns the claim (a JWS) */ @ready(new sigchainErrors.ErrorSigchainNotRunning()) - public async getClaim(claimId: ClaimId): Promise { - return await this._transaction(async () => { - const claim = await this.db.get( - this.sigchainClaimsDbDomain, - claimId.toBuffer(), + public async getClaim( + claimId: ClaimId, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.getClaim(claimId, tran), ); - if (claim == null) { - throw new sigchainErrors.ErrorSigchainClaimUndefined(); - } - return claim; - }); + } + const claim = await tran.get([ + ...this.sigchainClaimsDbPath, + claimId.toBuffer(), + ]); + if (claim == null) { + throw new sigchainErrors.ErrorSigchainClaimUndefined(); + } + return claim; } @ready(new sigchainErrors.ErrorSigchainNotRunning()) - public async getSeqMap(): Promise> { + public async getSeqMap( + tran?: DBTransaction, + ): Promise> { + if (tran == null) { + return this.withTransactionF(async (tran) => this.getSeqMap(tran)); + } const map: Record = {}; - const claimStream = this.sigchainClaimsDb.createKeyStream(); + const claimStream = tran.iterator({}, [...this.sigchainClaimsDbPath]); let seq = 1; - for await (const o of claimStream) { - map[seq] = IdInternal.fromBuffer(o as Buffer); + for await (const [key] of claimStream) { + map[seq] = IdInternal.fromBuffer(key); seq++; } return map; } - @ready(new sigchainErrors.ErrorSigchainNotRunning()) - public async clearDB() { - await this.sigchainDb.clear(); - - await this._transaction(async () => { - await this.db.put( - this.sigchainMetadataDbDomain, - this.sequenceNumberKey, - 0, - ); - }); - } - - protected async getLatestClaimId(): Promise { - return await this._transaction(async () => { - let latestId: ClaimId | undefined; - const keyStream = this.sigchainClaimsDb.createKeyStream({ - limit: 1, - reverse: true, - }); - for await (const o of keyStream) { - latestId = IdInternal.fromBuffer(o as Buffer); - } - return latestId; - }); + protected async getLatestClaimId( + tran: DBTransaction, + ): Promise { + let latestId: ClaimId | undefined; + const keyStream = tran.iterator({ limit: 1, reverse: true }, [ + ...this.sigchainClaimsDbPath, + ]); + for await (const [key] of keyStream) { + latestId = IdInternal.fromBuffer(key); + } + return latestId; } } diff --git a/tests/sigchain/Sigchain.test.ts b/tests/sigchain/Sigchain.test.ts index b6ff170ef..e36a70e10 100644 --- a/tests/sigchain/Sigchain.test.ts +++ b/tests/sigchain/Sigchain.test.ts @@ -6,11 +6,12 @@ import path from 'path'; import fs from 'fs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; -import { KeyManager, utils as keysUtils } from '@/keys'; -import { Sigchain } from '@/sigchain'; +import KeyManager from '@/keys/KeyManager'; +import Sigchain from '@/sigchain/Sigchain'; import * as claimsUtils from '@/claims/utils'; import * as sigchainErrors from '@/sigchain/errors'; -import { utils as nodesUtils } from '@/nodes'; +import * as nodesUtils from '@/nodes/utils'; +import * as keysUtils from '@/keys/utils'; import * as testUtils from '../utils'; describe('Sigchain', () => { @@ -92,7 +93,7 @@ describe('Sigchain', () => { }); }); - test('session readiness', async () => { + test('sigchain readiness', async () => { const sigchain = await Sigchain.createSigchain({ keyManager, db, logger }); await expect(async () => { await sigchain.destroy(); From 26dddde9078aec5bbcd02572b07f1c3eb413ffb9 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 13 May 2022 10:18:05 +1000 Subject: [PATCH 017/137] build: updated dependencies and added incremental build --- .eslintrc | 14 +- .npmignore | 1 + package-lock.json | 17299 ++++++++++++++++++++++++++++++++------------ package.json | 46 +- shell.nix | 8 +- tsconfig.json | 2 + 6 files changed, 12614 insertions(+), 4756 deletions(-) diff --git a/.eslintrc b/.eslintrc index c8db5d863..5b6e8f753 100644 --- a/.eslintrc +++ b/.eslintrc @@ -11,26 +11,24 @@ "eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended", - "prettier", - "prettier/@typescript-eslint" + "prettier" ], "plugins": [ "import" ], "parserOptions": { "project": "tsconfig.json", - "sourceType": "module", - "ecmaVersion": 2021 + "sourceType": "module" }, "rules": { "linebreak-style": ["error", "unix"], "no-empty": 1, - "no-undef": 0, "no-useless-catch": 1, "no-prototype-builtins": 1, "no-constant-condition": 0, "no-useless-escape" : 0, "no-console": "error", + "require-yield": 0, "eqeqeq": ["error", "smart"], "spaced-comment": [ "warn", @@ -121,6 +119,12 @@ "leadingUnderscore": "allow", "trailingUnderscore": "allowSingleOrDouble" }, + { + "selector": "function", + "format": ["camelCase", "PascalCase"], + "leadingUnderscore": "allow", + "trailingUnderscore": "allowSingleOrDouble" + }, { "selector": "variable", "format": ["camelCase", "UPPER_CASE", "PascalCase"], diff --git a/.npmignore b/.npmignore index 4a1857eea..3e70e24c7 100644 --- a/.npmignore +++ b/.npmignore @@ -14,3 +14,4 @@ /docs /benches /builds +/dist/tsbuildinfo diff --git a/package-lock.json b/package-lock.json index 4ad9b4ecb..8fe56b2cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,117 +1,10775 @@ { "name": "@matrixai/polykey", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@matrixai/polykey", + "version": "1.0.0", + "license": "GPL-3.0", + "dependencies": { + "@grpc/grpc-js": "1.6.7", + "@matrixai/async-init": "^1.7.3", + "@matrixai/async-locks": "^2.2.4", + "@matrixai/db": "^3.3.3", + "@matrixai/errors": "^1.1.1", + "@matrixai/id": "^3.3.3", + "@matrixai/logger": "^2.1.1", + "@matrixai/resources": "^1.1.3", + "@matrixai/workers": "^1.3.3", + "ajv": "^7.0.4", + "bip39": "^3.0.3", + "canonicalize": "^1.0.5", + "cheerio": "^1.0.0-rc.5", + "commander": "^8.3.0", + "cross-fetch": "^3.0.6", + "cross-spawn": "^7.0.3", + "encryptedfs": "^3.5.1", + "fast-fuzzy": "^1.10.8", + "fd-lock": "^1.2.0", + "google-protobuf": "^3.14.0", + "ip-num": "^1.3.3-0", + "isomorphic-git": "^1.8.1", + "jose": "^4.3.6", + "lexicographic-integer": "^1.1.0", + "multiformats": "^9.4.8", + "node-forge": "^0.10.0", + "pako": "^1.0.11", + "prompts": "^2.4.1", + "readable-stream": "^3.6.0", + "resource-counter": "^1.2.4", + "threads": "^1.6.5", + "utp-native": "^2.5.3", + "uuid": "^8.3.0" + }, + "bin": { + "pk": "dist/bin/polykey.js", + "polykey": "dist/bin/polykey.js" + }, + "devDependencies": { + "@babel/preset-env": "^7.13.10", + "@types/cross-spawn": "^6.0.2", + "@types/google-protobuf": "^3.7.4", + "@types/jest": "^27.0.2", + "@types/nexpect": "^0.4.31", + "@types/node": "^16.11.7", + "@types/node-forge": "^0.9.7", + "@types/pako": "^1.0.2", + "@types/prompts": "^2.0.13", + "@types/readable-stream": "^2.3.11", + "@types/uuid": "^8.3.0", + "@typescript-eslint/eslint-plugin": "^5.23.0", + "@typescript-eslint/parser": "^5.23.0", + "babel-jest": "^27.0.0", + "eslint": "^8.15.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-prettier": "^4.0.0", + "grpc_tools_node_protoc_ts": "^5.1.3", + "jest": "^27.2.5", + "jest-mock-process": "^1.4.1", + "jest-mock-props": "^1.9.0", + "mocked-env": "^1.3.5", + "nexpect": "^0.6.0", + "node-gyp-build": "4.4.0", + "pkg": "5.6.0", + "prettier": "^2.6.2", + "ts-jest": "^27.0.5", + "ts-node": "^10.4.0", + "tsconfig-paths": "^3.9.0", + "typedoc": "^0.22.15", + "typescript": "^4.5.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.17.10", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.17.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.9", + "@babel/parser": "^7.17.10", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.10", + "@babel/types": "^7.17.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.17.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.17.10", + "@jridgewell/gen-mapping": "^0.1.0", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.17.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.17.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.17.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.17.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.17.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.17.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.16.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.17.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.16.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.16.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.17.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.17.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.17.10", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.16.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.17.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.17.6", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.17.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.17.0", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.16.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.16.10", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "dev": true, + "license": "MIT", + "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-dynamic-import": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "dev": true, + "license": "MIT", + "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-top-level-await": { + "version": "7.14.5", + "dev": true, + "license": "MIT", + "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.17.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.16.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.17.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.17.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.17.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.17.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.17.9", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-transform": "^0.15.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.17.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-async-generator-functions": "^7.16.8", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-proposal-class-static-block": "^7.17.6", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.16.7", + "@babel/plugin-proposal-json-strings": "^7.16.7", + "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.17.3", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-private-methods": "^7.16.11", + "@babel/plugin-proposal-private-property-in-object": "^7.16.7", + "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@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-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.16.7", + "@babel/plugin-transform-async-to-generator": "^7.16.8", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.16.7", + "@babel/plugin-transform-classes": "^7.16.7", + "@babel/plugin-transform-computed-properties": "^7.16.7", + "@babel/plugin-transform-destructuring": "^7.17.7", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.16.7", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.16.7", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.16.7", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.17.9", + "@babel/plugin-transform-modules-systemjs": "^7.17.8", + "@babel/plugin-transform-modules-umd": "^7.16.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.10", + "@babel/plugin-transform-new-target": "^7.16.7", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.16.7", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.17.9", + "@babel/plugin-transform-reserved-words": "^7.16.7", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.16.7", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.16.7", + "@babel/plugin-transform-typeof-symbol": "^7.16.7", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.17.10", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.17.9", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.17.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.10", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.10", + "@babel/types": "^7.17.10", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.17.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspotcode/source-map-consumer": { + "version": "0.8.0", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-consumer": "0.8.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "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/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.6.7", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.6.4", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.6.12", + "license": "Apache-2.0", + "dependencies": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.10.0", + "yargs": "^16.2.0" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "dev": true, + "license": "ISC", + "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/schema": { + "version": "0.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "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/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.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/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/source-map": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "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.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@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-sequencer": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "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/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "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/types/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@matrixai/async-init": { + "version": "1.7.3", + "license": "Apache-2.0", + "dependencies": { + "@matrixai/async-locks": "^2.2.4", + "@matrixai/errors": "^1.1.1" + } + }, + "node_modules/@matrixai/async-locks": { + "version": "2.2.5", + "license": "Apache-2.0", + "dependencies": { + "@matrixai/errors": "^1.1.1", + "@matrixai/resources": "^1.1.3", + "async-mutex": "^0.3.2" + } + }, + "node_modules/@matrixai/db": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.3.4.tgz", + "integrity": "sha512-iRuwT+jbCZ4om5tbiUvaoYTRBfA6soULYmyqV0n2Av7gayiRhP7e0tEcxI3VFue4xuO1KPCsZjSTwcFXesHP0g==", + "dependencies": { + "@matrixai/async-init": "^1.7.3", + "@matrixai/errors": "^1.1.1", + "@matrixai/logger": "^2.1.1", + "@matrixai/resources": "^1.1.3", + "@matrixai/workers": "^1.3.3", + "@types/abstract-leveldown": "^7.2.0", + "level": "7.0.1", + "threads": "^1.6.5" + } + }, + "node_modules/@matrixai/errors": { + "version": "1.1.1", + "license": "Apache-2.0", + "dependencies": { + "ts-custom-error": "^3.2.0" + } + }, + "node_modules/@matrixai/id": { + "version": "3.3.3", + "license": "Apache-2.0", + "dependencies": { + "multiformats": "^9.4.8", + "uuid": "^8.3.2" + } + }, + "node_modules/@matrixai/logger": { + "version": "2.1.1", + "license": "Apache-2.0" + }, + "node_modules/@matrixai/resources": { + "version": "1.1.3", + "license": "Apache-2.0" + }, + "node_modules/@matrixai/workers": { + "version": "1.3.3", + "license": "Apache-2.0", + "dependencies": { + "@matrixai/async-init": "^1.7.3", + "@matrixai/errors": "^1.1.1", + "@matrixai/logger": "^2.1.1", + "threads": "^1.6.5" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/abstract-leveldown": { + "version": "7.2.0", + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.1.19", + "dev": true, + "license": "MIT", + "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.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.17.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/cross-spawn": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/google-protobuf": { + "version": "3.15.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/long": { + "version": "4.0.2", + "license": "MIT" + }, + "node_modules/@types/nexpect": { + "version": "0.4.31", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "16.11.35", + "license": "MIT" + }, + "node_modules/@types/node-forge": { + "version": "0.9.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/pako": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prettier": { + "version": "2.6.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prompts": { + "version": "2.0.14", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/readable-stream": { + "version": "2.3.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "safe-buffer": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "16.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "5.23.0", + "@typescript-eslint/type-utils": "5.23.0", + "@typescript-eslint/utils": "5.23.0", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.7", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.23.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "5.23.0", + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/typescript-estree": "5.23.0", + "debug": "^4.3.2" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/visitor-keys": "5.23.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "5.23.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.23.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.23.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/visitor-keys": "5.23.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.7", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.23.0", + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/typescript-estree": "5.23.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.23.0", + "eslint-visitor-keys": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/abstract-leveldown": { + "version": "7.2.0", + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.0.0", + "is-buffer": "^2.0.5", + "level-concat-iterator": "^3.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/acorn": { + "version": "8.7.1", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "7.2.4", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "dev": true, + "license": "ISC" + }, + "node_modules/are-we-there-yet": { + "version": "1.1.7", + "dev": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "2.3.7", + "dev": true, + "license": "MIT", + "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/are-we-there-yet/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/are-we-there-yet/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-includes": { + "version": "3.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async-lock": { + "version": "1.3.1", + "license": "MIT" + }, + "node_modules/async-mutex": { + "version": "0.3.2", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/babel-jest": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "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/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "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-plugin-polyfill-corejs2": { + "version": "0.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "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.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.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/babel-runtime": { + "version": "6.26.0", + "license": "MIT", + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "node_modules/babel-runtime/node_modules/regenerator-runtime": { + "version": "0.11.1", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bip39": { + "version": "3.0.4", + "license": "ISC", + "dependencies": { + "@types/node": "11.11.6", + "create-hash": "^1.1.0", + "pbkdf2": "^3.0.9", + "randombytes": "^2.0.1" + } + }, + "node_modules/bip39/node_modules/@types/node": { + "version": "11.11.6", + "license": "MIT" + }, + "node_modules/bitset": { + "version": "5.1.1", + "license": "MIT OR GPL-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "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" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/browserslist": { + "version": "4.20.3", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/call-bind": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001340", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/canonicalize": { + "version": "1.0.8", + "license": "Apache-2.0" + }, + "node_modules/catering": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/check-more-types": { + "version": "2.24.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.10", + "license": "MIT", + "dependencies": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "1.6.0", + "license": "BSD-2-Clause", + "dependencies": { + "css-select": "^4.3.0", + "css-what": "^6.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.3.1", + "domutils": "^2.8.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "dev": true, + "license": "ISC" + }, + "node_modules/ci-info": { + "version": "3.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/clean-git-ref": { + "version": "2.0.1", + "license": "Apache-2.0" + }, + "node_modules/cliui": { + "version": "7.0.4", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/co": { + "version": "4.6.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/convert-source-map/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/core-js": { + "version": "2.6.12", + "hasInstallScript": true, + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.20.3", + "semver": "7.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat/node_modules/semver": { + "version": "7.0.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/crc-32": { + "version": "1.2.2", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "license": "MIT", + "dependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "dev": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deferred-leveldown": { + "version": "7.0.0", + "license": "MIT", + "dependencies": { + "abstract-leveldown": "^7.2.0", + "inherits": "^2.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/define-properties": { + "version": "1.1.4", + "license": "MIT", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/diff3": { + "version": "0.0.3", + "license": "MIT" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domexception": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/domhandler": { + "version": "4.3.1", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.137", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.8.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "license": "MIT" + }, + "node_modules/encoding-down": { + "version": "7.1.0", + "license": "MIT", + "dependencies": { + "abstract-leveldown": "^7.2.0", + "inherits": "^2.0.3", + "level-codec": "^10.0.0", + "level-errors": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/encryptedfs": { + "version": "3.5.3", + "license": "Apache-2.0", + "dependencies": { + "@matrixai/async-init": "^1.7.3", + "@matrixai/async-locks": "^2.2.4", + "@matrixai/db": "^4.0.2", + "@matrixai/errors": "^1.1.1", + "@matrixai/logger": "^2.1.1", + "@matrixai/resources": "^1.1.3", + "@matrixai/workers": "^1.3.3", + "errno": "^0.1.7", + "lexicographic-integer": "^1.1.0", + "node-forge": "^1.3.1", + "readable-stream": "^3.6.0", + "resource-counter": "^1.2.4", + "threads": "^1.6.5", + "util-callbackify": "^1.0.0" + } + }, + "node_modules/encryptedfs/node_modules/@matrixai/db": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-4.0.5.tgz", + "integrity": "sha512-X3gBcyPxC+bTEfi1J1Y49n1bglvg7HjM8MKNH5s+OUEswqKSZgeg1uWfXqvUqq72yjBtgRi4Ghmy4MdrIB1oMw==", + "dependencies": { + "@matrixai/async-init": "^1.7.3", + "@matrixai/errors": "^1.1.1", + "@matrixai/logger": "^2.1.1", + "@matrixai/resources": "^1.1.3", + "@matrixai/workers": "^1.3.3", + "@types/abstract-leveldown": "^7.2.0", + "level": "7.0.1", + "threads": "^1.6.5" + } + }, + "node_modules/encryptedfs/node_modules/node-forge": { + "version": "1.3.1", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "license": "MIT", + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.20.0", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.1", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.0.0", + "dev": true, + "license": "BSD-2-Clause", + "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.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint/eslintrc": "^1.2.3", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.5.0", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.3", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/find-up": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/locate-path": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-limit": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-locate": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-try": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/path-exists": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.26.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "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/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/eslint/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esm": { + "version": "3.2.25", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/espree": { + "version": "9.3.2", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "dev": true, + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/expect": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-fuzzy": { + "version": "1.11.1", + "license": "ISC", + "dependencies": { + "graphemesplit": "^2.4.1" + } + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.13.0", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fd-lock": { + "version": "1.2.0", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-macros": "^2.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "dev": true, + "license": "ISC" + }, + "node_modules/form-data": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/from2/node_modules/readable-stream": { + "version": "2.3.7", + "dev": true, + "license": "MIT", + "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/from2/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/from2/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "2.7.4", + "dev": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/glob": { + "version": "7.2.0", + "dev": true, + "license": "ISC", + "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": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-protobuf": { + "version": "3.20.1", + "license": "BSD-3-Clause" + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemesplit": { + "version": "2.4.4", + "license": "MIT", + "dependencies": { + "js-base64": "^3.6.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/grpc_tools_node_protoc_ts": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "google-protobuf": "3.15.8", + "handlebars": "4.7.7" + }, + "bin": { + "protoc-gen-ts": "bin/protoc-gen-ts" + } + }, + "node_modules/grpc_tools_node_protoc_ts/node_modules/google-protobuf": { + "version": "3.15.8", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/handlebars": { + "version": "4.7.7", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has": { + "version": "1.0.3", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/hash-base": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.2.0", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "dev": true, + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/into-stream": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ip-num": { + "version": "1.4.0", + "license": "MIT" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.4", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-observable": { + "version": "2.1.0", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.1.4", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/isomorphic-git": { + "version": "1.17.2", + "license": "MIT", + "dependencies": { + "async-lock": "^1.1.0", + "clean-git-ref": "^2.0.1", + "crc-32": "^1.2.0", + "diff3": "0.0.3", + "ignore": "^5.1.4", + "minimisted": "^2.0.0", + "pako": "^1.0.10", + "pify": "^4.0.1", + "readable-stream": "^3.4.0", + "sha.js": "^2.4.9", + "simple-get": "^4.0.1" + }, + "bin": { + "isogit": "cli.cjs" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "dev": true, + "license": "BSD-3-Clause", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.4", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + }, + "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.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "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-circus": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "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/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-circus/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "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-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-cli/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "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/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-docblock": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "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.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-each/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "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-jasmine2": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-jasmine2/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-jasmine2/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-jasmine2/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "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/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-mock-process": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "peerDependencies": { + "jest": ">=23.4 <28" + } + }, + "node_modules/jest-mock-props": { + "version": "1.9.1", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "jest": ">=24.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.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.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "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/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-serializer": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@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.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.3.7", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "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/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jose": { + "version": "4.8.1", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-base64": { + "version": "3.7.2", + "license": "BSD-3-Clause" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "16.7.0", + "dev": true, + "license": "MIT", + "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.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lazy-ass": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "> 0.8" + } + }, + "node_modules/level": { + "version": "7.0.1", + "license": "MIT", + "dependencies": { + "level-js": "^6.1.0", + "level-packager": "^6.0.1", + "leveldown": "^6.1.0" + }, + "engines": { + "node": ">=10.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" + } + }, + "node_modules/level-codec": { + "version": "10.0.0", + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/level-concat-iterator": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "catering": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/level-errors": { + "version": "3.0.1", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/level-iterator-stream": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/level-js": { + "version": "6.1.0", + "license": "MIT", + "dependencies": { + "abstract-leveldown": "^7.2.0", + "buffer": "^6.0.3", + "inherits": "^2.0.3", + "ltgt": "^2.1.2", + "run-parallel-limit": "^1.1.0" + } + }, + "node_modules/level-packager": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "encoding-down": "^7.1.0", + "levelup": "^5.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/level-supports": { + "version": "2.1.0", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/leveldown": { + "version": "6.1.1", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "abstract-leveldown": "^7.2.0", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/levelup": { + "version": "5.1.1", + "license": "MIT", + "dependencies": { + "catering": "^2.0.0", + "deferred-leveldown": "^7.0.0", + "level-errors": "^3.0.1", + "level-iterator-stream": "^5.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lexicographic-integer": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/long": { + "version": "4.0.0", + "license": "Apache-2.0" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ltgt": { + "version": "2.2.1", + "license": "MIT" + }, + "node_modules/lunr": { + "version": "2.3.9", + "dev": true, + "license": "MIT" + }, + "node_modules/make-dir": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/marked": { + "version": "4.0.15", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "license": "MIT" + }, + "node_modules/minimisted": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "dev": true, + "license": "MIT" + }, + "node_modules/mocked-env": { + "version": "1.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "check-more-types": "2.24.0", + "debug": "4.3.2", + "lazy-ass": "1.6.0", + "ramda": "0.27.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocked-env/node_modules/debug": { + "version": "4.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/multiformats": { + "version": "9.6.5", + "license": "(Apache-2.0 AND MIT)" + }, + "node_modules/multistream": { + "version": "4.1.0", + "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" + } + ], + "license": "MIT", + "dependencies": { + "once": "^1.4.0", + "readable-stream": "^3.6.0" + } + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/napi-macros": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/nexpect": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^6.0.5" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/nexpect/node_modules/cross-spawn": { + "version": "6.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/nexpect/node_modules/path-key": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/nexpect/node_modules/semver": { + "version": "5.7.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nexpect/node_modules/shebang-command": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nexpect/node_modules/shebang-regex": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nexpect/node_modules/which": { + "version": "1.3.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/node-abi": { + "version": "2.30.1", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.4.1" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "5.7.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-forge": { + "version": "0.10.0", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.4.0", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.0.1", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nwsapi": { + "version": "2.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.0", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/observable-fns": { + "version": "0.6.1", + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "dev": true, + "license": "MIT", + "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-is-promise": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "license": "MIT" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "license": "MIT", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg": { + "version": "5.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "7.16.2", + "@babel/types": "7.16.0", + "chalk": "^4.1.2", + "escodegen": "^2.0.0", + "fs-extra": "^9.1.0", + "globby": "^11.0.4", + "into-stream": "^6.0.0", + "minimist": "^1.2.5", + "multistream": "^4.1.0", + "pkg-fetch": "3.3.0", + "prebuild-install": "6.1.4", + "progress": "^2.0.3", + "resolve": "^1.20.0", + "stream-meter": "^1.0.4", + "tslib": "2.3.1" + }, + "bin": { + "pkg": "lib-es5/bin.js" + }, + "peerDependencies": { + "node-notifier": ">=9.0.1" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-fetch": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "fs-extra": "^9.1.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.6", + "progress": "^2.0.3", + "semver": "^7.3.5", + "tar-fs": "^2.1.1", + "yargs": "^16.2.0" + }, + "bin": { + "pkg-fetch": "lib-es5/bin.js" + } + }, + "node_modules/pkg-fetch/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pkg-fetch/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/pkg-fetch/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pkg-fetch/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/pkg-fetch/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-fetch/node_modules/semver": { + "version": "7.3.7", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pkg-fetch/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg/node_modules/@babel/parser": { + "version": "7.16.2", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pkg/node_modules/@babel/types": { + "version": "7.16.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.15.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/pkg/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pkg/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/pkg/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pkg/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/pkg/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg/node_modules/tslib": { + "version": "2.3.1", + "dev": true, + "license": "0BSD" + }, + "node_modules/prebuild-install": { + "version": "6.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.21.0", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prebuild-install/node_modules/decompress-response": { + "version": "4.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prebuild-install/node_modules/mimic-response": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prebuild-install/node_modules/simple-get": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.6.2", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "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/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/protobufjs": { + "version": "6.11.3", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/psl": { + "version": "1.8.0", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/ramda": { + "version": "0.27.1", + "dev": true, + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.6.0", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.8.4", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/resource-counter": { + "version": "1.2.4", + "license": "Apache-2.0", + "dependencies": { + "babel-runtime": "^6.26.0", + "bitset": "^5.0.3" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "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" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-parallel-limit": { + "version": "1.1.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "5.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "0.10.1", + "dev": true, + "license": "MIT", + "dependencies": { + "jsonc-parser": "^3.0.0", + "vscode-oniguruma": "^1.6.1", + "vscode-textmate": "5.2.0" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stream-meter": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.1.4" + } + }, + "node_modules/stream-meter/node_modules/readable-stream": { + "version": "2.3.7", + "dev": true, + "license": "MIT", + "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/stream-meter/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/stream-meter/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "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", + "dev": true, + "license": "MIT" + }, + "node_modules/threads": { + "version": "1.7.0", + "license": "MIT", + "dependencies": { + "callsites": "^3.1.0", + "debug": "^4.2.0", + "is-observable": "^2.1.0", + "observable-fns": "^0.6.1" + }, + "funding": { + "url": "https://github.com/andywer/threads.js?sponsor=1" + }, + "optionalDependencies": { + "tiny-worker": ">= 2" + } + }, + "node_modules/throat": { + "version": "6.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/timeout-refresh": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/tiny-worker": { + "version": "2.3.0", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "esm": "^3.2.25" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.0.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-custom-error": { + "version": "3.2.0", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/ts-jest": { + "version": "27.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "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": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@types/jest": "^27.0.0", + "babel-jest": ">=27.0.0 <28", + "jest": "^27.0.0", + "typescript": ">=3.8 <5.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.3.7", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node": { + "version": "10.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "0.7.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.0", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "license": "0BSD" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "dev": true, + "license": "0BSD" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typedoc": { + "version": "0.22.15", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "glob": "^7.2.0", + "lunr": "^2.3.9", + "marked": "^4.0.12", + "minimatch": "^5.0.1", + "shiki": "^0.10.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 12.10.0" + }, + "peerDependencies": { + "typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "5.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typescript": { + "version": "4.6.4", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uglify-js": { + "version": "3.15.5", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unordered-set": { + "version": "2.0.1", + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-callbackify": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/utp-native": { + "version": "2.5.3", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-macros": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.0.2", + "timeout-refresh": "^1.0.0", + "unordered-set": "^2.0.1" + }, + "bin": { + "ucat": "ucat.js" + }, + "engines": { + "node": ">=8.12" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "dev": true, + "license": "ISC", + "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", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-textmate": { + "version": "5.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=10.4" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "license": "MIT", + "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", + "license": "MIT", + "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", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "dev": true, + "license": "ISC", + "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.5.7", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "16.2.0", + "license": "MIT", + "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", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + } + }, "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" } }, "@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "version": "7.17.10", "dev": true }, "@babel/core": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", - "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.15.8", - "@babel/generator": "^7.15.8", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.8", - "@babel/helpers": "^7.15.4", - "@babel/parser": "^7.15.8", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6", + "version": "7.17.10", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.9", + "@babel/parser": "^7.17.10", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.10", + "@babel/types": "^7.17.10", "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" + "json5": "^2.2.1", + "semver": "^6.3.0" } }, "@babel/generator": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", - "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", + "version": "7.17.10", "dev": true, "requires": { - "@babel/types": "^7.15.6", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.17.10", + "@jridgewell/gen-mapping": "^0.1.0", + "jsesc": "^2.5.1" } }, "@babel/helper-annotate-as-pure": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz", - "integrity": "sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.15.4.tgz", - "integrity": "sha512-P8o7JP2Mzi0SdC6eWr1zF+AEYvrsZa7GSY1lTayjF5XJhVH0kjLYUZPvTMflP7tBgZoe9gIhTa60QwFpqh/E0Q==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-compilation-targets": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", - "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", + "version": "7.17.10", "dev": true, "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", + "@babel/compat-data": "^7.17.10", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.20.2", "semver": "^6.3.0" } }, "@babel/helper-create-class-features-plugin": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.4.tgz", - "integrity": "sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw==", + "version": "7.17.9", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", + "version": "7.17.0", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "regexpu-core": "^4.7.1" + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" } }, "@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "version": "0.3.1", "dev": true, "requires": { "@babel/helper-compilation-targets": "^7.13.0", @@ -124,368 +10782,301 @@ "semver": "^6.1.2" } }, - "@babel/helper-explode-assignable-expression": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.15.4.tgz", - "integrity": "sha512-J14f/vq8+hdC2KoWLIQSsGrC9EFBKE4NFts8pfMpymfApds+fPqR30AOUWc4tyr56h9l/GA1Sxv2q3dLZWbQ/g==", + "@babel/helper-environment-visitor": { + "version": "7.16.7", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, - "@babel/helper-function-name": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "@babel/helper-explode-assignable-expression": { + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, - "@babel/helper-get-function-arity": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "@babel/helper-function-name": { + "version": "7.17.9", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/template": "^7.16.7", + "@babel/types": "^7.17.0" } }, "@babel/helper-hoist-variables": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", - "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", + "version": "7.17.7", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.17.0" } }, "@babel/helper-module-imports": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", - "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-transforms": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", - "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", + "version": "7.17.7", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-simple-access": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" } }, "@babel/helper-optimise-call-expression": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", - "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, "@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==", + "version": "7.16.7", "dev": true }, "@babel/helper-remap-async-to-generator": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz", - "integrity": "sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ==", + "version": "7.16.8", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-wrap-function": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helper-replace-supers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", - "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-simple-access": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", - "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "version": "7.17.7", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.17.0" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.15.4.tgz", - "integrity": "sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A==", + "version": "7.16.0", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.0" } }, "@babel/helper-split-export-declaration": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "version": "7.16.7", "dev": true }, "@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==", + "version": "7.16.7", "dev": true }, "@babel/helper-wrap-function": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.15.4.tgz", - "integrity": "sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw==", + "version": "7.16.8", "dev": true, "requires": { - "@babel/helper-function-name": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helpers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", - "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "version": "7.17.9", "dev": true, "requires": { - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0" } }, "@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==", + "version": "7.17.9", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.16.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", - "integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", + "version": "7.17.10", "dev": true }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.16.7", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.15.4.tgz", - "integrity": "sha512-eBnpsl9tlhPhpI10kU06JHnrYXwg3+V6CaP2idsCXNef0aeslpqyITXQ74Vfk5uHgY7IG7XP0yIH8b42KSzHog==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4", - "@babel/plugin-proposal-optional-chaining": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.7" } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.8.tgz", - "integrity": "sha512-2Z5F2R2ibINTc63mY7FLqGfEbmofrHU9FitJW1Q7aPaKFhiPvSq6QEt/BoWN5oME3GVyjcRuNNSRbb9LC0CSWA==", + "version": "7.16.8", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.15.4", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz", - "integrity": "sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-proposal-class-static-block": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.15.4.tgz", - "integrity": "sha512-M682XWrrLNk3chXCjoPUQWOyYsB93B9z3mRyjtqqYJWDf2mfCdIYgDrA11cgNVhAQieaq6F2fn2f3wI0U4aTjA==", + "version": "7.17.6", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.17.6", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz", - "integrity": "sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz", - "integrity": "sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz", - "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz", - "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz", - "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz", - "integrity": "sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.15.6.tgz", - "integrity": "sha512-qtOHo7A1Vt+O23qEAX+GdBpqaIuD3i9VRrWgCJeq7WO6H2d14EK3q11urj5Te2MAeK97nMiIdRpwd/ST4JFbNg==", + "version": "7.17.3", "dev": true, "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/compat-data": "^7.17.0", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.15.4" + "@babel/plugin-transform-parameters": "^7.16.7" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", - "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz", - "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz", - "integrity": "sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==", + "version": "7.16.11", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.10", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.15.4.tgz", - "integrity": "sha512-X0UTixkLf0PCCffxgu5/1RQyGGbgZuKoI+vXP4iSbJSYwPb7hu06omsFGBvQ9lJEvwgrxHdS8B5nbfcd8GyUNA==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-create-class-features-plugin": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz", - "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -493,8 +11084,6 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -502,8 +11091,6 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.12.13" @@ -511,8 +11098,6 @@ }, "@babel/plugin-syntax-class-static-block": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" @@ -520,8 +11105,6 @@ }, "@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -529,8 +11112,6 @@ }, "@babel/plugin-syntax-export-namespace-from": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.3" @@ -538,8 +11119,6 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.10.4" @@ -547,8 +11126,6 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -556,8 +11133,6 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.10.4" @@ -565,8 +11140,6 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -574,8 +11147,6 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.10.4" @@ -583,8 +11154,6 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -592,8 +11161,6 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -601,8 +11168,6 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -610,8 +11175,6 @@ }, "@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" @@ -619,351 +11182,293 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.14.5" } }, + "@babel/plugin-syntax-typescript": { + "version": "7.17.10", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, "@babel/plugin-transform-arrow-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", - "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", - "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", + "version": "7.16.8", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5" + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", - "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz", - "integrity": "sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-classes": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.15.4.tgz", - "integrity": "sha512-Yjvhex8GzBmmPQUvpXRPWQ9WnxXgAFuZSrqOK/eJlOGIXwvv8H3UEdUigl1gb/bnjTrln+e8bkZUYCBt/xYlBg==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", - "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-destructuring": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", - "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", + "version": "7.17.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz", - "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz", - "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", - "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-for-of": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.15.4.tgz", - "integrity": "sha512-DRTY9fA751AFBDh2oxydvVm4SYevs5ILTWLs6xKXps4Re/KG5nfUkr+TdHCrRWB8C69TlzVgA9b3RmGWmgN9LA==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz", - "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", - "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz", - "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz", - "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.4.tgz", - "integrity": "sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA==", + "version": "7.17.9", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.15.4.tgz", - "integrity": "sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw==", + "version": "7.17.8", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz", - "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz", - "integrity": "sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==", + "version": "7.17.10", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.17.0" } }, "@babel/plugin-transform-new-target": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz", - "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-object-super": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", - "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" } }, "@babel/plugin-transform-parameters": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.15.4.tgz", - "integrity": "sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-property-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", - "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-regenerator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", - "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", + "version": "7.17.9", "dev": true, "requires": { - "regenerator-transform": "^0.14.2" + "regenerator-transform": "^0.15.0" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz", - "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", - "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-spread": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.15.8.tgz", - "integrity": "sha512-/daZ8s2tNaRekl9YJa9X4bzjpeRZLt122cpgFnQPLGUe61PH8zMEBmYqKkW5xF5JUEh5buEGXJoQpqBmIbpmEQ==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", - "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-template-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", - "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", - "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz", - "integrity": "sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", - "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/preset-env": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.8.tgz", - "integrity": "sha512-rCC0wH8husJgY4FPbHsiYyiLxSY8oMDJH7Rl6RQMknbN9oDDHhM9RDFvnGM2MgkbUJzSQB4gtuwygY5mCqGSsA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.15.4", - "@babel/plugin-proposal-async-generator-functions": "^7.15.8", - "@babel/plugin-proposal-class-properties": "^7.14.5", - "@babel/plugin-proposal-class-static-block": "^7.15.4", - "@babel/plugin-proposal-dynamic-import": "^7.14.5", - "@babel/plugin-proposal-export-namespace-from": "^7.14.5", - "@babel/plugin-proposal-json-strings": "^7.14.5", - "@babel/plugin-proposal-logical-assignment-operators": "^7.14.5", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", - "@babel/plugin-proposal-numeric-separator": "^7.14.5", - "@babel/plugin-proposal-object-rest-spread": "^7.15.6", - "@babel/plugin-proposal-optional-catch-binding": "^7.14.5", - "@babel/plugin-proposal-optional-chaining": "^7.14.5", - "@babel/plugin-proposal-private-methods": "^7.14.5", - "@babel/plugin-proposal-private-property-in-object": "^7.15.4", - "@babel/plugin-proposal-unicode-property-regex": "^7.14.5", + "version": "7.17.10", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-async-generator-functions": "^7.16.8", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-proposal-class-static-block": "^7.17.6", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.16.7", + "@babel/plugin-proposal-json-strings": "^7.16.7", + "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.17.3", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-private-methods": "^7.16.11", + "@babel/plugin-proposal-private-property-in-object": "^7.16.7", + "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", @@ -978,51 +11483,49 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.14.5", - "@babel/plugin-transform-async-to-generator": "^7.14.5", - "@babel/plugin-transform-block-scoped-functions": "^7.14.5", - "@babel/plugin-transform-block-scoping": "^7.15.3", - "@babel/plugin-transform-classes": "^7.15.4", - "@babel/plugin-transform-computed-properties": "^7.14.5", - "@babel/plugin-transform-destructuring": "^7.14.7", - "@babel/plugin-transform-dotall-regex": "^7.14.5", - "@babel/plugin-transform-duplicate-keys": "^7.14.5", - "@babel/plugin-transform-exponentiation-operator": "^7.14.5", - "@babel/plugin-transform-for-of": "^7.15.4", - "@babel/plugin-transform-function-name": "^7.14.5", - "@babel/plugin-transform-literals": "^7.14.5", - "@babel/plugin-transform-member-expression-literals": "^7.14.5", - "@babel/plugin-transform-modules-amd": "^7.14.5", - "@babel/plugin-transform-modules-commonjs": "^7.15.4", - "@babel/plugin-transform-modules-systemjs": "^7.15.4", - "@babel/plugin-transform-modules-umd": "^7.14.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.9", - "@babel/plugin-transform-new-target": "^7.14.5", - "@babel/plugin-transform-object-super": "^7.14.5", - "@babel/plugin-transform-parameters": "^7.15.4", - "@babel/plugin-transform-property-literals": "^7.14.5", - "@babel/plugin-transform-regenerator": "^7.14.5", - "@babel/plugin-transform-reserved-words": "^7.14.5", - "@babel/plugin-transform-shorthand-properties": "^7.14.5", - "@babel/plugin-transform-spread": "^7.15.8", - "@babel/plugin-transform-sticky-regex": "^7.14.5", - "@babel/plugin-transform-template-literals": "^7.14.5", - "@babel/plugin-transform-typeof-symbol": "^7.14.5", - "@babel/plugin-transform-unicode-escapes": "^7.14.5", - "@babel/plugin-transform-unicode-regex": "^7.14.5", - "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.15.6", - "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.5", - "babel-plugin-polyfill-regenerator": "^0.2.2", - "core-js-compat": "^3.16.0", + "@babel/plugin-transform-arrow-functions": "^7.16.7", + "@babel/plugin-transform-async-to-generator": "^7.16.8", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.16.7", + "@babel/plugin-transform-classes": "^7.16.7", + "@babel/plugin-transform-computed-properties": "^7.16.7", + "@babel/plugin-transform-destructuring": "^7.17.7", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.16.7", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.16.7", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.16.7", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.17.9", + "@babel/plugin-transform-modules-systemjs": "^7.17.8", + "@babel/plugin-transform-modules-umd": "^7.16.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.10", + "@babel/plugin-transform-new-target": "^7.16.7", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.16.7", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.17.9", + "@babel/plugin-transform-reserved-words": "^7.16.7", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.16.7", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.16.7", + "@babel/plugin-transform-typeof-symbol": "^7.16.7", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.17.10", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.22.1", "semver": "^6.3.0" } }, "@babel/preset-modules": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "version": "0.1.5", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -1033,112 +11536,77 @@ } }, "@babel/runtime": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", - "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "version": "7.17.9", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - } } }, "@babel/template": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "version": "7.16.7", "dev": true, "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/traverse": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.17.10", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.10", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.10", + "@babel/types": "^7.17.10", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", - "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", + "version": "7.17.10", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" } }, "@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 }, - "@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, "@cspotcode/source-map-consumer": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", "dev": true }, "@cspotcode/source-map-support": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", "dev": true, "requires": { "@cspotcode/source-map-consumer": "0.8.0" } }, "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "1.2.3", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", + "debug": "^4.3.2", + "espree": "^9.3.2", "globals": "^13.9.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "dependencies": { "ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -1147,58 +11615,66 @@ "uri-js": "^4.2.2" } }, + "argparse": { + "version": "2.0.1", + "dev": true + }, "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.15.0", "dev": true, "requires": { "type-fest": "^0.20.2" } }, - "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 + "js-yaml": { + "version": "4.1.0", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } }, "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 + }, + "type-fest": { + "version": "0.20.2", "dev": true } } }, "@grpc/grpc-js": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.3.7.tgz", - "integrity": "sha512-CKQVuwuSPh40tgOkR7c0ZisxYRiN05PcKPW72mQL5y++qd7CwBRoaJZvU5xfXnCJDFBmS3qZGQ71Frx6Ofo2XA==", + "version": "1.6.7", "requires": { + "@grpc/proto-loader": "^0.6.4", "@types/node": ">=12.12.47" } }, + "@grpc/proto-loader": { + "version": "0.6.12", + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.10.0", + "yargs": "^16.2.0" + } + }, "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.9.5", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.0", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", "minimatch": "^3.0.4" } }, "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "version": "1.2.1", "dev": true }, "@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, "requires": { "camelcase": "^5.3.1", @@ -1210,44 +11686,52 @@ }, "@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 }, "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -1256,61 +11740,71 @@ } }, "@jest/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@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": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -1319,140 +11813,99 @@ } }, "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^26.6.2" + "jest-mock": "^27.5.1" } }, "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" } }, "@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" } }, "@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "version": "27.5.1", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", "glob": "^7.1.2", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "node-notifier": "^8.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" + "v8-to-istanbul": "^8.1.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, - "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 - }, - "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==", + "color-convert": { + "version": "2.0.1", "dev": true, "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "color-name": "~1.1.4" } }, - "node-notifier": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", - "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", - "dev": true, - "optional": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" - }, - "dependencies": { - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "optional": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } + "color-name": { + "version": "1.1.4", + "dev": true }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "has-flag": { + "version": "4.0.0", "dev": true }, "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, "requires": { "has-flag": "^4.0.0" @@ -1461,98 +11914,87 @@ } }, "@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", + "version": "27.5.1", "dev": true, "requires": { "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "source-map": "^0.6.0" - }, - "dependencies": { - "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 - } } }, "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" } }, "@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "version": "27.5.1", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", - "babel-plugin-istanbul": "^6.0.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", "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": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", "slash": "^3.0.0", "source-map": "^0.6.1", "write-file-atomic": "^3.0.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", "dev": true }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "has-flag": { + "version": "4.0.0", "dev": true }, "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, "requires": { "has-flag": "^4.0.0" @@ -1561,38 +12003,48 @@ } }, "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "version": "27.5.1", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^15.0.0", + "@types/yargs": "^16.0.0", "chalk": "^4.0.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -1600,82 +12052,94 @@ } } }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.0.7", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.1", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.13", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@matrixai/async-init": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.7.1.tgz", - "integrity": "sha512-3ELRuEn6AoC3e0b4QccA+NxZl0LilyjYeu6a3Pf9VUVB89EepnNKsk/Afb9qa+B5LvLQwmgHtg4r9VwRpQpnQA==", + "version": "1.7.3", "requires": { - "@matrixai/async-locks": "^2.2.0", - "@matrixai/errors": "^1.0.1" + "@matrixai/async-locks": "^2.2.4", + "@matrixai/errors": "^1.1.1" } }, "@matrixai/async-locks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.2.0.tgz", - "integrity": "sha512-i0a551EUMhD1WKpaAyhBUt83ckbOxPB4MlOH8VDzeDyPMAtLI9egCqf3HWOvhN0rSjoH97EmzmfxyAeAgiQzTw==", + "version": "2.2.5", "requires": { - "@matrixai/errors": "^1.0.1", - "@matrixai/resources": "^1.0.0", + "@matrixai/errors": "^1.1.1", + "@matrixai/resources": "^1.1.3", "async-mutex": "^0.3.2" } }, "@matrixai/db": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.3.1.tgz", - "integrity": "sha512-EQulm82sBhw1WRhOzzWMoij1SwpjAQHgyokxleTwFHoAnDPMi4WVy4AIxd2lJMPOhhzEFQxCqQmmMYhZWwYAPg==", - "requires": { - "@matrixai/async-init": "^1.7.0", - "@matrixai/errors": "^1.0.1", - "@matrixai/logger": "^2.1.0", - "@matrixai/resources": "^1.0.0", - "@matrixai/workers": "^1.3.0", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.3.4.tgz", + "integrity": "sha512-iRuwT+jbCZ4om5tbiUvaoYTRBfA6soULYmyqV0n2Av7gayiRhP7e0tEcxI3VFue4xuO1KPCsZjSTwcFXesHP0g==", + "requires": { + "@matrixai/async-init": "^1.7.3", + "@matrixai/errors": "^1.1.1", + "@matrixai/logger": "^2.1.1", + "@matrixai/resources": "^1.1.3", + "@matrixai/workers": "^1.3.3", "@types/abstract-leveldown": "^7.2.0", "level": "7.0.1", "threads": "^1.6.5" } }, "@matrixai/errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.0.1.tgz", - "integrity": "sha512-9NbIm3rPMkZz+Ma5tfKduVCWfvYzdHlO89u9mBap7FzJqXkl4yoENjMZm5Do6PvhtIYtRcm6+eTgWvHd6pkdGg==", + "version": "1.1.1", "requires": { "ts-custom-error": "^3.2.0" } }, "@matrixai/id": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@matrixai/id/-/id-3.3.2.tgz", - "integrity": "sha512-gpW56P7jZILPc0oxyNQvZBkEBn30JPGpslOHIcDoKnCZR8VGZXEKX485xy1WE4MBiQHXdGeiYF8A2CluqTnu3w==", + "version": "3.3.3", "requires": { "multiformats": "^9.4.8", "uuid": "^8.3.2" } }, "@matrixai/logger": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.1.0.tgz", - "integrity": "sha512-UmLuXi2PJ03v0Scfl57217RPnjEZDRLlpfdIjIwCfju+kofnhhCI9P7OZu3/FgW147vbvSzWCrrtpwJiLROUUA==" + "version": "2.1.1" }, "@matrixai/resources": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@matrixai/resources/-/resources-1.0.0.tgz", - "integrity": "sha512-B1ZkySZwOZTIzhK+YTN4HifOTd1dk1ifDUV8/8WgGho2nUZzIMYms7iDmW/ZHUCkqvWupKY6AYvfwnKBOJJnWg==" + "version": "1.1.3" }, "@matrixai/workers": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@matrixai/workers/-/workers-1.3.1.tgz", - "integrity": "sha512-AXI37aZ7gSqS5PpUCG7/yfNcnWNYiQUp4yFBY1Z9lKk0zrkQzND1zPjDuJ2E7t6E1a4rwa8vtysj5TVeMCA8jw==", + "version": "1.3.3", "requires": { - "@matrixai/async-init": "^1.7.0", - "@matrixai/errors": "^1.0.1", - "@matrixai/logger": "^2.1.0", + "@matrixai/async-init": "^1.7.3", + "@matrixai/errors": "^1.1.1", + "@matrixai/logger": "^2.1.1", "threads": "^1.6.5" } }, "@nodelib/fs.scandir": { "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "requires": { "@nodelib/fs.stat": "2.0.5", @@ -1684,33 +12148,59 @@ }, "@nodelib/fs.stat": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true }, "@nodelib/fs.walk": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, + "@protobufjs/aspromise": { + "version": "1.1.2" + }, + "@protobufjs/base64": { + "version": "1.1.2" + }, + "@protobufjs/codegen": { + "version": "2.0.4" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2" + }, + "@protobufjs/inquire": { + "version": "1.1.0" + }, + "@protobufjs/path": { + "version": "1.1.2" + }, + "@protobufjs/pool": { + "version": "1.1.0" + }, + "@protobufjs/utf8": { + "version": "1.1.0" + }, "@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, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "version": "8.1.0", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" @@ -1718,43 +12208,29 @@ }, "@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 }, "@tsconfig/node10": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", "dev": true }, "@tsconfig/node12": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", "dev": true }, "@tsconfig/node14": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", "dev": true }, "@tsconfig/node16": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, "@types/abstract-leveldown": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", - "integrity": "sha512-q5veSX6zjUy/DlDhR4Y4cU0k2Ar+DT2LUraP00T19WLmTO6Se1djepCCaqU6nQrwcJ5Hyo/CWqxTzrrFg8eqbQ==" + "version": "7.2.0" }, "@types/babel__core": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", - "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", + "version": "7.1.19", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -1765,9 +12241,7 @@ } }, "@types/babel__generator": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", - "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "version": "7.6.4", "dev": true, "requires": { "@babel/types": "^7.0.0" @@ -1775,8 +12249,6 @@ }, "@types/babel__template": { "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -1784,9 +12256,7 @@ } }, "@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "version": "7.17.1", "dev": true, "requires": { "@babel/types": "^7.3.0" @@ -1794,38 +12264,28 @@ }, "@types/cross-spawn": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.2.tgz", - "integrity": "sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==", "dev": true, "requires": { "@types/node": "*" } }, "@types/google-protobuf": { - "version": "3.15.5", - "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.5.tgz", - "integrity": "sha512-6bgv24B+A2bo9AfzReeg5StdiijKzwwnRflA8RLd1V4Yv995LeTmo0z69/MPbBDFSiZWdZHQygLo/ccXhMEDgw==", + "version": "3.15.6", "dev": true }, "@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, "requires": { "@types/node": "*" } }, "@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==", + "version": "2.0.4", "dev": true }, "@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, "requires": { "@types/istanbul-lib-coverage": "*" @@ -1833,89 +12293,64 @@ }, "@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, "requires": { "@types/istanbul-lib-report": "*" } }, "@types/jest": { - "version": "26.0.24", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", - "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", + "version": "27.5.1", "dev": true, "requires": { - "jest-diff": "^26.0.0", - "pretty-format": "^26.0.0" + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" } }, "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "version": "7.0.11", "dev": true }, "@types/json5": { "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/long": { + "version": "4.0.2" + }, "@types/nexpect": { "version": "0.4.31", - "resolved": "https://registry.npmjs.org/@types/nexpect/-/nexpect-0.4.31.tgz", - "integrity": "sha512-Plh9Dlj2AKdsblgF1Pv7s2BjlojqW93d1zIUtK5xVVrUjkZQezyWIOAq0Xfwp0e0SDQ70YmaDqzhoJru2kqVPA==", "dev": true, "requires": { "@types/node": "*" } }, "@types/node": { - "version": "16.11.29", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.29.tgz", - "integrity": "sha512-9dDdonLyPJQJ/kdOlDxAah+bTI+u2ccF3k62FErhquDuggoCX6piWez7j7o6yNE+rP2IRcZVQ6Tw4N0P38+rWA==" + "version": "16.11.35" }, "@types/node-forge": { "version": "0.9.10", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-0.9.10.tgz", - "integrity": "sha512-+BbPlhZeYs/WETWftQi2LeRx9VviWSwawNo+Pid5qNrSZHb60loYjpph3OrbwXMMseadu9rE9NeK34r4BHT+QQ==", "dev": true, "requires": { "@types/node": "*" } }, - "@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "dev": true - }, "@types/pako": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.2.tgz", - "integrity": "sha512-8UJl2MjkqqS6ncpLZqRZ5LmGiFBkbYxocD4e4jmBqGvfRG1RS23gKsBQbdtV9O9GvRyjFTiRHRByjSlKCLlmZw==", + "version": "1.0.4", "dev": true }, "@types/prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", + "version": "2.6.1", "dev": true }, "@types/prompts": { "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.14.tgz", - "integrity": "sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA==", "dev": true, "requires": { "@types/node": "*" } }, "@types/readable-stream": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.11.tgz", - "integrity": "sha512-0z+/apYJwKFz/RHp6mOMxz/y7xOvWPYPevuCEyAY3gXsjtaac02E26RvxA+I96rfvmVH/dEMGXNvyJfViR1FSQ==", + "version": "2.3.13", "dev": true, "requires": { "@types/node": "*", @@ -1924,39 +12359,30 @@ }, "@types/stack-utils": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, "@types/uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==", + "version": "8.3.4", "dev": true }, "@types/yargs": { - "version": "15.0.14", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", - "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "version": "16.0.4", "dev": true, "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "version": "21.0.0", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.4.0.tgz", - "integrity": "sha512-9/yPSBlwzsetCsGEn9j24D8vGQgJkOTr4oMLas/w886ZtzKIs1iyoqFrwsX2fqYEeUwsdBpC21gcjRGo57u0eg==", + "version": "5.23.0", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "5.4.0", - "@typescript-eslint/scope-manager": "5.4.0", + "@typescript-eslint/scope-manager": "5.23.0", + "@typescript-eslint/type-utils": "5.23.0", + "@typescript-eslint/utils": "5.23.0", "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", "ignore": "^5.1.8", @@ -1966,9 +12392,7 @@ }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -1976,56 +12400,43 @@ } } }, - "@typescript-eslint/experimental-utils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.4.0.tgz", - "integrity": "sha512-Nz2JDIQUdmIGd6p33A+naQmwfkU5KVTLb/5lTk+tLVTDacZKoGQisj8UCxk7onJcrgjIvr8xWqkYI+DbI3TfXg==", + "@typescript-eslint/parser": { + "version": "5.23.0", "dev": true, "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.4.0", - "@typescript-eslint/types": "5.4.0", - "@typescript-eslint/typescript-estree": "5.4.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@typescript-eslint/scope-manager": "5.23.0", + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/typescript-estree": "5.23.0", + "debug": "^4.3.2" } }, - "@typescript-eslint/parser": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.4.0.tgz", - "integrity": "sha512-JoB41EmxiYpaEsRwpZEYAJ9XQURPFer8hpkIW9GiaspVLX8oqbqNM8P4EP8HOZg96yaALiLEVWllA2E8vwsIKw==", + "@typescript-eslint/scope-manager": { + "version": "5.23.0", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.4.0", - "@typescript-eslint/types": "5.4.0", - "@typescript-eslint/typescript-estree": "5.4.0", - "debug": "^4.3.2" + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/visitor-keys": "5.23.0" } }, - "@typescript-eslint/scope-manager": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.4.0.tgz", - "integrity": "sha512-pRxFjYwoi8R+n+sibjgF9iUiAELU9ihPBtHzocyW8v8D8G8KeQvXTsW7+CBYIyTYsmhtNk50QPGLE3vrvhM5KA==", + "@typescript-eslint/type-utils": { + "version": "5.23.0", "dev": true, "requires": { - "@typescript-eslint/types": "5.4.0", - "@typescript-eslint/visitor-keys": "5.4.0" + "@typescript-eslint/utils": "5.23.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.4.0.tgz", - "integrity": "sha512-GjXNpmn+n1LvnttarX+sPD6+S7giO+9LxDIGlRl4wK3a7qMWALOHYuVSZpPTfEIklYjaWuMtfKdeByx0AcaThA==", + "version": "5.23.0", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.4.0.tgz", - "integrity": "sha512-nhlNoBdhKuwiLMx6GrybPT3SFILm5Gij2YBdPEPFlYNFAXUJWX6QRgvi/lwVoadaQEFsizohs6aFRMqsXI2ewA==", + "version": "5.23.0", "dev": true, "requires": { - "@typescript-eslint/types": "5.4.0", - "@typescript-eslint/visitor-keys": "5.4.0", + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/visitor-keys": "5.23.0", "debug": "^4.3.2", "globby": "^11.0.4", "is-glob": "^4.0.3", @@ -2034,9 +12445,7 @@ }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -2044,34 +12453,32 @@ } } }, + "@typescript-eslint/utils": { + "version": "5.23.0", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.23.0", + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/typescript-estree": "5.23.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, "@typescript-eslint/visitor-keys": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.4.0.tgz", - "integrity": "sha512-PVbax7MeE7tdLfW5SA0fs8NGVVr+buMPrcj+CWYWPXsZCH8qZ1THufDzbXm1xrZ2b2PA1iENJ0sRq5fuUtvsJg==", + "version": "5.23.0", "dev": true, "requires": { - "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/types": "5.23.0", "eslint-visitor-keys": "^3.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", - "dev": true - } } }, "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "version": "2.0.6", "dev": true }, "abstract-leveldown": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", - "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", "requires": { "buffer": "^6.0.3", "catering": "^2.0.0", @@ -2082,37 +12489,34 @@ } }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.7.1", "dev": true }, "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, "requires": { "acorn": "^7.1.1", "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "dev": true + } } }, "acorn-jsx": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "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 }, "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, "requires": { "debug": "4" @@ -2120,8 +12524,6 @@ }, "ajv": { "version": "7.2.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.4.tgz", - "integrity": "sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -2129,48 +12531,25 @@ "uri-js": "^4.2.2" } }, - "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 - }, "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, "requires": { "type-fest": "^0.21.3" - }, - "dependencies": { - "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 - } } }, "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 + "version": "5.0.1" }, "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.2.1", "dev": true, "requires": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" } }, "anymatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -2179,14 +12558,10 @@ }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true }, "are-we-there-yet": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", "dev": true, "requires": { "delegates": "^1.0.0", @@ -2195,8 +12570,6 @@ "dependencies": { "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, "requires": { "core-util-is": "~1.0.0", @@ -2210,14 +12583,10 @@ }, "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 }, "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, "requires": { "safe-buffer": "~5.1.0" @@ -2227,152 +12596,103 @@ }, "arg": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, "argparse": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "version": "3.1.5", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", "get-intrinsic": "^1.1.1", "is-string": "^1.0.7" } }, "array-union": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.0", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" } }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, "async-lock": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.3.0.tgz", - "integrity": "sha512-8A7SkiisnEgME2zEedtDYPxUPzdv3x//E7n5IFktPAtMYSEAV7eNJF0rMwrVyUFj6d/8rgajLantbjcNRQYXIg==" + "version": "1.3.1" }, "async-mutex": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", - "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", "requires": { "tslib": "^2.3.1" } }, "asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, "at-least-node": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, "babel-jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.6.2", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -2382,8 +12702,6 @@ }, "babel-plugin-dynamic-import-node": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", "dev": true, "requires": { "object.assign": "^4.1.0" @@ -2391,8 +12709,6 @@ }, "babel-plugin-istanbul": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -2403,9 +12719,7 @@ } }, "babel-plugin-jest-hoist": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "version": "27.5.1", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -2415,39 +12729,31 @@ } }, "babel-plugin-polyfill-corejs2": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", - "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", + "version": "0.3.1", "dev": true, "requires": { "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.2.2", + "@babel/helper-define-polyfill-provider": "^0.3.1", "semver": "^6.1.1" } }, "babel-plugin-polyfill-corejs3": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz", - "integrity": "sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw==", + "version": "0.5.2", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.16.2" + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz", - "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", + "version": "0.3.1", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.2" + "@babel/helper-define-polyfill-provider": "^0.3.1" } }, "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, "requires": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -2465,99 +12771,34 @@ } }, "babel-preset-jest": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "version": "27.5.1", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^26.6.2", + "babel-plugin-jest-hoist": "^27.5.1", "babel-preset-current-node-syntax": "^1.0.0" } }, "babel-runtime": { "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1" + } } }, "balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "big-integer": { - "version": "1.6.50", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.50.tgz", - "integrity": "sha512-+O2uoQWFRo8ysZNo/rjtri2jIwjr3XfeAgRjAUADRqGG+ZITvyn8J1kvXLTaKVr3hhGXk+f23tKfdzmklVM9vQ==" + "version": "1.5.1" }, "bip39": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz", - "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==", "requires": { "@types/node": "11.11.6", "create-hash": "^1.1.0", @@ -2566,21 +12807,15 @@ }, "dependencies": { "@types/node": { - "version": "11.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", - "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" + "version": "11.11.6" } } }, "bitset": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/bitset/-/bitset-5.1.1.tgz", - "integrity": "sha512-oKaRp6mzXedJ1Npo86PKhWfDelI6HxxJo+it9nAcBB0HLVvYVp+5i6yj6DT5hfFgo+TS5T57MRWtw8zhwdTs3g==" + "version": "5.1.1" }, "bl": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "requires": { "buffer": "^5.5.0", @@ -2590,8 +12825,6 @@ "dependencies": { "buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "requires": { "base64-js": "^1.3.1", @@ -2601,14 +12834,10 @@ } }, "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + "version": "1.0.0" }, "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, "requires": { "balanced-match": "^1.0.0", @@ -2617,8 +12846,6 @@ }, "braces": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -2626,27 +12853,21 @@ }, "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 }, "browserslist": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", - "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", + "version": "4.20.3", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001265", - "electron-to-chromium": "^1.3.867", + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", "escalade": "^3.1.1", - "node-releases": "^2.0.0", + "node-releases": "^2.0.3", "picocolors": "^1.0.0" } }, "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, "requires": { "fast-json-stable-stringify": "2.x" @@ -2654,8 +12875,6 @@ }, "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, "requires": { "node-int64": "^0.4.0" @@ -2663,8 +12882,6 @@ }, "buffer": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "requires": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -2672,125 +12889,51 @@ }, "buffer-from": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, "call-bind": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" } }, "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + "version": "3.1.0" }, "camelcase": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, "caniuse-lite": { - "version": "1.0.30001269", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001269.tgz", - "integrity": "sha512-UOy8okEVs48MyHYgV+RdW1Oiudl1H6KolybD6ZquD0VcrPSgj25omXO1S7rDydjpqaISCwA8Pyx+jUQKZwWO5w==", + "version": "1.0.30001340", "dev": true }, "canonicalize": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-1.0.5.tgz", - "integrity": "sha512-mAjKJPIyP0xqqv6IAkvso07StOmz6cmGtNDg3pXCSzXVZOqka7StIkAhJl/zHOi4M2CgpYfD6aeRWbnrmtvBEA==" - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } + "version": "1.0.8" }, "catering": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", - "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==" + "version": "2.1.1" }, "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, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" - }, - "dependencies": { - "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, - "requires": { - "color-convert": "^1.9.0" - } - }, - "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, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - } } }, "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 }, "check-more-types": { "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", "dev": true }, "cheerio": { "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", "requires": { "cheerio-select": "^1.5.0", "dom-serializer": "^1.3.2", @@ -2802,162 +12945,101 @@ } }, "cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", + "version": "1.6.0", "requires": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", + "css-select": "^4.3.0", + "css-what": "^6.0.1", "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" + "domhandler": "^4.3.1", + "domutils": "^2.8.0" } }, "chownr": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true }, "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "version": "3.3.1", "dev": true }, "cipher-base": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, "cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", + "version": "1.2.2", "dev": true }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "clean-git-ref": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", - "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==" + "version": "2.0.1" }, "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, "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "3.0.0" + }, + "string-width": { + "version": "4.2.3", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } } }, "co": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "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 }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, "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==", + "version": "1.9.3", "dev": true, "requires": { - "color-name": "~1.1.4" + "color-name": "1.1.3" } }, "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==", + "version": "1.1.3", "dev": true }, "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, "requires": { "delayed-stream": "~1.0.0" } }, - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "commander": { + "version": "8.3.0" }, "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 }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true }, "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, "requires": { "safe-buffer": "~5.1.1" @@ -2965,60 +13047,36 @@ "dependencies": { "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 } } }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + "version": "2.6.12" }, "core-js-compat": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.18.3.tgz", - "integrity": "sha512-4zP6/y0a2RTHN5bRGT7PTq9lVt3WzvffTNjqnTKsXhkAYNDTkdCLOIfAdOLcQ/7TDdyRj3c+NeHe1NmF1eDScw==", + "version": "3.22.5", "dev": true, "requires": { - "browserslist": "^4.17.3", + "browserslist": "^4.20.3", "semver": "7.0.0" }, "dependencies": { "semver": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", "dev": true } } }, "core-util-is": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, "crc-32": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", - "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", - "requires": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - } + "version": "1.2.2" }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -3029,8 +13087,6 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -3042,22 +13098,16 @@ }, "create-require": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, "cross-fetch": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", - "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", + "version": "3.1.5", "requires": { - "node-fetch": "2.6.1" + "node-fetch": "2.6.7" } }, "cross-spawn": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3065,32 +13115,24 @@ } }, "css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "version": "4.3.0", "requires": { "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" } }, "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==" + "version": "6.1.0" }, "cssom": { "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", "dev": true }, "cssstyle": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, "requires": { "cssom": "~0.3.6" @@ -3098,16 +13140,12 @@ "dependencies": { "cssom": { "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true } } }, "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, "requires": { "abab": "^2.0.3", @@ -3116,165 +13154,80 @@ } }, "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", "requires": { "ms": "2.1.2" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, "decimal.js": { "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, "decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "version": "6.0.0", "requires": { - "mimic-response": "^2.0.0" + "mimic-response": "^3.1.0" } }, + "dedent": { + "version": "0.7.0", + "dev": true + }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true }, "deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, "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 }, "deferred-leveldown": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-7.0.0.tgz", - "integrity": "sha512-QKN8NtuS3BC6m0B8vAnBls44tX1WXAFATUsJlruyAYbZpysWV3siH6o/i3g9DCHauzodksO60bdj5NazNbjCmg==", "requires": { "abstract-leveldown": "^7.2.0", "inherits": "^2.0.3" } }, "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, + "version": "1.1.4", "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, - "defined": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", - "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=" - }, "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 }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true }, "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 }, "diff": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, "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==", + "version": "27.5.1", "dev": true }, "diff3": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", - "integrity": "sha1-1OXDpM305f4SEatC5pP8tDIVgPw=" + "version": "0.0.3" }, "dir-glob": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "requires": { "path-type": "^4.0.0" @@ -3282,17 +13235,13 @@ }, "doctrine": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { "esutils": "^2.0.2" } }, "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "version": "1.4.1", "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -3300,14 +13249,10 @@ } }, "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + "version": "2.3.0" }, "domexception": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", "dev": true, "requires": { "webidl-conversions": "^5.0.0" @@ -3315,24 +13260,18 @@ "dependencies": { "webidl-conversions": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", "dev": true } } }, "domhandler": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", + "version": "4.3.1", "requires": { "domelementtype": "^2.2.0" } }, "domutils": { "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "requires": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -3340,27 +13279,18 @@ } }, "electron-to-chromium": { - "version": "1.3.871", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.871.tgz", - "integrity": "sha512-qcLvDUPf8DSIMWarHT2ptgcqrYg62n3vPA7vhrOF24d8UNzbUBaHu2CySiENR3nEDzYgaN60071t0F6KLYMQ7Q==", + "version": "1.4.137", "dev": true }, "emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", + "version": "0.8.1", "dev": true }, "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 + "version": "8.0.0" }, "encoding-down": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-7.1.0.tgz", - "integrity": "sha512-ky47X5jP84ryk5EQmvedQzELwVJPjCgXDQZGeb9F6r4PdChByCGHTBrVcF3h8ynKVJ1wVbkxTsDC8zBROPypgQ==", "requires": { "abstract-leveldown": "^7.2.0", "inherits": "^2.0.3", @@ -3369,116 +13299,104 @@ } }, "encryptedfs": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/encryptedfs/-/encryptedfs-3.4.3.tgz", - "integrity": "sha512-OQqsGw3eNrMdFpiYRX17nMq1NKKebaA0KXyM9IRY9aPOxpaeOwcdvWnOcvvO9wCxZFNxgy/A2SOZdxnhCe3paA==", - "requires": { - "@matrixai/async-init": "^1.6.0", - "@matrixai/db": "^1.1.5", - "@matrixai/logger": "^2.1.0", - "@matrixai/workers": "^1.2.5", - "async-mutex": "^0.3.2", + "version": "3.5.3", + "requires": { + "@matrixai/async-init": "^1.7.3", + "@matrixai/async-locks": "^2.2.4", + "@matrixai/db": "^4.0.2", + "@matrixai/errors": "^1.1.1", + "@matrixai/logger": "^2.1.1", + "@matrixai/resources": "^1.1.3", + "@matrixai/workers": "^1.3.3", "errno": "^0.1.7", "lexicographic-integer": "^1.1.0", - "node-forge": "^0.10.0", + "node-forge": "^1.3.1", "readable-stream": "^3.6.0", "resource-counter": "^1.2.4", "threads": "^1.6.5", - "ts-custom-error": "^3.2.0", "util-callbackify": "^1.0.0" }, "dependencies": { "@matrixai/db": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-1.2.1.tgz", - "integrity": "sha512-1W8TORmRX3q3NugZFn0FTgI0mo/n0nWBTXHKXwwPfxtdyNfi18JCj3HVCwWdToOo87ypnS/mqLDIUTSHbF7F3Q==", - "requires": { - "@matrixai/async-init": "^1.6.0", - "@matrixai/logger": "^2.1.0", - "@matrixai/workers": "^1.2.5", - "abstract-leveldown": "^7.2.0", - "async-mutex": "^0.3.1", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-4.0.5.tgz", + "integrity": "sha512-X3gBcyPxC+bTEfi1J1Y49n1bglvg7HjM8MKNH5s+OUEswqKSZgeg1uWfXqvUqq72yjBtgRi4Ghmy4MdrIB1oMw==", + "requires": { + "@matrixai/async-init": "^1.7.3", + "@matrixai/errors": "^1.1.1", + "@matrixai/logger": "^2.1.1", + "@matrixai/resources": "^1.1.3", + "@matrixai/workers": "^1.3.3", + "@types/abstract-leveldown": "^7.2.0", "level": "7.0.1", - "levelup": "^5.1.1", - "sublevel-prefixer": "^1.0.0", - "subleveldown": "^6.0.1", - "threads": "^1.6.5", - "ts-custom-error": "^3.2.0" + "threads": "^1.6.5" } + }, + "node-forge": { + "version": "1.3.1" } } }, "end-of-stream": { "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { "once": "^1.4.0" } }, - "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, - "requires": { - "ansi-colors": "^4.1.1" - } - }, "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + "version": "2.2.0" }, "errno": { "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "requires": { "prr": "~1.0.1" } }, "error-ex": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { "is-arrayish": "^0.2.1" } }, "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.20.0", "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", "get-intrinsic": "^1.1.1", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "regexp.prototype.flags": "^1.4.1", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "dev": true, + "requires": { + "has": "^1.0.3" } }, "es-to-primitive": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -3486,21 +13404,14 @@ } }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "version": "3.1.1" }, "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 }, "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, "requires": { "esprima": "^4.0.1", @@ -3511,15 +13422,11 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", "dev": true }, "levn": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { "prelude-ls": "~1.1.2", @@ -3528,8 +13435,6 @@ }, "optionator": { "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "requires": { "deep-is": "~0.1.3", @@ -3542,21 +13447,10 @@ }, "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 }, - "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, - "optional": true - }, "type-check": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { "prelude-ls": "~1.1.2" @@ -3565,66 +13459,48 @@ } }, "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "version": "8.15.0", "dev": true, "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", + "@eslint/eslintrc": "^1.2.3", + "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", + "glob-parent": "^6.0.1", "globals": "^13.6.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "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", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.9", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, "ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -3633,43 +13509,54 @@ "uri-js": "^4.2.2" } }, + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "dev": true + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "eslint-scope": { + "version": "7.1.1", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "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 - } + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" } }, + "estraverse": { + "version": "5.3.0", + "dev": true + }, "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.15.0", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -3677,52 +13564,39 @@ }, "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 }, - "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 + "js-yaml": { + "version": "4.1.0", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } }, "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 }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, "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, "requires": { "has-flag": "^4.0.0" } + }, + "type-fest": { + "version": "0.20.2", + "dev": true } } }, "eslint-config-prettier": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", - "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", - "dev": true + "version": "8.5.0", + "dev": true, + "requires": {} }, "eslint-import-resolver-node": { "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dev": true, "requires": { "debug": "^3.2.7", @@ -3731,8 +13605,6 @@ "dependencies": { "debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -3741,20 +13613,15 @@ } }, "eslint-module-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", - "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", + "version": "2.7.3", "dev": true, "requires": { "debug": "^3.2.7", - "find-up": "^2.1.0", - "pkg-dir": "^2.0.0" + "find-up": "^2.1.0" }, "dependencies": { "debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -3762,8 +13629,6 @@ }, "find-up": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { "locate-path": "^2.0.0" @@ -3771,8 +13636,6 @@ }, "locate-path": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { "p-locate": "^2.0.0", @@ -3781,8 +13644,6 @@ }, "p-limit": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { "p-try": "^1.0.0" @@ -3790,8 +13651,6 @@ }, "p-locate": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { "p-limit": "^1.1.0" @@ -3799,31 +13658,16 @@ }, "p-try": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, "path-exists": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } } } }, "eslint-plugin-import": { - "version": "2.25.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", - "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", + "version": "2.26.0", "dev": true, "requires": { "array-includes": "^3.1.4", @@ -3831,20 +13675,18 @@ "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.1", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.11.0" + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "dependencies": { "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -3852,8 +13694,6 @@ }, "doctrine": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -3861,16 +13701,12 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } } }, "eslint-plugin-prettier": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", - "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "version": "4.0.0", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" @@ -3878,8 +13714,6 @@ }, "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, "requires": { "esrecurse": "^4.3.0", @@ -3888,358 +13722,120 @@ }, "eslint-utils": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "dev": true + } } }, "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "version": "3.3.0", "dev": true }, "esm": { "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", "optional": true }, "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.3.2", "dev": true, "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "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 - } + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" } }, "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 }, "esquery": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { "estraverse": "^5.1.0" }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", "dev": true } } }, "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, "requires": { "estraverse": "^5.2.0" }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", "dev": true } } }, "estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "exec-sh": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", - "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", "dev": true }, "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true - }, - "expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "version": "5.1.1", "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "requires": { + "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" } }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "exit": { + "version": "0.1.2", + "dev": true + }, + "expand-template": { + "version": "2.0.3", + "dev": true + }, + "expect": { + "version": "27.5.1", "dev": true, "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" } }, "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==" + "version": "3.1.3" }, "fast-diff": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, "fast-fuzzy": { - "version": "1.10.10", - "resolved": "https://registry.npmjs.org/fast-fuzzy/-/fast-fuzzy-1.10.10.tgz", - "integrity": "sha512-TkXYYQcLyZ5tbDpg3kj5gq7PNl6vQQQEW99/sBpmYYRPcuCaZElm3FpoOOqwL51+1prhjrzsnGAjWgNCG7iVOA==", + "version": "1.11.1", "requires": { "graphemesplit": "^2.4.1" } }, "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.2.11", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -4247,24 +13843,27 @@ "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } } }, "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 }, "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 }, "fastq": { "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -4272,8 +13871,6 @@ }, "fb-watchman": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", "dev": true, "requires": { "bser": "2.1.1" @@ -4281,8 +13878,6 @@ }, "fd-lock": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fd-lock/-/fd-lock-1.2.0.tgz", - "integrity": "sha512-Lk/pKH2DldLpG4Yh/sOOY84k5VqNzxHPffGwf1+yYI+/qMXzTPp9KJMX+Wh6n4xqGSA1Mu7JPmaDArfJGw2O/A==", "requires": { "napi-macros": "^2.0.0", "node-gyp-build": "^4.2.2" @@ -4290,8 +13885,6 @@ }, "file-entry-cache": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { "flat-cache": "^3.0.4" @@ -4299,8 +13892,6 @@ }, "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, "requires": { "to-regex-range": "^5.0.1" @@ -4308,8 +13899,6 @@ }, "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, "requires": { "locate-path": "^5.0.0", @@ -4318,8 +13907,6 @@ }, "flat-cache": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { "flatted": "^3.1.0", @@ -4327,21 +13914,11 @@ } }, "flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "version": "3.2.5", "dev": true }, "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, "requires": { "asynckit": "^0.4.0", @@ -4349,19 +13926,8 @@ "mime-types": "^2.1.12" } }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, "from2": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "dev": true, "requires": { "inherits": "^2.0.1", @@ -4370,8 +13936,6 @@ "dependencies": { "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, "requires": { "core-util-is": "~1.0.0", @@ -4385,14 +13949,10 @@ }, "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 }, "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, "requires": { "safe-buffer": "~5.1.0" @@ -4402,58 +13962,43 @@ }, "fs-constants": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, "fs-extra": { "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" - }, - "dependencies": { - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } } }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.1" + }, + "function.prototype.name": { + "version": "1.1.5", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } }, "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 }, + "functions-have-names": { + "version": "1.2.3" + }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "requires": { "aproba": "^1.0.3", @@ -4468,34 +14013,10 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -4505,20 +14026,13 @@ }, "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 }, "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 + "version": "2.0.5" }, "get-intrinsic": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -4527,44 +14041,25 @@ }, "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 }, "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } + "version": "6.0.1", + "dev": true }, "get-symbol-description": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" } }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, "github-from-package": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", "dev": true }, "glob": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -4576,65 +14071,44 @@ } }, "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", "dev": true, "requires": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" } }, "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 }, "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", "dev": true, "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" } }, "google-protobuf": { - "version": "3.18.1", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.18.1.tgz", - "integrity": "sha512-cDqSamZ8rGs+pOzhIsBte7wpezUKg/sggeptDWN5odhnRY/eDLa5VWLeNeQvcfiqjS3yUwgM+6OePCJMB7aWZA==" + "version": "3.20.1" }, "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "version": "4.2.10", "dev": true }, "graphemesplit": { "version": "2.4.4", - "resolved": "https://registry.npmjs.org/graphemesplit/-/graphemesplit-2.4.4.tgz", - "integrity": "sha512-lKrpp1mk1NH26USxC/Asw4OHbhSQf5XfrWZ+CDv/dFVvd1j17kFgMotdJvOesmHkbFX9P9sBfpH8VogxOWLg8w==", "requires": { "js-base64": "^3.6.0", "unicode-trie": "^2.0.0" } }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true - }, "grpc_tools_node_protoc_ts": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/grpc_tools_node_protoc_ts/-/grpc_tools_node_protoc_ts-5.3.2.tgz", - "integrity": "sha512-7xPSeu8bwjcird3i9R5+9O4BF2Lhv9fMBdeobfUc2Bys9tSVtm/VB3WjTpKV78WlLYJyD94+wL/8hJqaMZ53Hw==", "dev": true, "requires": { "google-protobuf": "3.15.8", @@ -4643,16 +14117,12 @@ "dependencies": { "google-protobuf": { "version": "3.15.8", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.15.8.tgz", - "integrity": "sha512-2jtfdqTaSxk0cuBJBtTTWsot4WtR9RVr2rXg7x7OoqiuOKopPrwXpM1G4dXIkLcUNRh3RKzz76C8IOkksZSeOw==", "dev": true } } }, "handlebars": { "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, "requires": { "minimist": "^1.2.5", @@ -4660,132 +14130,50 @@ "source-map": "^0.6.1", "uglify-js": "^3.1.4", "wordwrap": "^1.0.0" - }, - "dependencies": { - "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 - } } }, "has": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "requires": { "function-bind": "^1.1.1" } }, "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + "version": "1.0.2" }, "has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-property-descriptors": { + "version": "1.0.0", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + "version": "1.0.3" }, "has-tostringtag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "requires": { "has-symbols": "^1.0.2" } }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "hash-base": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "requires": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", "safe-buffer": "^5.2.0" } }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, "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, "requires": { "whatwg-encoding": "^1.0.5" @@ -4793,14 +14181,10 @@ }, "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 }, "htmlparser2": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.0.0", @@ -4810,8 +14194,6 @@ }, "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, "requires": { "@tootallnate/once": "1", @@ -4820,9 +14202,7 @@ } }, "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==", + "version": "5.0.1", "dev": true, "requires": { "agent-base": "6", @@ -4830,34 +14210,24 @@ } }, "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "version": "2.1.0", "dev": true }, "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, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + "version": "1.2.1" }, "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + "version": "5.2.0" }, "import-fresh": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -4866,16 +14236,12 @@ "dependencies": { "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 } } }, "import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "version": "3.1.0", "dev": true, "requires": { "pkg-dir": "^4.2.0", @@ -4884,14 +14250,10 @@ }, "imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { "once": "^1.3.0", @@ -4899,20 +14261,14 @@ } }, "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "version": "2.0.4" }, "ini": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, "internal-slot": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "requires": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", @@ -4921,8 +14277,6 @@ }, "into-stream": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", - "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", "dev": true, "requires": { "from2": "^2.3.0", @@ -4930,309 +14284,134 @@ } }, "ip-num": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/ip-num/-/ip-num-1.3.3.tgz", - "integrity": "sha512-1QsiMKglDaemuIktincG1ntr3DvVTV/pU++eyG7vIm4xd+gvtJ9eoB34RRbI9YTqn1U5og16n7+1RgwLhv4RmA==", - "requires": { - "big-integer": "^1.6.48" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "version": "1.4.0" }, "is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "is-bigint": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "requires": { "has-bigints": "^1.0.1" } }, "is-boolean-object": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" } }, "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + "version": "2.0.5" }, "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } + "version": "1.2.4" }, "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.9.0", "dev": true, "requires": { "has": "^1.0.3" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-date-object": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "requires": { "has-tostringtag": "^1.0.0" } }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "optional": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, "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 }, "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 + "version": "1.0.0", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } }, "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 }, "is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + "version": "2.0.2" }, "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 }, "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", "requires": { "has-tostringtag": "^1.0.0" } }, "is-observable": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-2.1.0.tgz", - "integrity": "sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw==" - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } + "version": "2.1.0" }, "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 }, "is-regex": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" } }, "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" + "version": "1.0.2", + "requires": { + "call-bind": "^1.0.2" + } }, "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "version": "2.0.1", "dev": true }, "is-string": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "requires": { "has-tostringtag": "^1.0.0" } }, "is-symbol": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "requires": { "has-symbols": "^1.0.2" } }, "is-typedarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, "is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "requires": { - "call-bind": "^1.0.0" - } - }, - "is-windows": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "optional": true, "requires": { - "is-docker": "^2.0.0" + "call-bind": "^1.0.2" } }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "version": "2.0.0" }, "isomorphic-git": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.10.1.tgz", - "integrity": "sha512-abbPpKkykIVDJ92rtYoD4AOuT5/7PABHR2fDBrsm7H0r2ZT+MGpPL/FynrEJM6nTcFSieaIDxnHNGhfHO/v+bA==", + "version": "1.17.2", "requires": { "async-lock": "^1.1.0", "clean-git-ref": "^2.0.1", @@ -5244,32 +14423,26 @@ "pify": "^4.0.1", "readable-stream": "^3.4.0", "sha.js": "^2.4.9", - "simple-get": "^3.0.2" + "simple-get": "^4.0.1" } }, "istanbul-lib-coverage": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.1.0.tgz", - "integrity": "sha512-OFSPP1Csv3GxruycNA1iRJPnc5pon+N4Q89EUz8KYOFbdsqCoHRh0J8jwRdna5thveVcMTdgY27kUl/lZuAWdw==", + "version": "3.2.0", "dev": true }, "istanbul-lib-instrument": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.0.4.tgz", - "integrity": "sha512-W6jJF9rLGEISGoCyXRqa/JCGQGmmxPO10TMu7izaUTynxvBvTjqzAIIGCK9USBmIbQAaSWD6XJPrM9Pv5INknw==", + "version": "5.2.0", "dev": true, "requires": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, "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, "requires": { "istanbul-lib-coverage": "^3.0.0", @@ -5279,14 +14452,10 @@ "dependencies": { "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -5296,249 +14465,222 @@ }, "istanbul-lib-source-maps": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "requires": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" - }, - "dependencies": { - "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 - } } }, - "istanbul-reports": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", - "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", + "istanbul-reports": { + "version": "3.1.4", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "27.5.1", + "dev": true, + "requires": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + } + }, + "jest-changed-files": { + "version": "27.5.1", "dev": true, "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" } }, - "jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", + "jest-circus": { + "version": "27.5.1", "dev": true, "requires": { - "@jest/core": "^26.6.3", - "import-local": "^3.0.2", - "jest-cli": "^26.6.3" + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "color-convert": { + "version": "2.0.1", "dev": true, "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, - "jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", - "dev": true, - "requires": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "prompts": "^2.0.1", - "yargs": "^15.4.1" - } - }, "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, "requires": { "has-flag": "^4.0.0" } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } } } }, - "jest-changed-files": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", + "jest-cli": { + "version": "27.5.1", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" }, "dependencies": { - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "ansi-styles": { + "version": "4.3.0", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" + "color-convert": "^2.0.1" } }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "chalk": { + "version": "4.1.2", "dev": true, "requires": { - "pump": "^3.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "is-stream": { + "color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, + "has-flag": { + "version": "4.0.0", "dev": true }, - "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==", + "supports-color": { + "version": "7.2.0", "dev": true, "requires": { - "path-key": "^3.0.0" + "has-flag": "^4.0.0" } } } }, "jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "version": "27.5.1", "dev": true, "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -5547,37 +14689,47 @@ } }, "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==", + "version": "27.5.1", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -5586,47 +14738,55 @@ } }, "jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", + "version": "27.5.1", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -5635,108 +14795,108 @@ } }, "jest-environment-jsdom": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", - "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2", - "jsdom": "^16.4.0" + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" } }, "jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" } }, "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==", + "version": "27.5.1", "dev": true }, "jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "@types/graceful-fs": "^4.1.2", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", "walker": "^1.0.7" } }, "jest-jasmine2": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", - "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "version": "27.5.1", "dev": true, "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^26.6.2", + "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2", - "throat": "^5.0.0" + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -5745,47 +14905,55 @@ } }, "jest-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", + "version": "27.5.1", "dev": true, "requires": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" } }, "jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "version": "27.5.1", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -5794,42 +14962,52 @@ } }, "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "version": "27.5.1", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", "slash": "^3.0.0", - "stack-utils": "^2.0.2" + "stack-utils": "^2.0.3" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -5838,75 +15016,80 @@ } }, "jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "@types/node": "*" } }, "jest-mock-process": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jest-mock-process/-/jest-mock-process-1.4.1.tgz", - "integrity": "sha512-ZZUKRlEBizutngoO4KngzN30YoeAYP3nnwimk4cpi9WqLxQUf6SlAPK5p1D9usEpxDS3Uif2MIez3Bq0vGYR+g==", - "dev": true + "dev": true, + "requires": {} }, "jest-mock-props": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/jest-mock-props/-/jest-mock-props-1.9.0.tgz", - "integrity": "sha512-8IlIiZRvovnRuvqcvWZyDv4CyhrUGTbEW/1eKurHr2JY4VhIWQIPlbpt9lqL2nxdGnco+OcgpPBwGYCEeDb2+A==", - "dev": true + "version": "1.9.1", + "dev": true, + "requires": {} }, "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 + "dev": true, + "requires": {} }, "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "version": "27.5.1", "dev": true }, "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", "slash": "^3.0.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -5915,64 +15098,73 @@ } }, "jest-resolve-dependencies": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.6.2" + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" } }, "jest-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.7.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "source-map-support": "^0.5.6", - "throat": "^5.0.0" + "throat": "^6.0.1" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -5981,178 +15173,140 @@ } }, "jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", + "version": "27.5.1", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", + "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", + "execa": "^5.0.0", "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.4.1" + "strip-bom": "^4.0.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "color-convert": { + "version": "2.0.1", "dev": true, "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } } } }, "jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "version": "27.5.1", "dev": true, "requires": { "@types/node": "*", - "graceful-fs": "^4.2.4" + "graceful-fs": "^4.2.9" } }, "jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "version": "27.5.1", "dev": true, "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", + "pretty-format": "^27.5.1", "semver": "^7.3.2" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -6160,8 +15314,6 @@ }, "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, "requires": { "has-flag": "^4.0.0" @@ -6170,39 +15322,49 @@ } }, "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -6211,45 +15373,53 @@ } }, "jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", + "jest-get-type": "^27.5.1", "leven": "^3.1.0", - "pretty-format": "^26.6.2" + "pretty-format": "^27.5.1" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "version": "6.3.0", "dev": true }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -6258,40 +15428,50 @@ } }, "jest-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^26.6.2", + "jest-util": "^27.5.1", "string-length": "^4.0.1" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -6300,26 +15480,20 @@ } }, "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==", + "version": "27.5.1", "dev": true, "requires": { "@types/node": "*", "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "supports-color": "^8.0.0" }, "dependencies": { "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 }, "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==", + "version": "8.1.1", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -6328,25 +15502,17 @@ } }, "jose": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.3.6.tgz", - "integrity": "sha512-A/JgZGUerqG2IMuxkUDBtZ4aTxg/l1Y+pt/QAAYiRAR3EFlxIE0Su0xdpB8tQcPZK5eudB7g1PHCZ5uHatbY+g==" + "version": "4.8.1" }, "js-base64": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.2.tgz", - "integrity": "sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==" + "version": "3.7.2" }, "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 }, "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, "requires": { "argparse": "^1.0.7", @@ -6355,8 +15521,6 @@ }, "jsdom": { "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, "requires": { "abab": "^2.0.5", @@ -6386,93 +15550,48 @@ "whatwg-url": "^8.5.0", "ws": "^7.4.6", "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", - "dev": true - } } }, "jsesc": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, "json-parse-even-better-errors": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "version": "1.0.0" }, "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 }, "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.1", + "dev": true }, "jsonc-parser": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", "dev": true }, "jsonfile": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" - }, - "dependencies": { - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } } }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + "version": "3.0.3" }, "lazy-ass": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", "dev": true }, "level": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/level/-/level-7.0.1.tgz", - "integrity": "sha512-w3E64+ALx2eZf8RV5JL4kIcE0BFAvQscRYd1yU4YVqZN9RGTQxXSvH202xvK15yZwFFxRXe60f13LJjcJ//I4Q==", "requires": { "level-js": "^6.1.0", "level-packager": "^6.0.1", @@ -6481,29 +15600,21 @@ }, "level-codec": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-10.0.0.tgz", - "integrity": "sha512-QW3VteVNAp6c/LuV6nDjg7XDXx9XHK4abmQarxZmlRSDyXYk20UdaJTSX6yzVvQ4i0JyWSB7jert0DsyD/kk6g==", "requires": { "buffer": "^6.0.3" } }, "level-concat-iterator": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", - "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", "requires": { "catering": "^2.1.0" } }, "level-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-3.0.1.tgz", - "integrity": "sha512-tqTL2DxzPDzpwl0iV5+rBCv65HWbHp6eutluHNcVIftKZlQN//b6GEnZDM2CvGZvzGYMwyPtYppYnydBQd2SMQ==" + "version": "3.0.1" }, "level-iterator-stream": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-5.0.0.tgz", - "integrity": "sha512-wnb1+o+CVFUDdiSMR/ZymE2prPs3cjVLlXuDeSq9Zb8o032XrabGEXcTCsBxprAtseO3qvFeGzh6406z9sOTRA==", "requires": { "inherits": "^2.0.4", "readable-stream": "^3.4.0" @@ -6511,8 +15622,6 @@ }, "level-js": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/level-js/-/level-js-6.1.0.tgz", - "integrity": "sha512-i7mPtkZm68aewfv0FnIUWvFUFfoyzIvVKnUmuQGrelEkP72vSPTaA1SGneWWoCV5KZJG4wlzbJLp1WxVNGuc6A==", "requires": { "abstract-leveldown": "^7.2.0", "buffer": "^6.0.3", @@ -6521,32 +15630,18 @@ "run-parallel-limit": "^1.1.0" } }, - "level-option-wrap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/level-option-wrap/-/level-option-wrap-1.1.0.tgz", - "integrity": "sha1-rSDmjZ88IsiJdTHMaqevWWse0Sk=", - "requires": { - "defined": "~0.0.0" - } - }, "level-packager": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-6.0.1.tgz", - "integrity": "sha512-8Ezr0XM6hmAwqX9uu8IGzGNkWz/9doyPA8Oo9/D7qcMI6meJC+XhIbNYHukJhIn8OGdlzQs/JPcL9B8lA2F6EQ==", "requires": { "encoding-down": "^7.1.0", "levelup": "^5.1.1" } }, "level-supports": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", - "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==" + "version": "2.1.0" }, "leveldown": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.1.tgz", - "integrity": "sha512-88c+E+Eizn4CkQOBHwqlCJaTNEjGpaEIikn1S+cINc5E9HEvJ77bqY4JY/HxT5u0caWqsc3P3DcFIKBI1vHt+A==", "requires": { "abstract-leveldown": "^7.2.0", "napi-macros": "~2.0.0", @@ -6555,8 +15650,6 @@ }, "levelup": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-5.1.1.tgz", - "integrity": "sha512-0mFCcHcEebOwsQuk00WJwjLI6oCjbBuEYdh/RaRqhjnyVlzqf41T1NnDtCedumZ56qyIh8euLFDqV1KfzTAVhg==", "requires": { "catering": "^2.0.0", "deferred-leveldown": "^7.0.0", @@ -6568,14 +15661,10 @@ }, "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 }, "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, "requires": { "prelude-ls": "^1.2.1", @@ -6583,20 +15672,14 @@ } }, "lexicographic-integer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/lexicographic-integer/-/lexicographic-integer-1.1.0.tgz", - "integrity": "sha1-UsptmYpXLmMitRX1uA45bGBD6bg=" + "version": "1.1.0" }, "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "version": "1.2.4", "dev": true }, "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, "requires": { "p-locate": "^4.1.0" @@ -6604,58 +15687,42 @@ }, "lodash": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true + "lodash.camelcase": { + "version": "4.3.0" }, "lodash.debounce": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", "dev": true }, "lodash.merge": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true + "long": { + "version": "4.0.0" }, "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, "requires": { "yallist": "^4.0.0" } }, "ltgt": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", - "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=" + "version": "2.2.1" }, "lunr": { "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", "dev": true }, "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, "requires": { "semver": "^6.0.0" @@ -6663,44 +15730,21 @@ }, "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 }, "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.x" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "version": "1.0.12", "dev": true, "requires": { - "object-visit": "^1.0.0" + "tmpl": "1.0.5" } }, "marked": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.14.tgz", - "integrity": "sha512-HL5sSPE/LP6U9qKgngIIPTthuxC0jrfxpYMZ3LdGDD3vTnLs59m2Z7r6+LNDR3ToqEQdkKd6YaaEfJhodJmijQ==", + "version": "4.0.15", "dev": true }, "md5.js": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -6709,185 +15753,108 @@ }, "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 }, "merge2": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "version": "1.52.0", "dev": true }, "mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "version": "2.1.35", "dev": true, "requires": { - "mime-db": "1.50.0" + "mime-db": "1.52.0" } }, "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 }, "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" + "version": "3.1.0" }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6" }, "minimisted": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", - "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", "requires": { "minimist": "^1.2.5" } }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, "mkdirp-classic": { "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, "mocked-env": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/mocked-env/-/mocked-env-1.3.5.tgz", - "integrity": "sha512-GyYY6ynVOdEoRlaGpaq8UYwdWkvrsU2xRme9B+WPSuJcNjh17+3QIxSYU6zwee0SbehhV6f06VZ4ahjG+9zdrA==", "dev": true, "requires": { "check-more-types": "2.24.0", "debug": "4.3.2", "lazy-ass": "1.6.0", "ramda": "0.27.1" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "dev": true, + "requires": { + "ms": "2.1.2" + } + } } }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" }, "multiformats": { - "version": "9.4.9", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.4.9.tgz", - "integrity": "sha512-zA84TTJcRfRMpjvYqy63piBbSEdqlIGqNNSpP6kspqtougqjo60PRhIFo+oAxrjkof14WMCImvr7acK6rPpXLw==" + "version": "9.6.5" }, "multistream": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", - "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", "dev": true, "requires": { "once": "^1.4.0", "readable-stream": "^3.6.0" } }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, "napi-build-utils": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", "dev": true }, "napi-macros": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" + "version": "2.0.0" }, "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 }, "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 }, "nexpect": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/nexpect/-/nexpect-0.6.0.tgz", - "integrity": "sha512-gG4cO0zoNG+kaPesw516hPVEKLW3YizGU8UWMr5lpkHKOgoTWcu4sPQN7rWVAIL4Ck87zM4N8immPUhYPdDz3g==", "dev": true, "requires": { "cross-spawn": "^6.0.5" @@ -6895,8 +15862,6 @@ "dependencies": { "cross-spawn": { "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -6908,20 +15873,14 @@ }, "path-key": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "semver": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "shebang-command": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { "shebang-regex": "^1.0.0" @@ -6929,14 +15888,10 @@ }, "shebang-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "which": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -6946,14 +15901,10 @@ }, "nice-try": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "node-abi": { "version": "2.30.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", - "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", "dev": true, "requires": { "semver": "^5.4.1" @@ -6961,92 +15912,58 @@ "dependencies": { "semver": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } }, "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + "version": "2.6.7", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3" + }, + "webidl-conversions": { + "version": "3.0.1" + }, + "whatwg-url": { + "version": "5.0.0", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } }, "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + "version": "0.10.0" }, "node-gyp-build": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", - "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==" + "version": "4.4.0" }, "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-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 }, "node-releases": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", - "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", + "version": "2.0.4", "dev": true }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "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 }, "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "version": "4.0.1", "dev": true, "requires": { - "path-key": "^2.0.0" - }, - "dependencies": { - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - } + "path-key": "^3.0.0" } }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -7057,90 +15974,30 @@ }, "nth-check": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", "requires": { "boolbase": "^1.0.0" } }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "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 }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + "version": "1.12.0" }, "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } + "version": "1.1.1" }, "object.assign": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -7150,27 +16007,14 @@ }, "object.getownpropertydescriptors": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", "es-abstract": "^1.19.1" } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "object.values": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -7179,22 +16023,16 @@ } }, "observable-fns": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/observable-fns/-/observable-fns-0.6.1.tgz", - "integrity": "sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==" + "version": "0.6.1" }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" } }, "onetime": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "requires": { "mimic-fn": "^2.1.0" @@ -7202,8 +16040,6 @@ }, "optionator": { "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "requires": { "deep-is": "^0.1.3", @@ -7214,28 +16050,12 @@ "word-wrap": "^1.2.3" } }, - "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 - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, "p-is-promise": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", - "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", "dev": true }, "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, "requires": { "p-try": "^2.0.0" @@ -7243,8 +16063,6 @@ }, "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, "requires": { "p-limit": "^2.2.0" @@ -7252,19 +16070,13 @@ }, "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 }, "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + "version": "1.0.11" }, "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, "requires": { "callsites": "^3.0.0" @@ -7272,8 +16084,6 @@ }, "parse-json": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -7283,57 +16093,35 @@ } }, "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + "version": "6.0.1" }, "parse5-htmlparser2-tree-adapter": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", "requires": { "parse5": "^6.0.1" } }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, "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 }, "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 }, "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "version": "3.1.1" }, "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 }, "path-type": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, "pbkdf2": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -7344,34 +16132,21 @@ }, "picocolors": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", "dev": true }, "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + "version": "4.0.1" }, "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } + "version": "4.0.5", + "dev": true }, "pkg": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.6.0.tgz", - "integrity": "sha512-mHrAVSQWmHA41RnUmRpC7pK9lNnMfdA16CF3cqOI22a8LZxOQzF7M8YWtA2nfs+d7I0MTDXOtkDsAsFXeCpYjg==", "dev": true, "requires": { "@babel/parser": "7.16.2", @@ -7391,37 +16166,63 @@ "tslib": "2.3.1" }, "dependencies": { + "@babel/parser": { + "version": "7.16.2", + "dev": true + }, + "@babel/types": { + "version": "7.16.0", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.15.7", + "to-fast-properties": "^2.0.0" + } + }, + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, "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 }, "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, "requires": { "has-flag": "^4.0.0" } + }, + "tslib": { + "version": "2.3.1", + "dev": true } } }, "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, "requires": { "find-up": "^4.0.0" @@ -7429,8 +16230,6 @@ }, "pkg-fetch": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.3.0.tgz", - "integrity": "sha512-xJnIZ1KP+8rNN+VLafwu4tEeV4m8IkFBDdCFqmAJz9K1aiXEtbARmdbEe6HlXWGSVuShSHjFXpfkKRkDBQ5kiA==", "dev": true, "requires": { "chalk": "^4.1.2", @@ -7443,35 +16242,38 @@ "yargs": "^16.2.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, - "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 - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "color-convert": { + "version": "2.0.1", "dev": true, "requires": { - "whatwg-url": "^5.0.0" + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "dev": true + }, "semver": { "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -7479,47 +16281,15 @@ }, "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, "requires": { "has-flag": "^4.0.0" } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "dev": true - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } } } }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, "prebuild-install": { "version": "6.1.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", - "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", "dev": true, "requires": { "detect-libc": "^1.0.3", @@ -7535,82 +16305,102 @@ "simple-get": "^3.0.3", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" + }, + "dependencies": { + "decompress-response": { + "version": "4.2.1", + "dev": true, + "requires": { + "mimic-response": "^2.0.0" + } + }, + "mimic-response": { + "version": "2.1.0", + "dev": true + }, + "simple-get": { + "version": "3.1.1", + "dev": true, + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + } } }, "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 }, "prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "version": "2.6.2", "dev": true }, "prettier-linter-helpers": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "requires": { "fast-diff": "^1.1.2" } }, "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==", + "version": "27.5.1", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "dev": true + } } }, - "printj": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", - "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==" - }, "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 }, "progress": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "prompts": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "requires": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, + "protobufjs": { + "version": "6.11.3", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + } + }, "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + "version": "1.0.1" }, "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 }, "pump": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -7618,33 +16408,23 @@ } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "version": "2.1.1" }, "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + "version": "1.2.3" }, "ramda": { "version": "0.27.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", - "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", "dev": true }, "randombytes": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "requires": { "safe-buffer": "^5.1.0" } }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "requires": { "deep-extend": "^0.6.0", @@ -7655,66 +16435,16 @@ "dependencies": { "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true } } }, - "reachdown": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reachdown/-/reachdown-1.1.0.tgz", - "integrity": "sha512-6LsdRe4cZyOjw4NnvbhUd/rGG7WQ9HMopPr+kyL018Uci4kijtxcGR5kVb5Ln13k4PEE+fEFQbjfOvNw7cnXmA==" - }, "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 }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "dependencies": { - "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 - } - } - }, "readable-stream": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -7723,73 +16453,56 @@ }, "regenerate": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true }, "regenerate-unicode-properties": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", + "version": "10.0.1", "dev": true, "requires": { "regenerate": "^1.4.2" } }, "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + "version": "0.13.9", + "dev": true }, "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", "dev": true, "requires": { "@babel/runtime": "^7.8.4" } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, + "regexp.prototype.flags": { + "version": "1.4.3", "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" } }, "regexpp": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "regexpu-core": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", + "version": "5.0.1", "dev": true, "requires": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" } }, "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "version": "0.6.0", "dev": true }, "regjsparser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", + "version": "0.8.4", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -7797,61 +16510,27 @@ "dependencies": { "jsesc": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true } } }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, "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 + "version": "2.1.1" }, "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true + "version": "2.0.2" }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.0", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "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, "requires": { "resolve-from": "^5.0.0" @@ -7859,41 +16538,25 @@ }, "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 }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "resolve.exports": { + "version": "1.1.0", "dev": true }, "resource-counter": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/resource-counter/-/resource-counter-1.2.4.tgz", - "integrity": "sha512-DGJChvE5r4smqPE+xYNv9r1u/I9cCfRR5yfm7D6EQckdKqMyVpJ5z0s40yn0EM0puFxHg6mPORrQLQdEbJ/RnQ==", "requires": { "babel-runtime": "^6.26.0", "bitset": "^5.0.3" } }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, "reusify": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, "rimraf": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" @@ -7901,23 +16564,13 @@ }, "ripemd160": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" } }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, "run-parallel": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "requires": { "queue-microtask": "^1.2.2" @@ -7925,183 +16578,19 @@ }, "run-parallel-limit": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", - "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", "requires": { "queue-microtask": "^1.2.2" } }, "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==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } + "version": "5.2.1" }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, "saxes": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", "dev": true, "requires": { "xmlchars": "^2.2.0" @@ -8109,43 +16598,14 @@ }, "semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -8153,310 +16613,70 @@ }, "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==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true - }, - "shiki": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", - "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", - "dev": true, - "requires": { - "jsonc-parser": "^3.0.0", - "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "5.2.0" - } - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", - "dev": true - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" - }, - "simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", - "requires": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", - "dev": true, "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "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 - } + "shebang-regex": "^3.0.0" } }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true + "shebang-regex": { + "version": "3.0.0" }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "shiki": { + "version": "0.10.1", "dev": true, "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "jsonc-parser": "^3.0.0", + "vscode-oniguruma": "^1.6.1", + "vscode-textmate": "5.2.0" } }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "side-channel": { + "version": "1.0.4", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", "dev": true }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, + "simple-concat": { + "version": "1.0.1" + }, + "simple-get": { + "version": "4.0.1", "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" } }, - "spdx-license-ids": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", - "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==", + "sisteransi": { + "version": "1.0.5" + }, + "slash": { + "version": "3.0.0", + "dev": true + }, + "source-map": { + "version": "0.6.1", "dev": true }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "source-map-support": { + "version": "0.5.21", "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, "sprintf-js": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, "stack-utils": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "requires": { "escape-string-regexp": "^2.0.0" @@ -8464,37 +16684,12 @@ "dependencies": { "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 } } }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "stream-meter": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", - "integrity": "sha1-Uq+Vql6nYKJJFxZwTb/5D3Ov3R0=", "dev": true, "requires": { "readable-stream": "^2.1.4" @@ -8502,8 +16697,6 @@ "dependencies": { "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, "requires": { "core-util-is": "~1.0.0", @@ -8517,14 +16710,10 @@ }, "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 }, "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, "requires": { "safe-buffer": "~5.1.0" @@ -8532,10 +16721,14 @@ } } }, + "string_decoder": { + "version": "1.3.0", + "requires": { + "safe-buffer": "~5.2.0" + } + }, "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, "requires": { "char-regex": "^1.0.2", @@ -8543,97 +16736,63 @@ } }, "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "1.0.2", "dev": true, "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } } }, "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.5", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.5", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "requires": { "ansi-regex": "^5.0.1" } }, "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 - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "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 }, "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 }, - "sublevel-prefixer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sublevel-prefixer/-/sublevel-prefixer-1.0.0.tgz", - "integrity": "sha1-TuRZ72Y6yFvyj8ZJ17eWX9ppEHM=" - }, - "subleveldown": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/subleveldown/-/subleveldown-6.0.1.tgz", - "integrity": "sha512-Cnf+cn2wISXU2xflY1SFIqfX4hG2d6lFk2P5F8RDQLmiqN9Ir4ExNfUFH6xnmizMseM/t+nMsDUKjN9Kw6ShFA==", - "requires": { - "abstract-leveldown": "^7.2.0", - "encoding-down": "^7.1.0", - "inherits": "^2.0.3", - "level-option-wrap": "^1.1.0", - "levelup": "^5.1.1", - "reachdown": "^1.1.0" - } - }, "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, "requires": { "has-flag": "^3.0.0" @@ -8641,8 +16800,6 @@ }, "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, "requires": { "has-flag": "^4.0.0", @@ -8651,14 +16808,10 @@ "dependencies": { "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -8666,44 +16819,16 @@ } } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true + }, "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 }, - "table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - } - } - }, "tar-fs": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "dev": true, "requires": { "chownr": "^1.1.1", @@ -8714,8 +16839,6 @@ }, "tar-stream": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "requires": { "bl": "^4.0.3", @@ -8727,8 +16850,6 @@ }, "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, "requires": { "ansi-escapes": "^4.2.1", @@ -8737,8 +16858,6 @@ }, "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, "requires": { "@istanbuljs/schema": "^0.1.2", @@ -8748,14 +16867,10 @@ }, "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 }, "threads": { "version": "1.7.0", - "resolved": "https://registry.npmjs.org/threads/-/threads-1.7.0.tgz", - "integrity": "sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ==", "requires": { "callsites": "^3.1.0", "debug": "^4.2.0", @@ -8765,25 +16880,17 @@ } }, "throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "version": "6.0.1", "dev": true }, "timeout-refresh": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-1.0.3.tgz", - "integrity": "sha512-Mz0CX4vBGM5lj8ttbIFt7o4ZMxk/9rgudJRh76EvB7xXZMur7T/cjRiH2w4Fmkq0zxf2QpM8IFvOSRn8FEu3gA==" + "version": "1.0.3" }, "tiny-inflate": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + "version": "1.0.3" }, "tiny-worker": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tiny-worker/-/tiny-worker-2.3.0.tgz", - "integrity": "sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==", "optional": true, "requires": { "esm": "^3.2.25" @@ -8791,58 +16898,14 @@ }, "tmpl": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, "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 }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "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, "requires": { "is-number": "^7.0.0" @@ -8850,51 +16913,45 @@ }, "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, "requires": { "psl": "^1.1.33", "punycode": "^2.1.1", "universalify": "^0.1.2" + }, + "dependencies": { + "universalify": { + "version": "0.1.2", + "dev": true + } } }, "tr46": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dev": true, "requires": { "punycode": "^2.1.1" } }, "ts-custom-error": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.2.0.tgz", - "integrity": "sha512-cBvC2QjtvJ9JfWLvstVnI45Y46Y5dMxIaG1TDMGAD/R87hpvqFL+7LhvUDhnRCfOnx/xitollFWWvUKKKhbN0A==" + "version": "3.2.0" }, "ts-jest": { - "version": "26.5.6", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz", - "integrity": "sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==", + "version": "27.1.4", "dev": true, "requires": { "bs-logger": "0.x", - "buffer-from": "1.x", "fast-json-stable-stringify": "2.x", - "jest-util": "^26.1.0", + "jest-util": "^27.0.0", "json5": "2.x", - "lodash": "4.x", + "lodash.memoize": "4.x", "make-error": "1.x", - "mkdirp": "1.x", "semver": "7.x", "yargs-parser": "20.x" }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -8903,9 +16960,7 @@ } }, "ts-node": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", - "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==", + "version": "10.7.0", "dev": true, "requires": { "@cspotcode/source-map-support": "0.7.0", @@ -8919,39 +16974,28 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.0", "yn": "3.1.1" }, "dependencies": { - "acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", - "dev": true - }, "acorn-walk": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true } } }, "tsconfig-paths": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", - "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "version": "3.14.1", "dev": true, "requires": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" }, "dependencies": { "json5": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -8959,21 +17003,15 @@ }, "strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true } } }, "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0" }, "tsutils": { "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "requires": { "tslib": "^1.8.1" @@ -8981,16 +17019,12 @@ "dependencies": { "tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true } } }, "tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { "safe-buffer": "^5.0.1" @@ -8998,8 +17032,6 @@ }, "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, "requires": { "prelude-ls": "^1.2.1" @@ -9007,20 +17039,14 @@ }, "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 }, "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "version": "0.21.3", "dev": true }, "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, "requires": { "is-typedarray": "^1.0.0" @@ -9028,8 +17054,6 @@ }, "typedoc": { "version": "0.22.15", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.15.tgz", - "integrity": "sha512-CMd1lrqQbFvbx6S9G6fL4HKp3GoIuhujJReWqlIvSb2T26vGai+8Os3Mde7Pn832pXYemd9BMuuYWhFpL5st0Q==", "dev": true, "requires": { "glob": "^7.2.0", @@ -9041,8 +17065,6 @@ "dependencies": { "brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { "balanced-match": "^1.0.0" @@ -9050,8 +17072,6 @@ }, "minimatch": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -9060,84 +17080,29 @@ } }, "typescript": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", - "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "version": "4.6.4", "dev": true }, - "typescript-cached-transpile": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typescript-cached-transpile/-/typescript-cached-transpile-0.0.6.tgz", - "integrity": "sha512-bfPc7YUW0PrVkQHU0xN0ANRuxdPgoYYXtZEW6PNkH5a97/AOM+kPPxSTMZbpWA3BG1do22JUkfC60KoCKJ9VZQ==", - "dev": true, - "requires": { - "@types/node": "^12.12.7", - "fs-extra": "^8.1.0", - "tslib": "^1.10.0" - }, - "dependencies": { - "@types/node": { - "version": "12.20.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.37.tgz", - "integrity": "sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA==", - "dev": true - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, "uglify-js": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz", - "integrity": "sha512-rtPMlmcO4agTUfz10CbgJ1k6UAoXM2gWb3GoMPPZB/+/Ackf8lNWk11K4rYi2D0apgoFRLtQOZhb+/iGNJq26A==", + "version": "3.15.5", "dev": true, "optional": true }, "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" } }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true }, "unicode-match-property-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "requires": { "unicode-canonical-property-names-ecmascript": "^2.0.0", @@ -9146,132 +17111,48 @@ }, "unicode-match-property-value-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", "dev": true }, "unicode-property-aliases-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true }, "unicode-trie": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", "requires": { "pako": "^0.2.5", "tiny-inflate": "^1.0.0" }, "dependencies": { "pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + "version": "0.2.9" } } }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "2.0.0", "dev": true }, "unordered-set": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", - "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==" - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } + "version": "2.0.1" }, "uri-js": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "requires": { "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, "util-callbackify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util-callbackify/-/util-callbackify-1.0.0.tgz", - "integrity": "sha512-5vEPPSM6DCHlCpq9FZryeIkY5FQMUqXLUz4yHtU369Z/abWUVdgInPVeINjWJV3Bk9DZhCr+JzGarEByPLsxBQ==", "requires": { "object.getownpropertydescriptors": "^2.0.3" } }, "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "version": "1.0.2" }, "utp-native": { "version": "2.5.3", - "resolved": "https://registry.npmjs.org/utp-native/-/utp-native-2.5.3.tgz", - "integrity": "sha512-sWTrWYXPhhWJh+cS2baPzhaZc89zwlWCfwSthUjGhLkZztyPhcQllo+XVVCbNGi7dhyRlxkWxN4NKU6FbA9Y8w==", "requires": { "napi-macros": "^2.0.0", "node-gyp-build": "^4.2.0", @@ -9281,20 +17162,18 @@ } }, "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + "version": "8.3.2" }, "v8-compile-cache": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "v8-compile-cache-lib": { + "version": "3.0.1", "dev": true }, "v8-to-istanbul": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", - "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", + "version": "8.1.1", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -9304,38 +17183,20 @@ "dependencies": { "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 } } }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "vscode-oniguruma": { "version": "1.6.2", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", - "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", "dev": true }, "vscode-textmate": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", - "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", "dev": true }, "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, "requires": { "browser-process-hrtime": "^1.0.0" @@ -9343,32 +17204,24 @@ }, "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, "requires": { "xml-name-validator": "^3.0.0" } }, "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "version": "1.0.8", "dev": true, "requires": { - "makeerror": "1.0.x" + "makeerror": "1.0.12" } }, "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 }, "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, "requires": { "iconv-lite": "0.4.24" @@ -9376,14 +17229,10 @@ }, "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 }, "whatwg-url": { "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, "requires": { "lodash": "^4.7.0", @@ -9393,16 +17242,12 @@ }, "which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "requires": { "isexe": "^2.0.0" } }, "which-boxed-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "requires": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -9411,16 +17256,8 @@ "is-symbol": "^1.0.3" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, "wide-align": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, "requires": { "string-width": "^1.0.2 || 2 || 3 || 4" @@ -9428,36 +17265,53 @@ }, "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 }, "wordwrap": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, "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, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4" + }, + "is-fullwidth-code-point": { + "version": "3.0.0" + }, + "string-width": { + "version": "4.2.3", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } } }, "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "version": "1.0.2" }, "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, "requires": { "imurmurhash": "^0.1.4", @@ -9467,40 +17321,27 @@ } }, "ws": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", - "dev": true + "version": "7.5.7", + "dev": true, + "requires": {} }, "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 }, "xmlchars": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "version": "5.0.8" }, "yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "yargs": { "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -9509,18 +17350,26 @@ "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "3.0.0" + }, + "string-width": { + "version": "4.2.3", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } } }, "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 + "version": "20.2.9" }, "yn": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true } } diff --git a/package.json b/package.json index 78eeae9a9..29bc7b603 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "scripts": "dist/workers/polykeyWorker.js" }, "scripts": { + "prepare": "tsc -p ./tsconfig.build.json", "build": "rm -r ./dist || true; tsc -p ./tsconfig.build.json", "postbuild": "cp -fR src/proto dist; cp src/notifications/*.json dist/notifications/; cp src/claims/*.json dist/claims/; cp src/status/*.json dist/status/;", "ts-node": "ts-node --require tsconfig-paths/register", @@ -71,15 +72,15 @@ "polykey": "ts-node --require tsconfig-paths/register --compiler typescript-cached-transpile --transpile-only src/bin/polykey.ts" }, "dependencies": { - "@grpc/grpc-js": "1.3.7", - "@matrixai/async-init": "^1.7.1", - "@matrixai/async-locks": "^2.2.0", - "@matrixai/db": "^3.2.3", - "@matrixai/errors": "^1.0.1", - "@matrixai/id": "^3.3.2", - "@matrixai/logger": "^2.1.0", - "@matrixai/resources": "^1.0.0", - "@matrixai/workers": "^1.3.1", + "@grpc/grpc-js": "1.6.7", + "@matrixai/async-init": "^1.7.3", + "@matrixai/async-locks": "^2.2.4", + "@matrixai/db": "^3.3.3", + "@matrixai/errors": "^1.1.1", + "@matrixai/id": "^3.3.3", + "@matrixai/logger": "^2.1.1", + "@matrixai/resources": "^1.1.3", + "@matrixai/workers": "^1.3.3", "ajv": "^7.0.4", "bip39": "^3.0.3", "canonicalize": "^1.0.5", @@ -87,7 +88,7 @@ "commander": "^8.3.0", "cross-fetch": "^3.0.6", "cross-spawn": "^7.0.3", - "encryptedfs": "^3.4.3", + "encryptedfs": "^3.5.1", "fast-fuzzy": "^1.10.8", "fd-lock": "^1.2.0", "google-protobuf": "^3.14.0", @@ -109,7 +110,7 @@ "@babel/preset-env": "^7.13.10", "@types/cross-spawn": "^6.0.2", "@types/google-protobuf": "^3.7.4", - "@types/jest": "^26.0.20", + "@types/jest": "^27.0.2", "@types/nexpect": "^0.4.31", "@types/node": "^16.11.7", "@types/node-forge": "^0.9.7", @@ -117,27 +118,26 @@ "@types/prompts": "^2.0.13", "@types/readable-stream": "^2.3.11", "@types/uuid": "^8.3.0", - "@typescript-eslint/eslint-plugin": "^5.4.0", - "@typescript-eslint/parser": "^5.4.0", - "babel-jest": "^26.6.3", - "eslint": "^7.17.0", - "eslint-config-prettier": "^7.1.0", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-prettier": "^3.3.1", + "@typescript-eslint/eslint-plugin": "^5.23.0", + "@typescript-eslint/parser": "^5.23.0", + "babel-jest": "^27.0.0", + "eslint": "^8.15.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-prettier": "^4.0.0", "grpc_tools_node_protoc_ts": "^5.1.3", - "jest": "^26.6.3", + "jest": "^27.2.5", "jest-mock-process": "^1.4.1", "jest-mock-props": "^1.9.0", "mocked-env": "^1.3.5", "nexpect": "^0.6.0", "node-gyp-build": "4.4.0", "pkg": "5.6.0", - "prettier": "^2.2.1", - "ts-jest": "^26.4.4", + "prettier": "^2.6.2", + "ts-jest": "^27.0.5", "ts-node": "^10.4.0", "tsconfig-paths": "^3.9.0", "typedoc": "^0.22.15", - "typescript": "^4.5.2", - "typescript-cached-transpile": "0.0.6" + "typescript": "^4.5.2" } } diff --git a/shell.nix b/shell.nix index 10f435f98..3b4bd595f 100644 --- a/shell.nix +++ b/shell.nix @@ -21,9 +21,9 @@ in set +o allexport set -v - # Enables npm link to work - export npm_config_prefix=~/.npm + mkdir --parents "$(pwd)/tmp" + # Built executables and NPM executables export PATH="$(pwd)/dist/bin:$(npm bin):$PATH" # pkg is installed in package.json @@ -34,8 +34,10 @@ in ] }:$PATH" + # Enables npm link to work + export npm_config_prefix=~/.npm + npm install - mkdir --parents "$(pwd)/tmp" set +v ''; diff --git a/tsconfig.json b/tsconfig.json index 8e4424ab2..8ee4055cd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,8 @@ { "compilerOptions": { "outDir": "./dist", + "tsBuildInfoFile": "./dist/tsbuildinfo", + "incremental": true, "sourceMap": true, "declaration": true, "allowJs": true, From ef8baf57c6b45c0dbfaa74b26c68f32898741005 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 13 May 2022 11:19:58 +1000 Subject: [PATCH 018/137] fix: integrating db changes into sessions --- jest.config.js | 2 +- src/sessions/SessionManager.ts | 113 +++++++++++--------------- tests/sessions/SessionManager.test.ts | 6 +- 3 files changed, 53 insertions(+), 68 deletions(-) diff --git a/jest.config.js b/jest.config.js index 46fe908e2..f811716a8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,7 +2,7 @@ const os = require('os'); const path = require('path'); const fs = require('fs'); const process = require('process'); -const { pathsToModuleNameMapper } = require('ts-jest/utils'); +const { pathsToModuleNameMapper } = require('ts-jest'); const { compilerOptions } = require('./tsconfig'); const moduleNameMapper = pathsToModuleNameMapper( diff --git a/src/sessions/SessionManager.ts b/src/sessions/SessionManager.ts index 6ee4bbbc9..b05ccdf0c 100644 --- a/src/sessions/SessionManager.ts +++ b/src/sessions/SessionManager.ts @@ -1,17 +1,16 @@ -import type { DB, DBLevel } from '@matrixai/db'; +import type { DB, DBTransaction, LevelPath } from '@matrixai/db'; import type { SessionToken } from './types'; -import type { KeyManager } from '../keys'; - +import type KeyManager from '../keys/KeyManager'; import Logger from '@matrixai/logger'; import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; -import { Mutex } from 'async-mutex'; +import { withF } from '@matrixai/resources'; import * as sessionsUtils from './utils'; import * as sessionsErrors from './errors'; import * as keysUtils from '../keys/utils'; -import { utils as nodesUtils } from '../nodes'; +import * as nodesUtils from '../nodes/utils'; interface SessionManager extends CreateDestroyStartStop {} @CreateDestroyStartStop( @@ -53,10 +52,7 @@ class SessionManager { protected logger: Logger; protected db: DB; protected keyManager: KeyManager; - protected sessionsDbDomain: string = this.constructor.name; - protected sessionsDb: DBLevel; - protected lock: Mutex = new Mutex(); - protected key: Uint8Array; + protected sessionsDbPath: LevelPath = [this.constructor.name]; public constructor({ db, @@ -78,23 +74,16 @@ class SessionManager { this.keyBits = keyBits; } - get locked(): boolean { - return this.lock.isLocked(); - } - public async start({ fresh = false, }: { fresh?: boolean; } = {}): Promise { this.logger.info(`Starting ${this.constructor.name}`); - const sessionsDb = await this.db.level(this.sessionsDbDomain); if (fresh) { - await sessionsDb.clear(); + await this.db.clear(this.sessionsDbPath); } - const key = await this.setupKey(this.keyBits); - this.sessionsDb = sessionsDb; - this.key = key; + await this.setupKey(this.keyBits); this.logger.info(`Started ${this.constructor.name}`); } @@ -105,44 +94,24 @@ class SessionManager { public async destroy() { this.logger.info(`Destroying ${this.constructor.name}`); - const sessionsDb = await this.db.level(this.sessionsDbDomain); - await sessionsDb.clear(); + await this.db.clear(this.sessionsDbPath); this.logger.info(`Destroyed ${this.constructor.name}`); } - /** - * Run several operations within the same lock - * This does not ensure atomicity of the underlying database - * Database atomicity still depends on the underlying operation - */ - public async transaction(f: (that: this) => Promise): Promise { - const release = await this.lock.acquire(); - try { - return await f(this); - } finally { - release(); - } - } - - /** - * Transaction wrapper that will not lock if the operation was executed - * within a transaction context - */ - protected async _transaction(f: () => Promise): Promise { - if (this.locked) { - return await f(); - } else { - return await this.transaction(f); - } + @ready(new sessionsErrors.ErrorSessionManagerNotRunning()) + public async withTransactionF( + f: (tran: DBTransaction) => Promise, + ): Promise { + return withF([this.db.transaction()], ([tran]) => f(tran)); } @ready(new sessionsErrors.ErrorSessionManagerNotRunning()) - public async resetKey(): Promise { - await this._transaction(async () => { - const key = await this.generateKey(this.keyBits); - await this.db.put([this.sessionsDbDomain], 'key', key, true); - this.key = key; - }); + public async resetKey(tran?: DBTransaction): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => this.resetKey(tran)); + } + const key = await this.generateKey(this.keyBits); + await tran.put([...this.sessionsDbPath, 'key'], key, true); } /** @@ -153,35 +122,49 @@ class SessionManager { @ready(new sessionsErrors.ErrorSessionManagerNotRunning()) public async createToken( expiry: number | undefined = this.expiry, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.createToken(expiry, tran), + ); + } const payload = { iss: nodesUtils.encodeNodeId(this.keyManager.getNodeId()), sub: nodesUtils.encodeNodeId(this.keyManager.getNodeId()), }; - const token = await sessionsUtils.createSessionToken( - payload, - this.key, - expiry, - ); + const key = await tran.get([...this.sessionsDbPath, 'key'], true); + const token = await sessionsUtils.createSessionToken(payload, key!, expiry); return token; } @ready(new sessionsErrors.ErrorSessionManagerNotRunning()) - public async verifyToken(token: SessionToken): Promise { - const result = await sessionsUtils.verifySessionToken(token, this.key); + public async verifyToken( + token: SessionToken, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.withTransactionF(async (tran) => + this.verifyToken(token, tran), + ); + } + const key = await tran.get([...this.sessionsDbPath, 'key'], true); + const result = await sessionsUtils.verifySessionToken(token, key!); return result !== undefined; } protected async setupKey(bits: 128 | 192 | 256): Promise { - let key: Buffer | undefined; - key = await this.db.get([this.sessionsDbDomain], 'key', true); - if (key != null) { + return withF([this.db.transaction()], async ([tran]) => { + let key: Buffer | undefined; + key = await tran.get([...this.sessionsDbPath, 'key'], true); + if (key != null) { + return key; + } + this.logger.info('Generating sessions key'); + key = await this.generateKey(bits); + await tran.put([...this.sessionsDbPath, 'key'], key, true); return key; - } - this.logger.info('Generating sessions key'); - key = await this.generateKey(bits); - await this.db.put([this.sessionsDbDomain], 'key', key, true); - return key; + }); } protected async generateKey(bits: 128 | 192 | 256): Promise { diff --git a/tests/sessions/SessionManager.test.ts b/tests/sessions/SessionManager.test.ts index 31461996b..bf479885b 100644 --- a/tests/sessions/SessionManager.test.ts +++ b/tests/sessions/SessionManager.test.ts @@ -3,8 +3,10 @@ import os from 'os'; import path from 'path'; import { DB } from '@matrixai/db'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import { KeyManager, utils as keysUtils } from '@/keys'; -import { SessionManager, errors as sessionsErrors } from '@/sessions'; +import KeyManager from '@/keys/KeyManager'; +import * as keysUtils from '@/keys/utils'; +import SessionManager from '@/sessions/SessionManager'; +import * as sessionsErrors from '@/sessions/errors'; import { sleep } from '@/utils'; import * as testUtils from '../utils'; From 16d036178d90733148214d58a7c355f517e73940 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 13 May 2022 15:11:28 +1000 Subject: [PATCH 019/137] fix: keymanager tests passing --- tests/keys/KeyManager.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/keys/KeyManager.test.ts b/tests/keys/KeyManager.test.ts index 773b5d3eb..260346bc6 100644 --- a/tests/keys/KeyManager.test.ts +++ b/tests/keys/KeyManager.test.ts @@ -315,7 +315,7 @@ describe('KeyManager', () => { const rootKeyPair1 = keyManager.getRootKeyPair(); const rootCert1 = keyManager.getRootCert(); await sleep(2000); // Let's just make sure there is time diff - await db.put(['test'], 'hello', 'world'); + await db.put(['test', 'hello'], 'world'); // Reset root key pair takes time await keyManager.resetRootKeyPair('password'); expect(keyManager.getRecoveryCode()).toBeDefined(); @@ -339,7 +339,7 @@ describe('KeyManager', () => { ); await db.stop(); await db.start(); - expect(await db.get(['test'], 'hello')).toBe('world'); + expect(await db.get(['test', 'hello'])).toBe('world'); await keyManager.stop(); }); test('can renew root key pair', async () => { @@ -364,7 +364,7 @@ describe('KeyManager', () => { const rootKeyPair1 = keyManager.getRootKeyPair(); const rootCert1 = keyManager.getRootCert(); await sleep(2000); // Let's just make sure there is time diff - await db.put(['test'], 'hello', 'world'); + await db.put(['test', 'hello'], 'world'); await keyManager.renewRootKeyPair('newpassword'); expect(keyManager.getRecoveryCode()).toBeDefined(); const rootKeyPair2 = keyManager.getRootKeyPair(); @@ -393,7 +393,7 @@ describe('KeyManager', () => { expect(keysUtils.certVerified(rootCert1, rootCert2)).toBe(true); await db.stop(); await db.start(); - expect(await db.get(['test'], 'hello')).toBe('world'); + expect(await db.get(['test', 'hello'])).toBe('world'); await keyManager.stop(); }); test('order of certificate chain should be leaf to root', async () => { From 98a3c759e255ace319698333c876fde0e3f7c34f Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 13 May 2022 15:18:59 +1000 Subject: [PATCH 020/137] fix: git tests passing --- tests/git/utils.test.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/git/utils.test.ts b/tests/git/utils.test.ts index 3f4b6cf9b..e1f59103f 100644 --- a/tests/git/utils.test.ts +++ b/tests/git/utils.test.ts @@ -165,9 +165,11 @@ describe('Git utils', () => { expect(object).toContain(firstCommit.commit.tree); expect(object).toContain(firstCommit.commit.parent[0]); expect(object).toContain(firstCommit.commit.author.name); - expect(object).toContain(firstCommit.commit.author.timestamp); + expect(object).toContain(firstCommit.commit.author.timestamp.toString()); expect(object).toContain(firstCommit.commit.committer.name); - expect(object).toContain(firstCommit.commit.committer.timestamp); + expect(object).toContain( + firstCommit.commit.committer.timestamp.toString(), + ); }); test('wrapped', async () => { const ref = await gitUtils.readObject({ @@ -190,9 +192,11 @@ describe('Git utils', () => { expect(object).toContain(firstCommit.commit.tree); expect(object).toContain(firstCommit.commit.parent[0]); expect(object).toContain(firstCommit.commit.author.name); - expect(object).toContain(firstCommit.commit.author.timestamp); + expect(object).toContain(firstCommit.commit.author.timestamp.toString()); expect(object).toContain(firstCommit.commit.committer.name); - expect(object).toContain(firstCommit.commit.committer.timestamp); + expect(object).toContain( + firstCommit.commit.committer.timestamp.toString(), + ); }); test('deflated', async () => { const ref = await gitUtils.readObject({ @@ -234,9 +238,11 @@ describe('Git utils', () => { expect(object).toContain(firstCommit.commit.tree); expect(object).toContain(firstCommit.commit.parent[0]); expect(object).toContain(firstCommit.commit.author.name); - expect(object).toContain(firstCommit.commit.author.timestamp); + expect(object).toContain(firstCommit.commit.author.timestamp.toString()); expect(object).toContain(firstCommit.commit.committer.name); - expect(object).toContain(firstCommit.commit.committer.timestamp); + expect(object).toContain( + firstCommit.commit.committer.timestamp.toString(), + ); }); }); }); From bfa77d02fdae5a314c6e608ddedefad0d9345b79 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 13 May 2022 16:12:51 +1000 Subject: [PATCH 021/137] fix: NodeGraph tests passing --- src/nodes/NodeConnectionManager.ts | 4 +-- src/nodes/NodeGraph.ts | 53 +++++++++++------------------- 2 files changed, 22 insertions(+), 35 deletions(-) diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 84e9ddfa9..23572a0c7 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -132,13 +132,13 @@ class NodeConnectionManager { return async () => { const connAndLock = await this.getConnection(targetNodeId); // Acquire the read lock and the release function - const release = connAndLock.lock.read(); + const [release] = await connAndLock.lock.read()(); // Resetting TTL timer connAndLock.timer?.refresh(); // Return tuple of [ResourceRelease, Resource] return [ async () => { - release(); + await release(); }, connAndLock.connection, ]; diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index f1f12e149..7cd35ee13 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -104,10 +104,7 @@ class NodeGraph { public async withTransactionF( f: (tran: DBTransaction) => Promise, ): Promise { - return withF( - [this.db.transaction()], - ([tran]) => f(tran), - ); + return withF([this.db.transaction()], ([tran]) => f(tran)); } /** @@ -116,20 +113,19 @@ class NodeGraph { * @returns Node Address of the target node */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async getNode(nodeId: NodeId, tran?: DBTransaction): Promise { + public async getNode( + nodeId: NodeId, + tran?: DBTransaction, + ): Promise { if (tran == null) { - return this.withTransactionF(async (tran) => - this.getNode(nodeId, tran), - ); + return this.withTransactionF(async (tran) => this.getNode(nodeId, tran)); } const bucketIndex = this.getBucketIndex(nodeId); const bucketPath = [ ...this.nodeGraphBucketsDbPath, bucketIndex, ] as unknown as KeyPath; - const bucket = await tran.get( - bucketPath, - ); + const bucket = await tran.get(bucketPath); if (bucket != null && nodeId in bucket) { return bucket[nodeId].address; } @@ -152,7 +148,10 @@ class NodeGraph { * @param bucketIndex */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async getBucket(bucketIndex: number, tran?: DBTransaction): Promise { + public async getBucket( + bucketIndex: number, + tran?: DBTransaction, + ): Promise { if (tran == null) { return this.withTransactionF(async (tran) => this.getBucket(bucketIndex, tran), @@ -162,9 +161,7 @@ class NodeGraph { ...this.nodeGraphBucketsDbPath, lexi.pack(bucketIndex, 'hex'), ] as unknown as KeyPath; - const bucket = await tran.get( - bucketPath, - ); + const bucket = await tran.get(bucketPath); // Cast the non-primitive types correctly (ensures type safety when using them) for (const nodeId in bucket) { bucket[nodeId].address.host = bucket[nodeId].address.host as @@ -195,9 +192,7 @@ class NodeGraph { ...this.nodeGraphBucketsDbPath, bucketIndex, ] as unknown as KeyPath; - let bucket = await tran.get( - bucketPath, - ); + let bucket = await tran.get(bucketPath); if (bucket == null) { bucket = {}; } @@ -245,9 +240,7 @@ class NodeGraph { ...this.nodeGraphBucketsDbPath, bucketIndex, ] as unknown as KeyPath; - const bucket = await tran.get( - bucketPath, - ); + const bucket = await tran.get(bucketPath); if (bucket != null && nodeId in bucket) { bucket[nodeId].lastUpdated = new Date(); if (nodeAddress != null) { @@ -275,9 +268,7 @@ class NodeGraph { ...this.nodeGraphBucketsDbPath, bucketIndex, ] as unknown as KeyPath; - const bucket = await tran.get( - bucketPath - ); + const bucket = await tran.get(bucketPath); if (bucket == null) { return; } @@ -308,12 +299,10 @@ class NodeGraph { @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async getAllBuckets(tran?: DBTransaction): Promise> { if (tran == null) { - return this.withTransactionF(async (tran) => - this.getAllBuckets(tran), - ); + return this.withTransactionF(async (tran) => this.getAllBuckets(tran)); } const buckets: Array = []; - for await (const [v] of tran.iterator({ key: false }, [ + for await (const [, v] of tran.iterator({ keys: false }, [ ...this.nodeGraphBucketsDbPath, ])) { const bucket = dbUtils.deserialize(v); @@ -332,19 +321,17 @@ class NodeGraph { @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async refreshBuckets(tran?: DBTransaction): Promise { if (tran == null) { - return this.withTransactionF(async (tran) => - this.refreshBuckets(tran), - ); + return this.withTransactionF(async (tran) => this.refreshBuckets(tran)); } // Get a local copy of all the buckets - const buckets = await this.getAllBuckets(); + const buckets = await this.getAllBuckets(tran); // Wrap as a batch operation. We want to rollback if we encounter any // errors (such that we don't clear the DB without re-adding the nodes) // 1. Delete every bucket for await (const [k] of tran.iterator({ value: false }, [ ...this.nodeGraphBucketsDbPath, ])) { - const hexBucketIndex = dbUtils.deserialize(k); + const hexBucketIndex = k.toString(); const hexBucketPath = [ ...this.nodeGraphBucketsDbPath, hexBucketIndex, From aa6206938a442ae1a40504b1f5f873a20a6100eb Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 13 May 2022 16:22:09 +1000 Subject: [PATCH 022/137] feat: adding transactions to service handlers --- src/PolykeyAgent.ts | 1 + src/client/service/agentLockAll.ts | 9 ++++++++- src/client/service/index.ts | 4 ++++ src/client/utils/utils.ts | 5 +++-- src/sessions/SessionManager.ts | 2 +- tests/nodes/NodeConnectionManager.lifecycle.test.ts | 2 +- 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index a72ba5f16..32be57de3 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -563,6 +563,7 @@ class PolykeyAgent { }); const clientService = createClientService({ pkAgent: this, + db: this.db, discovery: this.discovery, gestaltGraph: this.gestaltGraph, identitiesManager: this.identitiesManager, diff --git a/src/client/service/agentLockAll.ts b/src/client/service/agentLockAll.ts index 6f7eaba76..02caef2c1 100644 --- a/src/client/service/agentLockAll.ts +++ b/src/client/service/agentLockAll.ts @@ -1,17 +1,21 @@ +import type { DB } from '@matrixai/db'; import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { SessionManager } from '../../sessions'; import type Logger from '@matrixai/logger'; +import { withF } from '@matrixai/resources'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function agentLockAll({ authenticate, sessionManager, + db, logger, }: { authenticate: Authenticate; sessionManager: SessionManager; + db: DB; logger: Logger; }) { return async ( @@ -22,7 +26,10 @@ function agentLockAll({ const response = new utilsPB.EmptyMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - await sessionManager.resetKey(); + await withF( + [db.transaction()], + async ([tran]) => await sessionManager.resetKey(tran), + ); callback(null, response); return; } catch (e) { diff --git a/src/client/service/index.ts b/src/client/service/index.ts index 494c5088c..dc7ac4ff7 100644 --- a/src/client/service/index.ts +++ b/src/client/service/index.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type PolykeyAgent from '../../PolykeyAgent'; import type { KeyManager } from '../../keys'; import type { VaultManager } from '../../vaults'; @@ -88,11 +89,13 @@ import { ClientServiceService } from '../../proto/js/polykey/v1/client_service_g function createService({ keyManager, sessionManager, + db, logger = new Logger(createService.name), fs = require('fs'), ...containerRest }: { pkAgent: PolykeyAgent; + db: DB; keyManager: KeyManager; vaultManager: VaultManager; nodeGraph: NodeGraph; @@ -116,6 +119,7 @@ function createService({ ...containerRest, keyManager, sessionManager, + db, logger, fs, authenticate, diff --git a/src/client/utils/utils.ts b/src/client/utils/utils.ts index 3e2021cf9..f922128bb 100644 --- a/src/client/utils/utils.ts +++ b/src/client/utils/utils.ts @@ -3,8 +3,9 @@ import type { Interceptor, InterceptorOptions, } from '@grpc/grpc-js/build/src/client-interceptors'; -import type { KeyManager } from '../../keys'; -import type { Session, SessionManager } from '../../sessions'; +import type KeyManager from '../../keys/KeyManager'; +import type Session from '../../sessions/Session'; +import type SessionManager from '../../sessions/SessionManager'; import type { SessionToken } from '../../sessions/types'; import type { Authenticate } from '../types'; import * as grpc from '@grpc/grpc-js'; diff --git a/src/sessions/SessionManager.ts b/src/sessions/SessionManager.ts index b05ccdf0c..f7e618a0b 100644 --- a/src/sessions/SessionManager.ts +++ b/src/sessions/SessionManager.ts @@ -154,7 +154,7 @@ class SessionManager { } protected async setupKey(bits: 128 | 192 | 256): Promise { - return withF([this.db.transaction()], async ([tran]) => { + return await withF([this.db.transaction()], async ([tran]) => { let key: Buffer | undefined; key = await tran.get([...this.sessionsDbPath, 'key'], true); if (key != null) { diff --git a/tests/nodes/NodeConnectionManager.lifecycle.test.ts b/tests/nodes/NodeConnectionManager.lifecycle.test.ts index 7bb154f36..66961ca1a 100644 --- a/tests/nodes/NodeConnectionManager.lifecycle.test.ts +++ b/tests/nodes/NodeConnectionManager.lifecycle.test.ts @@ -5,6 +5,7 @@ import path from 'path'; import os from 'os'; import { DB } from '@matrixai/db'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { withF } from '@matrixai/resources'; import { IdInternal } from '@matrixai/id'; import PolykeyAgent from '@/PolykeyAgent'; import KeyManager from '@/keys/KeyManager'; @@ -16,7 +17,6 @@ import * as nodesUtils from '@/nodes/utils'; import * as nodesErrors from '@/nodes/errors'; import * as keysUtils from '@/keys/utils'; import * as grpcUtils from '@/grpc/utils'; -import { withF } from '@/utils'; describe(`${NodeConnectionManager.name} lifecycle test`, () => { const logger = new Logger( From 225d311aae2292644b658eb25a37776909e150ee Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 13 May 2022 17:47:24 +1000 Subject: [PATCH 023/137] fix: fix for `GRPCServer` `http2Servers` hack This was throwing an error because the expected object structure changed. The typing is brittle here since we're going around typescript's back to get a private property. --- src/grpc/GRPCServer.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/grpc/GRPCServer.ts b/src/grpc/GRPCServer.ts index b7a0ac84c..fb9218e3a 100644 --- a/src/grpc/GRPCServer.ts +++ b/src/grpc/GRPCServer.ts @@ -74,8 +74,9 @@ class GRPCServer { } if (serverCredentials._isSecure()) { // @ts-ignore hack for private property - const http2Servers = server.http2ServerList as Array; - for (const http2Server of http2Servers) { + const http2Servers = server.http2ServerList; + for (const http2ServerObjects of http2Servers) { + const http2Server = http2ServerObjects.server as Http2SecureServer; http2Server.on('session', (session: Http2Session) => { const socket = session.socket as TLSSocket; const address = networkUtils.buildAddress( @@ -199,7 +200,8 @@ class GRPCServer { this.logger.info(`Updating ${this.constructor.name} TLS Config`); // @ts-ignore hack for private property const http2Servers = this.server.http2ServerList; - for (const http2Server of http2Servers as Array) { + for (const http2ServerObjects of http2Servers) { + const http2Server = http2ServerObjects.server as Http2SecureServer; http2Server.setSecureContext({ key: Buffer.from(tlsConfig.keyPrivatePem, 'ascii'), cert: Buffer.from(tlsConfig.certChainPem, 'ascii'), From 2afa473a58607967ab976639d97a038b37baaba4 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Mon, 16 May 2022 11:41:52 +1000 Subject: [PATCH 024/137] fix: Small test fixes --- src/PolykeyAgent.ts | 3 +-- tests/bin/utils.ts | 2 +- tests/client/utils.ts | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index 32be57de3..855b3f908 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -421,8 +421,7 @@ class PolykeyAgent { public readonly grpcServerClient: GRPCServer; public readonly events: EventBus; public readonly fs: FileSystem; - - protected logger: Logger; + public readonly logger: Logger; constructor({ nodePath, diff --git a/tests/bin/utils.ts b/tests/bin/utils.ts index 47211b018..3b552cf64 100644 --- a/tests/bin/utils.ts +++ b/tests/bin/utils.ts @@ -343,7 +343,7 @@ async function processExit( function expectProcessError( exitCode: number, stderr: string, - error: ErrorPolykey, + error: ErrorPolykey, ) { expect(exitCode).toBe(error.exitCode); const stdErrLine = stderr.trim().split('\n').pop(); diff --git a/tests/client/utils.ts b/tests/client/utils.ts index c3cc7d25b..036257328 100644 --- a/tests/client/utils.ts +++ b/tests/client/utils.ts @@ -40,6 +40,8 @@ async function openTestClientServer({ grpcServerClient: pkAgent.grpcServerClient, grpcServerAgent: pkAgent.grpcServerAgent, fs: pkAgent.fs, + db: pkAgent.db, + logger: pkAgent.logger, }); const callCredentials = _secure From 5e2ea88db8a0bbfe847b219c57f9fc1a8255507a Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Mon, 16 May 2022 17:17:45 +1000 Subject: [PATCH 025/137] fix: Small fix for NotificationsManager tests --- tests/notifications/NotificationsManager.test.ts | 10 ++++------ tests/utils.ts | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/tests/notifications/NotificationsManager.test.ts b/tests/notifications/NotificationsManager.test.ts index cd3e1eaaa..37be01f56 100644 --- a/tests/notifications/NotificationsManager.test.ts +++ b/tests/notifications/NotificationsManager.test.ts @@ -277,28 +277,26 @@ describe('NotificationsManager', () => { pull: null, } as VaultActions, }; - await expect(async () => + + await testUtils.expectRemoteError( notificationsManager.sendNotification( receiver.keyManager.getNodeId(), generalNotification, ), - ).rejects.toThrow( notificationsErrors.ErrorNotificationsPermissionsNotFound, ); - await expect(async () => + await testUtils.expectRemoteError( notificationsManager.sendNotification( receiver.keyManager.getNodeId(), gestaltNotification, ), - ).rejects.toThrow( notificationsErrors.ErrorNotificationsPermissionsNotFound, ); - await expect(async () => + await testUtils.expectRemoteError( notificationsManager.sendNotification( receiver.keyManager.getNodeId(), vaultNotification, ), - ).rejects.toThrow( notificationsErrors.ErrorNotificationsPermissionsNotFound, ); const receivedNotifications = diff --git a/tests/utils.ts b/tests/utils.ts index c32329886..f6f76c538 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -13,6 +13,7 @@ import { IdInternal } from '@matrixai/id'; import * as keysUtils from '@/keys/utils'; // Import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import { sleep } from '@/utils'; +import * as errors from '@/errors'; // Import config from '@/config'; /** @@ -184,4 +185,16 @@ function generateRandomNodeId(): NodeId { return IdInternal.fromString(random); } -export { setupGlobalKeypair, generateRandomNodeId }; +const expectRemoteError = async ( + promise: Promise, + error, +): Promise => { + await expect(promise).rejects.toThrow(errors.ErrorPolykeyRemote); + try { + return await promise; + } catch (e) { + expect(e.cause).toBeInstanceOf(error); + } +}; + +export { setupGlobalKeypair, generateRandomNodeId, expectRemoteError }; From 1e1f5e5fa4b90edb2e7fc2fd03b5129977a71660 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Mon, 16 May 2022 17:18:06 +1000 Subject: [PATCH 026/137] fix: Small fix for Discovery tests --- src/discovery/Discovery.ts | 31 ++++++-- tests/discovery/Discovery.test.ts | 125 ++++-------------------------- 2 files changed, 37 insertions(+), 119 deletions(-) diff --git a/src/discovery/Discovery.ts b/src/discovery/Discovery.ts index 80b4b43f7..42d0fe154 100644 --- a/src/discovery/Discovery.ts +++ b/src/discovery/Discovery.ts @@ -26,6 +26,8 @@ import { import { IdInternal } from '@matrixai/id'; import { Lock } from '@matrixai/async-locks'; import * as idUtils from '@matrixai/id/dist/utils'; +import { utils as DBUtils } from '@matrixai/db'; +import * as resources from '@matrixai/resources'; import * as discoveryUtils from './utils'; import * as discoveryErrors from './errors'; import * as nodesErrors from '../nodes/errors'; @@ -92,6 +94,7 @@ class Discovery { protected visitedVertices = new Set(); protected discoveryProcess: Promise; protected queuePlug = promise(); + protected queueDrained = promise(); protected lock: Lock = new Lock(); public constructor({ @@ -184,28 +187,32 @@ class Discovery { * Async function for processing the Discovery Queue */ public async setupDiscoveryQueue(): Promise { + this.logger.debug('Setting up DiscoveryQueue'); while (true) { // Checking and waiting for items to process if (await this.queueIsEmpty()) { if (!(this[status] === 'stopping')) { this.queuePlug = promise(); + this.queueDrained.resolveP(); } + this.logger.debug('DiscoveryQueue is pausing'); await this.queuePlug.p; + this.queueDrained = promise(); } if (this[status] === 'stopping') { + this.logger.debug('DiscoveryQueue is ending'); break; } // Processing queue + this.logger.debug('DiscoveryQueue is processing'); for await (const [key, value] of this.db.iterator( {}, this.discoveryQueueDbPath, )) { const vertexId = IdInternal.fromBuffer(key) as DiscoveryQueueId; - const vertex = await this.db.deserializeDecrypt( - value, - false, - ); + const vertex = DBUtils.deserialize(value); + this.logger.debug(`Processing vertex: ${vertex}`); const vertexGId = gestaltsUtils.ungestaltKey(vertex); switch (vertexGId.type) { case 'node': @@ -406,6 +413,13 @@ class Discovery { } } + /** + * Will resolve once the queue has drained + */ + public async waitForDrained(): Promise { + await this.queueDrained.p; + } + /** * Simple check for whether the Discovery Queue is empty. Uses a * transaction lock to ensure consistency. @@ -432,8 +446,9 @@ class Discovery { protected async pushKeyToDiscoveryQueue( gestaltKey: GestaltKey, ): Promise { - await this.lock.withF(async () => { - await this.db.withTransactionF(async (tran) => { + await resources.withF( + [this.db.transaction(), this.lock.lock()], + async ([tran]) => { const valueIterator = tran.iterator({}, this.discoveryQueueDbPath); for await (const [, value] of valueIterator) { if (value.toString() === gestaltKey) { @@ -445,8 +460,8 @@ class Discovery { [...this.discoveryQueueDbDomain, idUtils.toBuffer(discoveryQueueId)], gestaltKey, ); - }); - }); + }, + ); this.queuePlug.resolveP(); } diff --git a/tests/discovery/Discovery.test.ts b/tests/discovery/Discovery.test.ts index 70c4641dd..abfcab85d 100644 --- a/tests/discovery/Discovery.test.ts +++ b/tests/discovery/Discovery.test.ts @@ -1,7 +1,6 @@ import type { ClaimLinkIdentity } from '@/claims/types'; import type { IdentityId, ProviderId } from '@/identities/types'; import type { Host, Port } from '@/network/types'; -import type { Gestalt } from '@/gestalts/types'; import fs from 'fs'; import path from 'path'; import os from 'os'; @@ -16,7 +15,6 @@ import { KeyManager } from '@/keys'; import { ACL } from '@/acl'; import { Sigchain } from '@/sigchain'; import Proxy from '@/network/Proxy'; -import { poll } from '@/utils'; import * as nodesUtils from '@/nodes/utils'; import * as claimsUtils from '@/claims/utils'; import * as discoveryErrors from '@/discovery/errors'; @@ -251,34 +249,15 @@ describe('Discovery', () => { logger, }); await discovery.queueDiscoveryByNode(nodeA.keyManager.getNodeId()); - const gestalt = await poll( - async () => { - const gestalts = await poll>( - async () => { - return await gestaltGraph.getGestalts(); - }, - (_, result) => { - if (result.length === 1) return true; - return false; - }, - 100, - ); - return gestalts[0]; - }, - (_, result) => { - if (result === undefined) return false; - if (Object.keys(result.matrix).length === 3) return true; - return false; - }, - 100, - ); - const gestaltMatrix = gestalt.matrix; - const gestaltNodes = gestalt.nodes; - const gestaltIdentities = gestalt.identities; + await discovery.waitForDrained(); + const gestalt = await gestaltGraph.getGestalts(); + const gestaltMatrix = gestalt[0].matrix; + const gestaltNodes = gestalt[0].nodes; + const gestaltIdentities = gestalt[0].identities; expect(Object.keys(gestaltMatrix)).toHaveLength(3); expect(Object.keys(gestaltNodes)).toHaveLength(2); expect(Object.keys(gestaltIdentities)).toHaveLength(1); - const gestaltString = JSON.stringify(gestalt); + const gestaltString = JSON.stringify(gestalt[0]); expect(gestaltString).toContain( nodesUtils.encodeNodeId(nodeA.keyManager.getNodeId()), ); @@ -304,27 +283,8 @@ describe('Discovery', () => { logger, }); await discovery.queueDiscoveryByIdentity(testToken.providerId, identityId); - const gestalt = await poll( - async () => { - const gestalts = await poll>( - async () => { - return await gestaltGraph.getGestalts(); - }, - (_, result) => { - if (result.length === 1) return true; - return false; - }, - 100, - ); - return gestalts[0]; - }, - (_, result) => { - if (result === undefined) return false; - if (Object.keys(result.matrix).length === 3) return true; - return false; - }, - 100, - ); + await discovery.waitForDrained(); + const gestalt = (await gestaltGraph.getGestalts())[0]; const gestaltMatrix = gestalt.matrix; const gestaltNodes = gestalt.nodes; const gestaltIdentities = gestalt.identities; @@ -357,27 +317,8 @@ describe('Discovery', () => { logger, }); await discovery.queueDiscoveryByNode(nodeA.keyManager.getNodeId()); - const gestalt1 = await poll( - async () => { - const gestalts = await poll>( - async () => { - return await gestaltGraph.getGestalts(); - }, - (_, result) => { - if (result.length === 1) return true; - return false; - }, - 100, - ); - return gestalts[0]; - }, - (_, result) => { - if (result === undefined) return false; - if (Object.keys(result.matrix).length === 3) return true; - return false; - }, - 100, - ); + await discovery.waitForDrained(); + const gestalt1 = (await gestaltGraph.getGestalts())[0]; const gestaltMatrix1 = gestalt1.matrix; const gestaltNodes1 = gestalt1.nodes; const gestaltIdentities1 = gestalt1.identities; @@ -410,27 +351,8 @@ describe('Discovery', () => { // Note that eventually we would like to add in a system of revisiting // already discovered vertices, however for now we must do this manually. await discovery.queueDiscoveryByNode(nodeA.keyManager.getNodeId()); - const gestalt2 = await poll( - async () => { - const gestalts = await poll>( - async () => { - return await gestaltGraph.getGestalts(); - }, - (_, result) => { - if (result.length === 1) return true; - return false; - }, - 100, - ); - return gestalts[0]; - }, - (_, result) => { - if (result === undefined) return false; - if (Object.keys(result.matrix).length === 4) return true; - return false; - }, - 100, - ); + await discovery.waitForDrained(); + const gestalt2 = (await gestaltGraph.getGestalts())[0]; const gestaltMatrix2 = gestalt2.matrix; const gestaltNodes2 = gestalt2.nodes; const gestaltIdentities2 = gestalt2.identities; @@ -470,27 +392,8 @@ describe('Discovery', () => { await discovery.queueDiscoveryByNode(nodeA.keyManager.getNodeId()); await discovery.stop(); await discovery.start(); - const gestalt = await poll( - async () => { - const gestalts = await poll>( - async () => { - return await gestaltGraph.getGestalts(); - }, - (_, result) => { - if (result.length === 1) return true; - return false; - }, - 100, - ); - return gestalts[0]; - }, - (_, result) => { - if (result === undefined) return false; - if (Object.keys(result.matrix).length === 3) return true; - return false; - }, - 100, - ); + await discovery.waitForDrained(); + const gestalt = (await gestaltGraph.getGestalts())[0]; const gestaltMatrix = gestalt.matrix; const gestaltNodes = gestalt.nodes; const gestaltIdentities = gestalt.identities; From 68412c797160c6933c757c7c8f4ccf4dcf2cc2d0 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 17 May 2022 11:17:19 +1000 Subject: [PATCH 027/137] fix: removing sigchain.transaction --- src/agent/service/nodesCrossSignClaim.ts | 248 +++++++++++------------ src/nodes/NodeManager.ts | 231 +++++++++++---------- 2 files changed, 245 insertions(+), 234 deletions(-) diff --git a/src/agent/service/nodesCrossSignClaim.ts b/src/agent/service/nodesCrossSignClaim.ts index 45af67a8d..59b9cac1a 100644 --- a/src/agent/service/nodesCrossSignClaim.ts +++ b/src/agent/service/nodesCrossSignClaim.ts @@ -28,136 +28,134 @@ function nodesCrossSignClaim({ ) => { const genClaims = grpcUtils.generatorDuplex(call, true); try { - await sigchain.transaction(async (sigchain) => { - const readStatus = await genClaims.read(); - // If nothing to read, end and destroy - if (readStatus.done) { - throw new claimsErrors.ErrorEmptyStream(); - } - const receivedMessage = readStatus.value; - const intermediaryClaimMessage = receivedMessage.getSinglySignedClaim(); - if (!intermediaryClaimMessage) { - throw new claimsErrors.ErrorUndefinedSinglySignedClaim(); - } - const intermediarySignature = intermediaryClaimMessage.getSignature(); - if (!intermediarySignature) { - throw new claimsErrors.ErrorUndefinedSignature(); - } + const readStatus = await genClaims.read(); + // If nothing to read, end and destroy + if (readStatus.done) { + throw new claimsErrors.ErrorEmptyStream(); + } + const receivedMessage = readStatus.value; + const intermediaryClaimMessage = receivedMessage.getSinglySignedClaim(); + if (!intermediaryClaimMessage) { + throw new claimsErrors.ErrorUndefinedSinglySignedClaim(); + } + const intermediarySignature = intermediaryClaimMessage.getSignature(); + if (!intermediarySignature) { + throw new claimsErrors.ErrorUndefinedSignature(); + } - // 3. X --> responds with double signing the Y signed claim, and also --> Y - // bundles it with its own signed claim (intermediate) - // Reconstruct the claim to verify its signature - const constructedIntermediaryClaim: ClaimIntermediary = { - payload: intermediaryClaimMessage.getPayload(), - signature: { + // 3. X --> responds with double signing the Y signed claim, and also --> Y + // bundles it with its own signed claim (intermediate) + // Reconstruct the claim to verify its signature + const constructedIntermediaryClaim: ClaimIntermediary = { + payload: intermediaryClaimMessage.getPayload(), + signature: { + protected: intermediarySignature.getProtected(), + signature: intermediarySignature.getSignature(), + }, + }; + // Get the sender's node ID from the claim + const constructedEncodedClaim: ClaimEncoded = { + payload: intermediaryClaimMessage.getPayload(), + signatures: [ + { protected: intermediarySignature.getProtected(), signature: intermediarySignature.getSignature(), }, - }; - // Get the sender's node ID from the claim - const constructedEncodedClaim: ClaimEncoded = { - payload: intermediaryClaimMessage.getPayload(), - signatures: [ - { - protected: intermediarySignature.getProtected(), - signature: intermediarySignature.getSignature(), - }, - ], - }; - const decodedClaim = claimsUtils.decodeClaim(constructedEncodedClaim); - const payloadData = decodedClaim.payload.data; - if (payloadData.type !== 'node') { - throw new claimsErrors.ErrorNodesClaimType(); - } - const { - nodeId, - }: { - nodeId: NodeId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [['nodeId'], () => validationUtils.parseNodeId(value)], - () => value, - ); - }, - { - nodeId: payloadData.node1, - }, - ); - // Verify the claim - const senderPublicKey = await nodeManager.getPublicKey(nodeId); - const verified = await claimsUtils.verifyClaimSignature( - constructedEncodedClaim, - senderPublicKey, - ); - if (!verified) { - throw new claimsErrors.ErrorSinglySignedClaimVerificationFailed(); - } - // If verified, add your own signature to the received claim - const doublySignedClaim = await claimsUtils.signIntermediaryClaim({ - claim: constructedIntermediaryClaim, - privateKey: keyManager.getRootKeyPairPem().privateKey, - signeeNodeId: nodesUtils.encodeNodeId(keyManager.getNodeId()), - }); - // Then create your own intermediary node claim (from X -> Y) - const singlySignedClaim = await sigchain.createIntermediaryClaim({ - type: 'node', - node1: nodesUtils.encodeNodeId(keyManager.getNodeId()), - node2: payloadData.node1, - }); - // Should never be reached, but just for type safety - if (!doublySignedClaim.payload || !singlySignedClaim.payload) { - throw new claimsErrors.ErrorClaimsUndefinedClaimPayload(); - } - // Write both these claims to a message to send - const crossSignMessage = claimsUtils.createCrossSignMessage({ - singlySignedClaim, - doublySignedClaim, - }); - await genClaims.write(crossSignMessage); - // 4. We expect to receive our singly signed claim we sent to now be a - // doubly signed claim (signed by the other node). - const responseStatus = await genClaims.read(); - if (responseStatus.done) { - throw new claimsErrors.ErrorEmptyStream(); - } - const receivedResponse = responseStatus.value; - const receivedDoublySignedClaimMessage = - receivedResponse.getDoublySignedClaim(); - if (!receivedDoublySignedClaimMessage) { - throw new claimsErrors.ErrorUndefinedDoublySignedClaim(); - } - // Reconstruct the expected object from message - const constructedDoublySignedClaim: ClaimEncoded = { - payload: receivedDoublySignedClaimMessage.getPayload(), - signatures: receivedDoublySignedClaimMessage - .getSignaturesList() - .map((sMsg) => { - return { - protected: sMsg.getProtected(), - signature: sMsg.getSignature(), - }; - }), - }; - // Verify the doubly signed claim with both our public key, and the sender's - const verifiedDoubly = - (await claimsUtils.verifyClaimSignature( - constructedDoublySignedClaim, - keyManager.getRootKeyPairPem().publicKey, - )) && - (await claimsUtils.verifyClaimSignature( - constructedDoublySignedClaim, - senderPublicKey, - )); - if (!verifiedDoubly) { - throw new claimsErrors.ErrorDoublySignedClaimVerificationFailed(); - } - // If verified, then we can safely add to our sigchain - await sigchain.addExistingClaim(constructedDoublySignedClaim); - // Close the stream - await genClaims.next(null); - return; + ], + }; + const decodedClaim = claimsUtils.decodeClaim(constructedEncodedClaim); + const payloadData = decodedClaim.payload.data; + if (payloadData.type !== 'node') { + throw new claimsErrors.ErrorNodesClaimType(); + } + const { + nodeId, + }: { + nodeId: NodeId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [['nodeId'], () => validationUtils.parseNodeId(value)], + () => value, + ); + }, + { + nodeId: payloadData.node1, + }, + ); + // Verify the claim + const senderPublicKey = await nodeManager.getPublicKey(nodeId); + const verified = await claimsUtils.verifyClaimSignature( + constructedEncodedClaim, + senderPublicKey, + ); + if (!verified) { + throw new claimsErrors.ErrorSinglySignedClaimVerificationFailed(); + } + // If verified, add your own signature to the received claim + const doublySignedClaim = await claimsUtils.signIntermediaryClaim({ + claim: constructedIntermediaryClaim, + privateKey: keyManager.getRootKeyPairPem().privateKey, + signeeNodeId: nodesUtils.encodeNodeId(keyManager.getNodeId()), }); + // Then create your own intermediary node claim (from X -> Y) + const singlySignedClaim = await sigchain.createIntermediaryClaim({ + type: 'node', + node1: nodesUtils.encodeNodeId(keyManager.getNodeId()), + node2: payloadData.node1, + }); + // Should never be reached, but just for type safety + if (!doublySignedClaim.payload || !singlySignedClaim.payload) { + throw new claimsErrors.ErrorClaimsUndefinedClaimPayload(); + } + // Write both these claims to a message to send + const crossSignMessage = claimsUtils.createCrossSignMessage({ + singlySignedClaim, + doublySignedClaim, + }); + await genClaims.write(crossSignMessage); + // 4. We expect to receive our singly signed claim we sent to now be a + // doubly signed claim (signed by the other node). + const responseStatus = await genClaims.read(); + if (responseStatus.done) { + throw new claimsErrors.ErrorEmptyStream(); + } + const receivedResponse = responseStatus.value; + const receivedDoublySignedClaimMessage = + receivedResponse.getDoublySignedClaim(); + if (!receivedDoublySignedClaimMessage) { + throw new claimsErrors.ErrorUndefinedDoublySignedClaim(); + } + // Reconstruct the expected object from message + const constructedDoublySignedClaim: ClaimEncoded = { + payload: receivedDoublySignedClaimMessage.getPayload(), + signatures: receivedDoublySignedClaimMessage + .getSignaturesList() + .map((sMsg) => { + return { + protected: sMsg.getProtected(), + signature: sMsg.getSignature(), + }; + }), + }; + // Verify the doubly signed claim with both our public key, and the sender's + const verifiedDoubly = + (await claimsUtils.verifyClaimSignature( + constructedDoublySignedClaim, + keyManager.getRootKeyPairPem().publicKey, + )) && + (await claimsUtils.verifyClaimSignature( + constructedDoublySignedClaim, + senderPublicKey, + )); + if (!verifiedDoubly) { + throw new claimsErrors.ErrorDoublySignedClaimVerificationFailed(); + } + // If verified, then we can safely add to our sigchain + await sigchain.addExistingClaim(constructedDoublySignedClaim); + // Close the stream + await genClaims.next(null); + return; } catch (e) { await genClaims.throw(e); logger.error(e); diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 8035f0bfa..61820d706 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -1,4 +1,4 @@ -import type { DB } from '@matrixai/db'; +import type { DB, DBTransaction } from '@matrixai/db'; import type NodeConnectionManager from './NodeConnectionManager'; import type NodeGraph from './NodeGraph'; import type KeyManager from '../keys/KeyManager'; @@ -182,120 +182,125 @@ class NodeManager { * Call this function upon receiving a "claim node request" notification from * another node. */ - public async claimNode(targetNodeId: NodeId): Promise { - await this.sigchain.transaction(async (sigchain) => { - // 2. Create your intermediary claim - const singlySignedClaim = await sigchain.createIntermediaryClaim({ + public async claimNode( + targetNodeId: NodeId, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => { + return this.claimNode(targetNodeId, tran); + }); + } + + // 2. Create your intermediary claim + const singlySignedClaim = await this.sigchain.createIntermediaryClaim( + { type: 'node', node1: nodesUtils.encodeNodeId(this.keyManager.getNodeId()), node2: nodesUtils.encodeNodeId(targetNodeId), - }); - let doublySignedClaim: ClaimEncoded; - await this.nodeConnectionManager.withConnF( - targetNodeId, - async (connection) => { - const client = connection.getClient(); - const genClaims = client.nodesCrossSignClaim(); - try { - // 2. Set up the intermediary claim message (the singly signed claim) to send - const crossSignMessage = claimsUtils.createCrossSignMessage({ - singlySignedClaim: singlySignedClaim, - }); - await genClaims.write(crossSignMessage); // Get the generator here - // 3. We expect to receieve our singly signed claim we sent to now be a - // doubly signed claim (signed by the other node), as well as a singly - // signed claim to be signed by us - const readStatus = await genClaims.read(); - // If nothing to read, end and destroy - if (readStatus.done) { - throw new claimsErrors.ErrorEmptyStream(); - } - const receivedMessage = readStatus.value; - const intermediaryClaimMessage = - receivedMessage.getSinglySignedClaim(); - const doublySignedClaimMessage = - receivedMessage.getDoublySignedClaim(); - // Ensure all of our expected messages are defined - if (!intermediaryClaimMessage) { - throw new claimsErrors.ErrorUndefinedSinglySignedClaim(); - } - const intermediaryClaimSignature = - intermediaryClaimMessage.getSignature(); - if (!intermediaryClaimSignature) { - throw new claimsErrors.ErrorUndefinedSignature(); - } - if (!doublySignedClaimMessage) { - throw new claimsErrors.ErrorUndefinedDoublySignedClaim(); - } - // Reconstruct the expected objects from the messages - const constructedIntermediaryClaim = - claimsUtils.reconstructClaimIntermediary( - intermediaryClaimMessage, - ); - const constructedDoublySignedClaim = - claimsUtils.reconstructClaimEncoded(doublySignedClaimMessage); - // Verify the singly signed claim with the sender's public key - const senderPublicKey = - connection.getExpectedPublicKey(targetNodeId); - if (!senderPublicKey) { - throw new nodesErrors.ErrorNodeConnectionPublicKeyNotFound(); - } - const verifiedSingly = - await claimsUtils.verifyIntermediaryClaimSignature( - constructedIntermediaryClaim, - senderPublicKey, - ); - if (!verifiedSingly) { - throw new claimsErrors.ErrorSinglySignedClaimVerificationFailed(); - } - // Verify the doubly signed claim with both our public key, and the sender's - const verifiedDoubly = - (await claimsUtils.verifyClaimSignature( - constructedDoublySignedClaim, - this.keyManager.getRootKeyPairPem().publicKey, - )) && - (await claimsUtils.verifyClaimSignature( - constructedDoublySignedClaim, - senderPublicKey, - )); - if (!verifiedDoubly) { - throw new claimsErrors.ErrorDoublySignedClaimVerificationFailed(); - } - // 4. X <- responds with double signing the X signed claim <- Y - const doublySignedClaimResponse = - await claimsUtils.signIntermediaryClaim({ - claim: constructedIntermediaryClaim, - privateKey: this.keyManager.getRootKeyPairPem().privateKey, - signeeNodeId: nodesUtils.encodeNodeId( - this.keyManager.getNodeId(), - ), - }); - // Should never be reached, but just for type safety - if (!doublySignedClaimResponse.payload) { - throw new claimsErrors.ErrorClaimsUndefinedClaimPayload(); - } - const crossSignMessageResponse = claimsUtils.createCrossSignMessage( - { - doublySignedClaim: doublySignedClaimResponse, - }, + }, + tran, + ); + let doublySignedClaim: ClaimEncoded; + await this.nodeConnectionManager.withConnF( + targetNodeId, + async (connection) => { + const client = connection.getClient(); + const genClaims = client.nodesCrossSignClaim(); + try { + // 2. Set up the intermediary claim message (the singly signed claim) to send + const crossSignMessage = claimsUtils.createCrossSignMessage({ + singlySignedClaim: singlySignedClaim, + }); + await genClaims.write(crossSignMessage); // Get the generator here + // 3. We expect to receive our singly signed claim we sent to now be a + // doubly signed claim (signed by the other node), as well as a singly + // signed claim to be signed by us + const readStatus = await genClaims.read(); + // If nothing to read, end and destroy + if (readStatus.done) { + throw new claimsErrors.ErrorEmptyStream(); + } + const receivedMessage = readStatus.value; + const intermediaryClaimMessage = + receivedMessage.getSinglySignedClaim(); + const doublySignedClaimMessage = + receivedMessage.getDoublySignedClaim(); + // Ensure all of our expected messages are defined + if (!intermediaryClaimMessage) { + throw new claimsErrors.ErrorUndefinedSinglySignedClaim(); + } + const intermediaryClaimSignature = + intermediaryClaimMessage.getSignature(); + if (!intermediaryClaimSignature) { + throw new claimsErrors.ErrorUndefinedSignature(); + } + if (!doublySignedClaimMessage) { + throw new claimsErrors.ErrorUndefinedDoublySignedClaim(); + } + // Reconstruct the expected objects from the messages + const constructedIntermediaryClaim = + claimsUtils.reconstructClaimIntermediary(intermediaryClaimMessage); + const constructedDoublySignedClaim = + claimsUtils.reconstructClaimEncoded(doublySignedClaimMessage); + // Verify the singly signed claim with the sender's public key + const senderPublicKey = connection.getExpectedPublicKey(targetNodeId); + if (!senderPublicKey) { + throw new nodesErrors.ErrorNodeConnectionPublicKeyNotFound(); + } + const verifiedSingly = + await claimsUtils.verifyIntermediaryClaimSignature( + constructedIntermediaryClaim, + senderPublicKey, ); - await genClaims.write(crossSignMessageResponse); - - // Check the stream is closed (should be closed by other side) - const finalResponse = await genClaims.read(); - if (finalResponse.done != null) { - await genClaims.next(null); - } + if (!verifiedSingly) { + throw new claimsErrors.ErrorSinglySignedClaimVerificationFailed(); + } + // Verify the doubly signed claim with both our public key, and the sender's + const verifiedDoubly = + (await claimsUtils.verifyClaimSignature( + constructedDoublySignedClaim, + this.keyManager.getRootKeyPairPem().publicKey, + )) && + (await claimsUtils.verifyClaimSignature( + constructedDoublySignedClaim, + senderPublicKey, + )); + if (!verifiedDoubly) { + throw new claimsErrors.ErrorDoublySignedClaimVerificationFailed(); + } + // 4. X <- responds with double signing the X signed claim <- Y + const doublySignedClaimResponse = + await claimsUtils.signIntermediaryClaim({ + claim: constructedIntermediaryClaim, + privateKey: this.keyManager.getRootKeyPairPem().privateKey, + signeeNodeId: nodesUtils.encodeNodeId( + this.keyManager.getNodeId(), + ), + }); + // Should never be reached, but just for type safety + if (!doublySignedClaimResponse.payload) { + throw new claimsErrors.ErrorClaimsUndefinedClaimPayload(); + } + const crossSignMessageResponse = claimsUtils.createCrossSignMessage({ + doublySignedClaim: doublySignedClaimResponse, + }); + await genClaims.write(crossSignMessageResponse); - doublySignedClaim = constructedDoublySignedClaim; - } catch (e) { - await genClaims.throw(e); - throw e; + // Check the stream is closed (should be closed by other side) + const finalResponse = await genClaims.read(); + if (finalResponse.done != null) { + await genClaims.next(null); } - await sigchain.addExistingClaim(doublySignedClaim); - }, - ); - }); + + doublySignedClaim = constructedDoublySignedClaim; + } catch (e) { + await genClaims.throw(e); + throw e; + } + await this.sigchain.addExistingClaim(doublySignedClaim, tran); + }, + ); } /** @@ -306,6 +311,7 @@ class NodeManager { public async getNodeAddress( nodeId: NodeId, ): Promise { + // FIXME: use tran return await this.nodeGraph.getNode(nodeId); } @@ -315,6 +321,7 @@ class NodeManager { * @returns true if the node exists in the table, false otherwise */ public async knowsNode(targetNodeId: NodeId): Promise { + // FIXME: use tran return await this.nodeGraph.knowsNode(targetNodeId); } @@ -322,6 +329,7 @@ class NodeManager { * Gets the specified bucket from the NodeGraph */ public async getBucket(bucketIndex: number): Promise { + // FIXME: use tran return await this.nodeGraph.getBucket(bucketIndex); } @@ -332,6 +340,7 @@ class NodeManager { nodeId: NodeId, nodeAddress: NodeAddress, ): Promise { + // FIXME: use tran return await this.nodeGraph.setNode(nodeId, nodeAddress); } @@ -342,6 +351,7 @@ class NodeManager { nodeId: NodeId, nodeAddress?: NodeAddress, ): Promise { + // FIXME: use tran return await this.nodeGraph.updateNode(nodeId, nodeAddress); } @@ -349,6 +359,7 @@ class NodeManager { * Removes a node from the NodeGraph */ public async unsetNode(nodeId: NodeId): Promise { + // FIXME: use tran return await this.nodeGraph.unsetNode(nodeId); } @@ -356,6 +367,7 @@ class NodeManager { * Gets all buckets from the NodeGraph */ public async getAllBuckets(): Promise> { + // FIXME: use tran return await this.nodeGraph.getAllBuckets(); } @@ -364,6 +376,7 @@ class NodeManager { * to the new node ID. */ public async refreshBuckets(): Promise { + // FIXME: use tran return await this.nodeGraph.refreshBuckets(); } } From 497583f74be8e608604978167d7c2367d93fc333 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 17 May 2022 12:00:35 +1000 Subject: [PATCH 028/137] fix: added locking back into sigchain Sequence numbers and claim ids needed locking due to serialisation concerns --- src/PolykeyAgent.ts | 1 + src/agent/service/index.ts | 4 + src/agent/service/nodesCrossSignClaim.ts | 272 ++++++++++++----------- src/sigchain/Sigchain.ts | 75 ++++--- tests/nodes/NodeManager.test.ts | 10 +- tests/sigchain/Sigchain.test.ts | 38 +++- 6 files changed, 221 insertions(+), 179 deletions(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index 855b3f908..b172f1fd2 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -549,6 +549,7 @@ class PolykeyAgent { await this.status.start({ pid: process.pid }); await this.schema.start({ fresh }); const agentService = createAgentService({ + db: this.db, keyManager: this.keyManager, vaultManager: this.vaultManager, nodeManager: this.nodeManager, diff --git a/src/agent/service/index.ts b/src/agent/service/index.ts index caa8c60ed..6342c2ba5 100644 --- a/src/agent/service/index.ts +++ b/src/agent/service/index.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type KeyManager from '../../keys/KeyManager'; import type VaultManager from '../../vaults/VaultManager'; import type NodeGraph from '../../nodes/NodeGraph'; @@ -25,9 +26,11 @@ import * as agentUtils from '../utils'; function createService({ proxy, + db, logger = new Logger(createService.name), ...containerRest }: { + db: DB; keyManager: KeyManager; vaultManager: VaultManager; nodeConnectionManager: NodeConnectionManager; @@ -43,6 +46,7 @@ function createService({ const connectionInfoGet = agentUtils.connectionInfoGetter(proxy); const container = { ...containerRest, + db, logger, connectionInfoGet: connectionInfoGet, }; diff --git a/src/agent/service/nodesCrossSignClaim.ts b/src/agent/service/nodesCrossSignClaim.ts index 59b9cac1a..b21ed882c 100644 --- a/src/agent/service/nodesCrossSignClaim.ts +++ b/src/agent/service/nodesCrossSignClaim.ts @@ -1,23 +1,29 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { ClaimEncoded, ClaimIntermediary } from '../../claims/types'; -import type { NodeManager } from '../../nodes'; +import type NodeManager from '../../nodes/NodeManager'; import type { NodeId } from '../../nodes/types'; -import type { Sigchain } from '../../sigchain'; -import type { KeyManager } from '../../keys'; +import type Sigchain from '../../sigchain/Sigchain'; +import type KeyManager from '../../keys/KeyManager'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { utils as claimsUtils, errors as claimsErrors } from '../../claims'; -import { utils as nodesUtils } from '../../nodes'; -import { validateSync, utils as validationUtils } from '../../validation'; +import { withF } from '@matrixai/resources'; +import * as grpcUtils from '../../grpc/utils'; +import * as claimsUtils from '../../claims/utils'; +import * as claimsErrors from '../../claims/errors'; +import * as nodesUtils from '../../nodes/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; function nodesCrossSignClaim({ + db, keyManager, nodeManager, sigchain, logger, }: { + db: DB; keyManager: KeyManager; nodeManager: NodeManager; sigchain: Sigchain; @@ -28,134 +34,138 @@ function nodesCrossSignClaim({ ) => { const genClaims = grpcUtils.generatorDuplex(call, true); try { - const readStatus = await genClaims.read(); - // If nothing to read, end and destroy - if (readStatus.done) { - throw new claimsErrors.ErrorEmptyStream(); - } - const receivedMessage = readStatus.value; - const intermediaryClaimMessage = receivedMessage.getSinglySignedClaim(); - if (!intermediaryClaimMessage) { - throw new claimsErrors.ErrorUndefinedSinglySignedClaim(); - } - const intermediarySignature = intermediaryClaimMessage.getSignature(); - if (!intermediarySignature) { - throw new claimsErrors.ErrorUndefinedSignature(); - } - - // 3. X --> responds with double signing the Y signed claim, and also --> Y - // bundles it with its own signed claim (intermediate) - // Reconstruct the claim to verify its signature - const constructedIntermediaryClaim: ClaimIntermediary = { - payload: intermediaryClaimMessage.getPayload(), - signature: { - protected: intermediarySignature.getProtected(), - signature: intermediarySignature.getSignature(), - }, - }; - // Get the sender's node ID from the claim - const constructedEncodedClaim: ClaimEncoded = { - payload: intermediaryClaimMessage.getPayload(), - signatures: [ - { + await withF([db.transaction()], async ([tran]) => { + const readStatus = await genClaims.read(); + // If nothing to read, end and destroy + if (readStatus.done) { + throw new claimsErrors.ErrorEmptyStream(); + } + const receivedMessage = readStatus.value; + const intermediaryClaimMessage = receivedMessage.getSinglySignedClaim(); + if (!intermediaryClaimMessage) { + throw new claimsErrors.ErrorUndefinedSinglySignedClaim(); + } + const intermediarySignature = intermediaryClaimMessage.getSignature(); + if (!intermediarySignature) { + throw new claimsErrors.ErrorUndefinedSignature(); + } + // 3. X --> responds with double signing the Y signed claim, and also --> Y + // bundles it with its own signed claim (intermediate) + // Reconstruct the claim to verify its signature + const constructedIntermediaryClaim: ClaimIntermediary = { + payload: intermediaryClaimMessage.getPayload(), + signature: { protected: intermediarySignature.getProtected(), signature: intermediarySignature.getSignature(), }, - ], - }; - const decodedClaim = claimsUtils.decodeClaim(constructedEncodedClaim); - const payloadData = decodedClaim.payload.data; - if (payloadData.type !== 'node') { - throw new claimsErrors.ErrorNodesClaimType(); - } - const { - nodeId, - }: { - nodeId: NodeId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [['nodeId'], () => validationUtils.parseNodeId(value)], - () => value, - ); - }, - { - nodeId: payloadData.node1, - }, - ); - // Verify the claim - const senderPublicKey = await nodeManager.getPublicKey(nodeId); - const verified = await claimsUtils.verifyClaimSignature( - constructedEncodedClaim, - senderPublicKey, - ); - if (!verified) { - throw new claimsErrors.ErrorSinglySignedClaimVerificationFailed(); - } - // If verified, add your own signature to the received claim - const doublySignedClaim = await claimsUtils.signIntermediaryClaim({ - claim: constructedIntermediaryClaim, - privateKey: keyManager.getRootKeyPairPem().privateKey, - signeeNodeId: nodesUtils.encodeNodeId(keyManager.getNodeId()), - }); - // Then create your own intermediary node claim (from X -> Y) - const singlySignedClaim = await sigchain.createIntermediaryClaim({ - type: 'node', - node1: nodesUtils.encodeNodeId(keyManager.getNodeId()), - node2: payloadData.node1, - }); - // Should never be reached, but just for type safety - if (!doublySignedClaim.payload || !singlySignedClaim.payload) { - throw new claimsErrors.ErrorClaimsUndefinedClaimPayload(); - } - // Write both these claims to a message to send - const crossSignMessage = claimsUtils.createCrossSignMessage({ - singlySignedClaim, - doublySignedClaim, - }); - await genClaims.write(crossSignMessage); - // 4. We expect to receive our singly signed claim we sent to now be a - // doubly signed claim (signed by the other node). - const responseStatus = await genClaims.read(); - if (responseStatus.done) { - throw new claimsErrors.ErrorEmptyStream(); - } - const receivedResponse = responseStatus.value; - const receivedDoublySignedClaimMessage = - receivedResponse.getDoublySignedClaim(); - if (!receivedDoublySignedClaimMessage) { - throw new claimsErrors.ErrorUndefinedDoublySignedClaim(); - } - // Reconstruct the expected object from message - const constructedDoublySignedClaim: ClaimEncoded = { - payload: receivedDoublySignedClaimMessage.getPayload(), - signatures: receivedDoublySignedClaimMessage - .getSignaturesList() - .map((sMsg) => { - return { - protected: sMsg.getProtected(), - signature: sMsg.getSignature(), - }; - }), - }; - // Verify the doubly signed claim with both our public key, and the sender's - const verifiedDoubly = - (await claimsUtils.verifyClaimSignature( - constructedDoublySignedClaim, - keyManager.getRootKeyPairPem().publicKey, - )) && - (await claimsUtils.verifyClaimSignature( - constructedDoublySignedClaim, + }; + // Get the sender's node ID from the claim + const constructedEncodedClaim: ClaimEncoded = { + payload: intermediaryClaimMessage.getPayload(), + signatures: [ + { + protected: intermediarySignature.getProtected(), + signature: intermediarySignature.getSignature(), + }, + ], + }; + const decodedClaim = claimsUtils.decodeClaim(constructedEncodedClaim); + const payloadData = decodedClaim.payload.data; + if (payloadData.type !== 'node') { + throw new claimsErrors.ErrorNodesClaimType(); + } + const { + nodeId, + }: { + nodeId: NodeId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [['nodeId'], () => validationUtils.parseNodeId(value)], + () => value, + ); + }, + { + nodeId: payloadData.node1, + }, + ); + // Verify the claim + const senderPublicKey = await nodeManager.getPublicKey(nodeId); + const verified = await claimsUtils.verifyClaimSignature( + constructedEncodedClaim, senderPublicKey, - )); - if (!verifiedDoubly) { - throw new claimsErrors.ErrorDoublySignedClaimVerificationFailed(); - } - // If verified, then we can safely add to our sigchain - await sigchain.addExistingClaim(constructedDoublySignedClaim); - // Close the stream - await genClaims.next(null); - return; + ); + if (!verified) { + throw new claimsErrors.ErrorSinglySignedClaimVerificationFailed(); + } + // If verified, add your own signature to the received claim + const doublySignedClaim = await claimsUtils.signIntermediaryClaim({ + claim: constructedIntermediaryClaim, + privateKey: keyManager.getRootKeyPairPem().privateKey, + signeeNodeId: nodesUtils.encodeNodeId(keyManager.getNodeId()), + }); + // Then create your own intermediary node claim (from X -> Y) + const singlySignedClaim = await sigchain.createIntermediaryClaim( + { + type: 'node', + node1: nodesUtils.encodeNodeId(keyManager.getNodeId()), + node2: payloadData.node1, + }, + tran, + ); + // Should never be reached, but just for type safety + if (!doublySignedClaim.payload || !singlySignedClaim.payload) { + throw new claimsErrors.ErrorClaimsUndefinedClaimPayload(); + } + // Write both these claims to a message to send + const crossSignMessage = claimsUtils.createCrossSignMessage({ + singlySignedClaim, + doublySignedClaim, + }); + await genClaims.write(crossSignMessage); + // 4. We expect to receive our singly signed claim we sent to now be a + // doubly signed claim (signed by the other node). + const responseStatus = await genClaims.read(); + if (responseStatus.done) { + throw new claimsErrors.ErrorEmptyStream(); + } + const receivedResponse = responseStatus.value; + const receivedDoublySignedClaimMessage = + receivedResponse.getDoublySignedClaim(); + if (!receivedDoublySignedClaimMessage) { + throw new claimsErrors.ErrorUndefinedDoublySignedClaim(); + } + // Reconstruct the expected object from message + const constructedDoublySignedClaim: ClaimEncoded = { + payload: receivedDoublySignedClaimMessage.getPayload(), + signatures: receivedDoublySignedClaimMessage + .getSignaturesList() + .map((sMsg) => { + return { + protected: sMsg.getProtected(), + signature: sMsg.getSignature(), + }; + }), + }; + // Verify the doubly signed claim with both our public key, and the sender's + const verifiedDoubly = + (await claimsUtils.verifyClaimSignature( + constructedDoublySignedClaim, + keyManager.getRootKeyPairPem().publicKey, + )) && + (await claimsUtils.verifyClaimSignature( + constructedDoublySignedClaim, + senderPublicKey, + )); + if (!verifiedDoubly) { + throw new claimsErrors.ErrorDoublySignedClaimVerificationFailed(); + } + // If verified, then we can safely add to our sigchain + await sigchain.addExistingClaim(constructedDoublySignedClaim, tran); + // Close the stream + await genClaims.next(null); + return; + }); } catch (e) { await genClaims.throw(e); logger.error(e); diff --git a/src/sigchain/Sigchain.ts b/src/sigchain/Sigchain.ts index 0a7f8bb65..25614e490 100644 --- a/src/sigchain/Sigchain.ts +++ b/src/sigchain/Sigchain.ts @@ -1,4 +1,4 @@ -import type { DB, DBTransaction, LevelPath } from '@matrixai/db'; +import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; import type { ChainDataEncoded } from './types'; import type { ClaimData, @@ -17,6 +17,7 @@ import { ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { utils as dbUtils } from '@matrixai/db'; +import { Lock, LockBox } from '@matrixai/async-locks'; import { withF } from '@matrixai/resources'; import * as sigchainErrors from './errors'; import * as claimsUtils from '../claims/utils'; @@ -32,6 +33,7 @@ class Sigchain { protected logger: Logger; protected keyManager: KeyManager; protected db: DB; + protected locks: LockBox = new LockBox(); // Top-level database for the sigchain domain protected sigchainDbPath: LevelPath = [this.constructor.name]; // ClaimId (the lexicographic integer of the sequence number) @@ -125,9 +127,16 @@ class Sigchain { @ready(new sigchainErrors.ErrorSigchainNotRunning()) public async withTransactionF( - f: (tran: DBTransaction) => Promise, + ...params: [...keys: Array, f: (tran: DBTransaction) => Promise] ): Promise { - return withF([this.db.transaction()], ([tran]) => f(tran)); + const f = params.pop() as (tran: DBTransaction) => Promise; + const lockRequests = (params as Array).map<[KeyPath, typeof Lock]>( + (key) => [key, Lock], + ); + return withF( + [this.db.transaction(), this.locks.lock(...lockRequests)], + ([tran]) => f(tran), + ); } /** @@ -171,9 +180,17 @@ class Sigchain { claimData: ClaimData, tran?: DBTransaction, ): Promise<[ClaimId, ClaimEncoded]> { + const claimId = this.generateClaimId(); + const claimIdPath = [...this.sigchainClaimsDbPath, claimId.toBuffer()]; + const sequenceNumberPath = [ + ...this.sigchainMetadataDbPath, + this.sequenceNumberKey, + ]; if (tran == null) { - return this.withTransactionF(async (tran) => - this.addClaim(claimData, tran), + return this.withTransactionF( + claimIdPath, + sequenceNumberPath, + async (tran) => this.addClaim(claimData, tran), ); } const prevSequenceNumber = await this.getSequenceNumber(tran); @@ -184,12 +201,8 @@ class Sigchain { data: claimData, }); // Add the claim to the sigchain database, and update the sequence number - const claimId = this.generateClaimId(); - await tran.put([...this.sigchainClaimsDbPath, claimId.toBuffer()], claim); - await tran.put( - [...this.sigchainMetadataDbPath, this.sequenceNumberKey], - newSequenceNumber, - ); + await tran.put(claimIdPath, claim); + await tran.put(sequenceNumberPath, newSequenceNumber); return [claimId, claim]; } @@ -206,9 +219,17 @@ class Sigchain { claim: ClaimEncoded, tran?: DBTransaction, ): Promise { + const claimId = this.generateClaimId(); + const claimIdPath = [...this.sigchainClaimsDbPath, claimId.toBuffer()]; + const sequenceNumberPath = [ + ...this.sigchainMetadataDbPath, + this.sequenceNumberKey, + ]; if (tran == null) { - return this.withTransactionF(async (tran) => - this.addExistingClaim(claim, tran), + return this.withTransactionF( + claimIdPath, + sequenceNumberPath, + async (tran) => this.addExistingClaim(claim, tran), ); } const decodedClaim = claimsUtils.decodeClaim(claim); @@ -221,14 +242,8 @@ class Sigchain { if (decodedClaim.payload.hPrev !== (await this.getHashPrevious(tran))) { throw new sigchainErrors.ErrorSigchainInvalidHash(); } - await tran.put( - [...this.sigchainClaimsDbPath, this.generateClaimId().toBuffer()], - claim, - ); - await tran.put( - [...this.sigchainMetadataDbPath, this.sequenceNumberKey], - expectedSequenceNumber, - ); + await tran.put(claimIdPath, claim); + await tran.put(sequenceNumberPath, expectedSequenceNumber); } /** @@ -240,8 +255,12 @@ class Sigchain { claimData: ClaimData, tran?: DBTransaction, ): Promise { + const sequenceNumberPath = [ + ...this.sigchainMetadataDbPath, + this.sequenceNumberKey, + ]; if (tran == null) { - return this.withTransactionF(async (tran) => + return this.withTransactionF(sequenceNumberPath, async (tran) => this.createIntermediaryClaim(claimData, tran), ); } @@ -314,12 +333,7 @@ class Sigchain { * @returns previous sequence number */ @ready(new sigchainErrors.ErrorSigchainNotRunning()) - public async getSequenceNumber(tran?: DBTransaction): Promise { - if (tran == null) { - return this.withTransactionF(async (tran) => - this.getSequenceNumber(tran), - ); - } + protected async getSequenceNumber(tran: DBTransaction): Promise { const sequenceNumber = await tran.get([ ...this.sigchainMetadataDbPath, this.sequenceNumberKey, @@ -336,10 +350,7 @@ class Sigchain { * Helper function to compute the hash of the previous claim. */ @ready(new sigchainErrors.ErrorSigchainNotRunning()) - public async getHashPrevious(tran?: DBTransaction): Promise { - if (tran == null) { - return this.withTransactionF(async (tran) => this.getHashPrevious(tran)); - } + protected async getHashPrevious(tran: DBTransaction): Promise { const prevSequenceNumber = await this.getLatestClaimId(tran); if (prevSequenceNumber == null) { // If no other claims, then null diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index f3de57cd8..0ac96ec27 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -321,8 +321,10 @@ describe(`${NodeManager.name} test`, () => { // Make sure to remove any side-effects after each test afterEach(async () => { - await x.sigchain.clearDB(); - await y.sigchain.clearDB(); + await x.sigchain.stop(); + await x.sigchain.start({ fresh: true }); + await y.sigchain.stop(); + await y.sigchain.start({ fresh: true }); }); test('can successfully cross sign a claim', async () => { @@ -332,10 +334,6 @@ describe(`${NodeManager.name} test`, () => { // 4. X <- sends doubly signed claim (X's intermediary) <- Y await y.nodeManager.claimNode(xNodeId); - // Check both sigchain locks are released - expect(x.sigchain.locked).toBe(false); - expect(y.sigchain.locked).toBe(false); - // Check X's sigchain state const xChain = await x.sigchain.getChainData(); expect(Object.keys(xChain).length).toBe(1); diff --git a/tests/sigchain/Sigchain.test.ts b/tests/sigchain/Sigchain.test.ts index e36a70e10..e53a4c67f 100644 --- a/tests/sigchain/Sigchain.test.ts +++ b/tests/sigchain/Sigchain.test.ts @@ -105,13 +105,13 @@ describe('Sigchain', () => { await expect(async () => { await sigchain.start(); }).rejects.toThrow(sigchainErrors.ErrorSigchainDestroyed); - await expect(async () => { - await sigchain.getSequenceNumber(); - }).rejects.toThrow(sigchainErrors.ErrorSigchainNotRunning); }); test('async start initialises the sequence number', async () => { const sigchain = await Sigchain.createSigchain({ keyManager, db, logger }); - const sequenceNumber = await sigchain.getSequenceNumber(); + const sequenceNumber = await sigchain.withTransactionF(async (tran) => + // @ts-ignore - get protected method + sigchain.getSequenceNumber(tran), + ); expect(sequenceNumber).toBe(0); await sigchain.stop(); }); @@ -249,8 +249,14 @@ describe('Sigchain', () => { // Create a claim // Firstly, check that we can add an existing claim if it's the first claim // in the sigchain - const hPrev1 = await sigchain.getHashPrevious(); - const seq1 = await sigchain.getSequenceNumber(); + const hPrev1 = await sigchain.withTransactionF(async (tran) => + // @ts-ignore - get protected method + sigchain.getHashPrevious(tran), + ); + const seq1 = await sigchain.withTransactionF(async (tran) => + // @ts-ignore - get protected method + sigchain.getSequenceNumber(tran), + ); expect(hPrev1).toBeNull(); expect(seq1).toBe(0); const claim1 = await claimsUtils.createClaim({ @@ -265,8 +271,14 @@ describe('Sigchain', () => { kid: nodeIdAEncoded, }); await sigchain.addExistingClaim(claim1); - const hPrev2 = await sigchain.getHashPrevious(); - const seq2 = await sigchain.getSequenceNumber(); + const hPrev2 = await sigchain.withTransactionF(async (tran) => + // @ts-ignore - get protected method + sigchain.getHashPrevious(tran), + ); + const seq2 = await sigchain.withTransactionF(async (tran) => + // @ts-ignore - get protected method + sigchain.getSequenceNumber(tran), + ); expect(hPrev2).not.toBeNull(); expect(seq2).toBe(1); @@ -283,8 +295,14 @@ describe('Sigchain', () => { kid: nodeIdAEncoded, }); await sigchain.addExistingClaim(claim2); - const hPrev3 = await sigchain.getHashPrevious(); - const seq3 = await sigchain.getSequenceNumber(); + const hPrev3 = await sigchain.withTransactionF(async (tran) => + // @ts-ignore - get protected method + sigchain.getHashPrevious(tran), + ); + const seq3 = await sigchain.withTransactionF(async (tran) => + // @ts-ignore - get protected method + sigchain.getSequenceNumber(tran), + ); expect(hPrev3).not.toBeNull(); expect(seq3).toBe(2); From c2de660efe7271e4183b6de6289e0055cda8c7e7 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 17 May 2022 12:51:10 +1000 Subject: [PATCH 029/137] fix: added locking back into notifications Notifications have strict ordering in the DB, therefore locking is required. --- src/notifications/NotificationsManager.ts | 258 ++++++++++++---------- 1 file changed, 138 insertions(+), 120 deletions(-) diff --git a/src/notifications/NotificationsManager.ts b/src/notifications/NotificationsManager.ts index 83eca6f7b..b2780000a 100644 --- a/src/notifications/NotificationsManager.ts +++ b/src/notifications/NotificationsManager.ts @@ -1,4 +1,4 @@ -import type { DB, DBTransaction, LevelPath } from '@matrixai/db'; +import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; import type { NotificationId, Notification, @@ -12,13 +12,13 @@ import type NodeConnectionManager from '../nodes/NodeConnectionManager'; import type { NodeId } from '../nodes/types'; import Logger from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; -import { Lock } from '@matrixai/async-locks'; +import { Lock, LockBox } from '@matrixai/async-locks'; import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { utils as idUtils } from '@matrixai/id'; -import * as resources from '@matrixai/resources'; +import { withF } from '@matrixai/resources'; import * as notificationsUtils from './utils'; import * as notificationsErrors from './errors'; import * as notificationsPB from '../proto/js/polykey/v1/notifications/notifications_pb'; @@ -77,7 +77,7 @@ class NotificationsManager { protected nodeManager: NodeManager; protected nodeConnectionManager: NodeConnectionManager; protected messageCap: number; - protected lock: Lock = new Lock(); + protected locks: LockBox = new LockBox(); /** * Top level stores MESSAGE_COUNT_KEY -> number (of messages) @@ -122,25 +122,34 @@ class NotificationsManager { public async start({ fresh = false, }: { fresh?: boolean } = {}): Promise { - await this.db.withTransactionF(async (tran) => { - this.logger.info(`Starting ${this.constructor.name}`); - if (fresh) { - await tran.clear(this.notificationsDbPath); - } + await withF( + [ + this.db.transaction(), + this.locks.lock([ + [...this.notificationsDbPath, MESSAGE_COUNT_KEY], + Lock, + ]), + ], + async ([tran]) => { + this.logger.info(`Starting ${this.constructor.name}`); + if (fresh) { + await tran.clear(this.notificationsDbPath); + } - // Getting latest ID and creating ID generator - let latestId: NotificationId | undefined; - const keyIterator = tran.iterator( - { limit: 1, reverse: true }, - this.notificationsMessagesDbPath, - ); - for await (const [key] of keyIterator) { - latestId = IdInternal.fromBuffer(key); - } - this.notificationIdGenerator = - notificationsUtils.createNotificationIdGenerator(latestId); - this.logger.info(`Started ${this.constructor.name}`); - }); + // Getting latest ID and creating ID generator + let latestId: NotificationId | undefined; + const keyIterator = tran.iterator( + { limit: 1, reverse: true }, + this.notificationsMessagesDbPath, + ); + for await (const [key] of keyIterator) { + latestId = IdInternal.fromBuffer(key); + } + this.notificationIdGenerator = + notificationsUtils.createNotificationIdGenerator(latestId); + this.logger.info(`Started ${this.constructor.name}`); + }, + ); } public async stop() { @@ -156,6 +165,20 @@ class NotificationsManager { this.logger.info(`Destroyed ${this.constructor.name}`); } + @ready(new notificationsErrors.ErrorNotificationsNotRunning()) + public async withTransactionF( + ...params: [...keys: Array, f: (tran: DBTransaction) => Promise] + ): Promise { + const f = params.pop() as (tran: DBTransaction) => Promise; + const lockRequests = (params as Array).map<[KeyPath, typeof Lock]>( + (key) => [key, Lock], + ); + return withF( + [this.db.transaction(), this.locks.lock(...lockRequests)], + ([tran]) => f(tran), + ); + } + /** * Send a notification to another node * The `data` parameter must match one of the NotificationData types outlined in ./types @@ -186,50 +209,45 @@ class NotificationsManager { * Receive a notification */ @ready(new notificationsErrors.ErrorNotificationsNotRunning()) - public async receiveNotification(notification: Notification): Promise { - return await resources.withF( - [this.db.transaction(), this.lock.lock()], - async ([tran]) => { - const nodePerms = await this.acl.getNodePerm( - nodesUtils.decodeNodeId(notification.senderId)!, - ); - if (nodePerms === undefined) { - throw new notificationsErrors.ErrorNotificationsPermissionsNotFound(); - } - // Only keep the message if the sending node has the correct permissions - if (Object.keys(nodePerms.gestalt).includes('notify')) { - // If the number stored in notificationsDb >= 10000 - let numMessages = await tran.get([ - ...this.notificationsDbPath, - MESSAGE_COUNT_KEY, - ]); - if (numMessages === undefined) { - numMessages = 0; - await tran.put([...this.notificationsDbPath, MESSAGE_COUNT_KEY], 0); - } - if (numMessages >= this.messageCap) { - // Remove the oldest notification from notificationsMessagesDb - const oldestId = await this.getOldestNotificationId(tran); - await this.removeNotification(oldestId!, tran); - } - // Store the new notification in notificationsMessagesDb - const notificationId = this.notificationIdGenerator(); - await tran.put( - [ - ...this.notificationsMessagesDbPath, - idUtils.toBuffer(notificationId), - ], - notification, - ); - // Number of messages += 1 - const newNumMessages = numMessages + 1; - await tran.put( - [...this.notificationsDbPath, MESSAGE_COUNT_KEY], - newNumMessages, - ); - } - }, + public async receiveNotification( + notification: Notification, + tran?: DBTransaction, + ): Promise { + const messageCountPath = [...this.notificationsDbPath, MESSAGE_COUNT_KEY]; + if (tran == null) { + return this.withTransactionF(messageCountPath, async (tran) => + this.receiveNotification(notification, tran), + ); + } + const nodePerms = await this.acl.getNodePerm( + nodesUtils.decodeNodeId(notification.senderId)!, ); + if (nodePerms === undefined) { + throw new notificationsErrors.ErrorNotificationsPermissionsNotFound(); + } + // Only keep the message if the sending node has the correct permissions + if (Object.keys(nodePerms.gestalt).includes('notify')) { + // If the number stored in notificationsDb >= 10000 + let numMessages = await tran.get(messageCountPath); + if (numMessages === undefined) { + numMessages = 0; + await tran.put(messageCountPath, 0); + } + if (numMessages >= this.messageCap) { + // Remove the oldest notification from notificationsMessagesDb + const oldestId = await this.getOldestNotificationId(tran); + await this.removeNotification(oldestId!, tran); + } + // Store the new notification in notificationsMessagesDb + const notificationId = this.notificationIdGenerator(); + await tran.put( + [...this.notificationsMessagesDbPath, idUtils.toBuffer(notificationId)], + notification, + ); + // Number of messages += 1 + const newNumMessages = numMessages + 1; + await tran.put(messageCountPath, newNumMessages); + } } /** @@ -240,39 +258,41 @@ class NotificationsManager { unread = false, number = 'all', order = 'newest', + tran, }: { unread?: boolean; number?: number | 'all'; order?: 'newest' | 'oldest'; + tran?: DBTransaction; } = {}): Promise> { - return await resources.withF( - [this.db.transaction(), this.lock.lock()], - async ([tran]) => { - let notificationIds: Array; - if (unread) { - notificationIds = await this.getNotificationIds('unread', tran); - } else { - notificationIds = await this.getNotificationIds('all', tran); - } + if (tran == null) { + return this.withTransactionF(async (tran) => + this.readNotifications({ unread, number, order, tran }), + ); + } + let notificationIds: Array; + if (unread) { + notificationIds = await this.getNotificationIds('unread', tran); + } else { + notificationIds = await this.getNotificationIds('all', tran); + } - if (order === 'newest') { - notificationIds.reverse(); - } + if (order === 'newest') { + notificationIds.reverse(); + } - if (number === 'all' || number > notificationIds.length) { - number = notificationIds.length; - } - notificationIds = notificationIds.slice(0, number); + if (number === 'all' || number > notificationIds.length) { + number = notificationIds.length; + } + notificationIds = notificationIds.slice(0, number); - const notifications: Array = []; - for (const id of notificationIds) { - const notification = await this.readNotificationById(id, tran); - notifications.push(notification!); - } + const notifications: Array = []; + for (const id of notificationIds) { + const notification = await this.readNotificationById(id, tran); + notifications.push(notification!); + } - return notifications; - }, - ); + return notifications; } /** @@ -282,43 +302,42 @@ class NotificationsManager { @ready(new notificationsErrors.ErrorNotificationsNotRunning()) public async findGestaltInvite( fromNode: NodeId, + tran?: DBTransaction, ): Promise { - return await resources.withF( - [this.db.transaction(), this.lock.lock()], - async ([tran]) => { - const notifications = await this.getNotifications('all', tran); - for (const notification of notifications) { - if ( - notification.data.type === 'GestaltInvite' && - nodesUtils.decodeNodeId(notification.senderId)!.equals(fromNode) - ) { - return notification; - } - } - }, - ); + if (tran == null) { + return this.withTransactionF(async (tran) => + this.findGestaltInvite(fromNode, tran), + ); + } + const notifications = await this.getNotifications('all', tran); + for (const notification of notifications) { + if ( + notification.data.type === 'GestaltInvite' && + nodesUtils.decodeNodeId(notification.senderId)!.equals(fromNode) + ) { + return notification; + } + } } /** * Removes all notifications */ @ready(new notificationsErrors.ErrorNotificationsNotRunning()) - public async clearNotifications(): Promise { - await resources.withF( - [this.db.transaction(), this.lock.lock()], - async ([tran]) => { - const notificationIds = await this.getNotificationIds('all', tran); - const numMessages = await tran.get([ - ...this.notificationsDbPath, - MESSAGE_COUNT_KEY, - ]); - if (numMessages !== undefined) { - for (const id of notificationIds) { - await this.removeNotification(id, tran); - } - } - }, - ); + public async clearNotifications(tran?: DBTransaction): Promise { + const messageCountPath = [...this.notificationsDbPath, MESSAGE_COUNT_KEY]; + if (tran == null) { + return this.withTransactionF(messageCountPath, async (tran) => + this.clearNotifications(tran), + ); + } + const notificationIds = await this.getNotificationIds('all', tran); + const numMessages = await tran.get(messageCountPath); + if (numMessages !== undefined) { + for (const id of notificationIds) { + await this.removeNotification(id, tran); + } + } } protected async readNotificationById( @@ -365,7 +384,6 @@ class NotificationsManager { tran: DBTransaction, ): Promise> { const notifications: Array = []; - // This.notificationsMessagesDb.createValueStream() for await (const [, value] of tran.iterator( {}, this.notificationsMessagesDbPath, From 73e389157c4dc3a4f8eef25ffb94a462ef419571 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 17 May 2022 13:42:02 +1000 Subject: [PATCH 030/137] fix: discovery test fixes --- src/discovery/Discovery.ts | 12 ++++-------- tests/discovery/Discovery.test.ts | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/discovery/Discovery.ts b/src/discovery/Discovery.ts index 42d0fe154..53026b098 100644 --- a/src/discovery/Discovery.ts +++ b/src/discovery/Discovery.ts @@ -13,8 +13,8 @@ import type { IdentityClaimId, IdentityClaims, } from '../identities/types'; -import type { Sigchain } from '../sigchain'; -import type { KeyManager } from '../keys'; +import type Sigchain from '../sigchain/Sigchain'; +import type KeyManager from '../keys/KeyManager'; import type { ClaimIdEncoded, Claim, ClaimLinkIdentity } from '../claims/types'; import type { ChainData } from '../sigchain/types'; import Logger from '@matrixai/logger'; @@ -83,11 +83,7 @@ class Discovery { protected gestaltGraph: GestaltGraph; protected identitiesManager: IdentitiesManager; protected nodeManager: NodeManager; - protected discoveryDbDomain: string = this.constructor.name; - protected discoveryQueueDbDomain: Array = [ - this.discoveryDbDomain, - 'queue', - ]; + protected discoveryDbPath: LevelPath = [this.constructor.name]; protected discoveryQueueDbPath: LevelPath = [this.constructor.name, 'queue']; protected discoveryQueueIdGenerator: DiscoveryQueueIdGenerator; @@ -457,7 +453,7 @@ class Discovery { } const discoveryQueueId = this.discoveryQueueIdGenerator(); await tran.put( - [...this.discoveryQueueDbDomain, idUtils.toBuffer(discoveryQueueId)], + [...this.discoveryQueueDbPath, idUtils.toBuffer(discoveryQueueId)], gestaltKey, ); }, diff --git a/tests/discovery/Discovery.test.ts b/tests/discovery/Discovery.test.ts index abfcab85d..c11c8d000 100644 --- a/tests/discovery/Discovery.test.ts +++ b/tests/discovery/Discovery.test.ts @@ -6,14 +6,16 @@ import path from 'path'; import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; -import { PolykeyAgent } from '@'; -import { Discovery } from '@/discovery'; -import { GestaltGraph } from '@/gestalts'; -import { IdentitiesManager } from '@/identities'; -import { NodeConnectionManager, NodeGraph, NodeManager } from '@/nodes'; -import { KeyManager } from '@/keys'; -import { ACL } from '@/acl'; -import { Sigchain } from '@/sigchain'; +import PolykeyAgent from '@/PolykeyAgent'; +import Discovery from '@/discovery/Discovery'; +import GestaltGraph from '@/gestalts/GestaltGraph'; +import IdentitiesManager from '@/identities/IdentitiesManager'; +import NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import NodeGraph from '@/nodes/NodeGraph'; +import NodeManager from '@/nodes/NodeManager'; +import KeyManager from '@/keys/KeyManager'; +import ACL from '@/acl/ACL'; +import Sigchain from '@/sigchain/Sigchain'; import Proxy from '@/network/Proxy'; import * as nodesUtils from '@/nodes/utils'; import * as claimsUtils from '@/claims/utils'; From 845d7e4ba4f64287a92485fca3e88e992e16700f Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 17 May 2022 13:50:21 +1000 Subject: [PATCH 031/137] fix: fix for `NodeConnection.test.ts` not running --- tests/nodes/NodeConnection.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index 52d1ce674..fcc37d701 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -267,6 +267,7 @@ describe(`${NodeConnection.name} test`, () => { }); await serverGestaltGraph.setNode(node); const agentService = createAgentService({ + db: serverDb, keyManager: serverKeyManager, vaultManager: serverVaultManager, nodeConnectionManager: dummyNodeConnectionManager, From 69e7d3af908731c6ab09f0a9024d71c7ff928fbf Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 17 May 2022 14:37:21 +1000 Subject: [PATCH 032/137] refactor: replacing `Mutex` with `Lock` for Proxy --- src/network/Proxy.ts | 285 ++++++++++++++++++------------------ tests/network/Proxy.test.ts | 14 +- 2 files changed, 150 insertions(+), 149 deletions(-) diff --git a/src/network/Proxy.ts b/src/network/Proxy.ts index 15bbf4d05..1a6ff46f1 100644 --- a/src/network/Proxy.ts +++ b/src/network/Proxy.ts @@ -7,8 +7,9 @@ import type UTPConnection from 'utp-native/lib/connection'; import type { ConnectionsReverse } from './ConnectionReverse'; import http from 'http'; import UTP from 'utp-native'; -import { Mutex } from 'async-mutex'; import Logger from '@matrixai/logger'; +import { Lock } from '@matrixai/async-locks'; +import { withF } from '@matrixai/resources'; import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; import ConnectionReverse from './ConnectionReverse'; import ConnectionForward from './ConnectionForward'; @@ -37,12 +38,12 @@ class Proxy { protected server: http.Server; protected utpSocket: UTP; protected tlsConfig: TLSConfig; - protected connectionLocksForward: Map = new Map(); + protected connectionLocksForward: Map = new Map(); protected connectionsForward: ConnectionsForward = { proxy: new Map(), client: new Map(), }; - protected connectionLocksReverse: Map = new Map(); + protected connectionLocksReverse: Map = new Map(); protected connectionsReverse: ConnectionsReverse = { proxy: new Map(), reverse: new Map(), @@ -316,24 +317,24 @@ class Proxy { const proxyAddress = networkUtils.buildAddress(proxyHost, proxyPort); let lock = this.connectionLocksForward.get(proxyAddress); if (lock == null) { - lock = new Mutex(); + lock = new Lock(); this.connectionLocksForward.set(proxyAddress, lock); } - const release = await lock.acquire(); - try { - await this.establishConnectionForward( - nodeId, - proxyHost, - proxyPort, - timer_, - ); - } finally { - if (timer === undefined) { - timerStop(timer_!); + await withF([lock.lock()], async () => { + try { + await this.establishConnectionForward( + nodeId, + proxyHost, + proxyPort, + timer_, + ); + } finally { + if (timer === undefined) { + timerStop(timer_!); + } + this.connectionLocksForward.delete(proxyAddress); } - release(); - this.connectionLocksForward.delete(proxyAddress); - } + }); } @ready(new networkErrors.ErrorProxyNotRunning(), true) @@ -344,20 +345,20 @@ class Proxy { const proxyAddress = networkUtils.buildAddress(proxyHost, proxyPort); let lock = this.connectionLocksForward.get(proxyAddress); if (lock == null) { - lock = new Mutex(); + lock = new Lock(); this.connectionLocksForward.set(proxyAddress, lock); } - const release = await lock.acquire(); - try { - const conn = this.connectionsForward.proxy.get(proxyAddress); - if (conn == null) { - return; + await withF([lock.lock()], async () => { + try { + const conn = this.connectionsForward.proxy.get(proxyAddress); + if (conn == null) { + return; + } + await conn.stop(); + } finally { + this.connectionLocksForward.delete(proxyAddress); } - await conn.stop(); - } finally { - release(); - this.connectionLocksForward.delete(proxyAddress); - } + }); } /** @@ -419,61 +420,71 @@ class Proxy { } let lock = this.connectionLocksForward.get(proxyAddress as Address); if (lock == null) { - lock = new Mutex(); + lock = new Lock(); this.connectionLocksForward.set(proxyAddress as Address, lock); } - const release = await lock.acquire(); - try { - const timer = timerStart(this.connConnectTime); + await withF([lock.lock()], async () => { try { - await this.connectForward( - nodeId, - proxyHost, - proxyPort, - clientSocket, - timer, - ); - } catch (e) { - if (e instanceof networkErrors.ErrorProxyConnectInvalidUrl) { - if (!clientSocket.destroyed) { - await clientSocketEnd('HTTP/1.1 400 Bad Request\r\n' + '\r\n'); - clientSocket.destroy(e); + const timer = timerStart(this.connConnectTime); + try { + await this.connectForward( + nodeId, + proxyHost, + proxyPort, + clientSocket, + timer, + ); + } catch (e) { + if (e instanceof networkErrors.ErrorProxyConnectInvalidUrl) { + if (!clientSocket.destroyed) { + await clientSocketEnd('HTTP/1.1 400 Bad Request\r\n' + '\r\n'); + clientSocket.destroy(e); + } + return; } - return; - } - if (e instanceof networkErrors.ErrorConnectionStartTimeout) { - if (!clientSocket.destroyed) { - await clientSocketEnd('HTTP/1.1 504 Gateway Timeout\r\n' + '\r\n'); - clientSocket.destroy(e); + if (e instanceof networkErrors.ErrorConnectionStartTimeout) { + if (!clientSocket.destroyed) { + await clientSocketEnd( + 'HTTP/1.1 504 Gateway Timeout\r\n' + '\r\n', + ); + clientSocket.destroy(e); + } + return; } - return; - } - if (e instanceof networkErrors.ErrorConnectionStart) { - if (!clientSocket.destroyed) { - await clientSocketEnd('HTTP/1.1 502 Bad Gateway\r\n' + '\r\n'); - clientSocket.destroy(e); + if (e instanceof networkErrors.ErrorConnectionStart) { + if (!clientSocket.destroyed) { + await clientSocketEnd('HTTP/1.1 502 Bad Gateway\r\n' + '\r\n'); + clientSocket.destroy(e); + } + return; } - return; - } - if (e instanceof networkErrors.ErrorCertChain) { - if (!clientSocket.destroyed) { - await clientSocketEnd( - 'HTTP/1.1 526 Invalid SSL Certificate\r\n' + '\r\n', - ); - clientSocket.destroy(e); + if (e instanceof networkErrors.ErrorCertChain) { + if (!clientSocket.destroyed) { + await clientSocketEnd( + 'HTTP/1.1 526 Invalid SSL Certificate\r\n' + '\r\n', + ); + clientSocket.destroy(e); + } + return; } - return; - } - if (e instanceof networkErrors.ErrorConnectionTimeout) { - if (!clientSocket.destroyed) { - await clientSocketEnd( - 'HTTP/1.1 524 A Timeout Occurred\r\n' + '\r\n', - ); - clientSocket.destroy(e); + if (e instanceof networkErrors.ErrorConnectionTimeout) { + if (!clientSocket.destroyed) { + await clientSocketEnd( + 'HTTP/1.1 524 A Timeout Occurred\r\n' + '\r\n', + ); + clientSocket.destroy(e); + } + return; + } + if (e instanceof networkErrors.ErrorConnection) { + if (!clientSocket.destroyed) { + await clientSocketEnd( + 'HTTP/1.1 500 Internal Server Error\r\n' + '\r\n', + ); + clientSocket.destroy(e); + } + return; } - return; - } - if (e instanceof networkErrors.ErrorConnection) { if (!clientSocket.destroyed) { await clientSocketEnd( 'HTTP/1.1 500 Internal Server Error\r\n' + '\r\n', @@ -481,27 +492,19 @@ class Proxy { clientSocket.destroy(e); } return; + } finally { + timerStop(timer); } - if (!clientSocket.destroyed) { - await clientSocketEnd( - 'HTTP/1.1 500 Internal Server Error\r\n' + '\r\n', - ); - clientSocket.destroy(e); - } - return; + // After composing, switch off this error handler + clientSocket.off('error', handleConnectError); + await clientSocketWrite( + 'HTTP/1.1 200 Connection Established\r\n' + '\r\n', + ); + this.logger.info(`Handled CONNECT to ${proxyAddress}`); } finally { - timerStop(timer); + this.connectionLocksForward.delete(proxyAddress as Address); } - // After composing, switch off this error handler - clientSocket.off('error', handleConnectError); - await clientSocketWrite( - 'HTTP/1.1 200 Connection Established\r\n' + '\r\n', - ); - this.logger.info(`Handled CONNECT to ${proxyAddress}`); - } finally { - release(); - this.connectionLocksForward.delete(proxyAddress as Address); - } + }); }; protected async connectForward( @@ -590,19 +593,19 @@ class Proxy { const proxyAddress = networkUtils.buildAddress(proxyHost, proxyPort); let lock = this.connectionLocksReverse.get(proxyAddress); if (lock == null) { - lock = new Mutex(); + lock = new Lock(); this.connectionLocksReverse.set(proxyAddress, lock); } - const release = await lock.acquire(); - try { - await this.establishConnectionReverse(proxyHost, proxyPort, timer_); - } finally { - if (timer === undefined) { - timerStop(timer_!); + await withF([lock.lock()], async () => { + try { + await this.establishConnectionReverse(proxyHost, proxyPort, timer_); + } finally { + if (timer === undefined) { + timerStop(timer_!); + } + this.connectionLocksReverse.delete(proxyAddress); } - release(); - this.connectionLocksReverse.delete(proxyAddress); - } + }); } @ready(new networkErrors.ErrorProxyNotRunning(), true) @@ -613,20 +616,20 @@ class Proxy { const proxyAddress = networkUtils.buildAddress(proxyHost, proxyPort); let lock = this.connectionLocksReverse.get(proxyAddress); if (lock == null) { - lock = new Mutex(); + lock = new Lock(); this.connectionLocksReverse.set(proxyAddress, lock); } - const release = await lock.acquire(); - try { - const conn = this.connectionsReverse.proxy.get(proxyAddress); - if (conn == null) { - return; + await withF([lock.lock()], async () => { + try { + const conn = this.connectionsReverse.proxy.get(proxyAddress); + if (conn == null) { + return; + } + await conn.stop(); + } finally { + this.connectionLocksReverse.delete(proxyAddress); } - await conn.stop(); - } finally { - release(); - this.connectionLocksReverse.delete(proxyAddress); - } + }); } protected handleConnectionReverse = async ( @@ -638,38 +641,38 @@ class Proxy { ); let lock = this.connectionLocksReverse.get(proxyAddress); if (lock == null) { - lock = new Mutex(); + lock = new Lock(); this.connectionLocksReverse.set(proxyAddress, lock); } - const release = await lock.acquire(); - try { - this.logger.info(`Handling connection from ${proxyAddress}`); - const timer = timerStart(this.connConnectTime); + await withF([lock.lock()], async () => { try { - await this.connectReverse( - utpConn.remoteAddress, - utpConn.remotePort, - utpConn, - timer, - ); - } catch (e) { - if (!(e instanceof networkErrors.ErrorNetwork)) { - throw e; - } - if (!utpConn.destroyed) { - utpConn.destroy(); + this.logger.info(`Handling connection from ${proxyAddress}`); + const timer = timerStart(this.connConnectTime); + try { + await this.connectReverse( + utpConn.remoteAddress, + utpConn.remotePort, + utpConn, + timer, + ); + } catch (e) { + if (!(e instanceof networkErrors.ErrorNetwork)) { + throw e; + } + if (!utpConn.destroyed) { + utpConn.destroy(); + } + this.logger.warn( + `Failed connection from ${proxyAddress} - ${e.toString()}`, + ); + } finally { + timerStop(timer); } - this.logger.warn( - `Failed connection from ${proxyAddress} - ${e.toString()}`, - ); + this.logger.info(`Handled connection from ${proxyAddress}`); } finally { - timerStop(timer); + this.connectionLocksReverse.delete(proxyAddress); } - this.logger.info(`Handled connection from ${proxyAddress}`); - } finally { - release(); - this.connectionLocksReverse.delete(proxyAddress); - } + }); }; protected async connectReverse( diff --git a/tests/network/Proxy.test.ts b/tests/network/Proxy.test.ts index 4393c69b9..afd93c3b4 100644 --- a/tests/network/Proxy.test.ts +++ b/tests/network/Proxy.test.ts @@ -6,14 +6,12 @@ import net from 'net'; import tls from 'tls'; import UTP from 'utp-native'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import { - Proxy, - utils as networkUtils, - errors as networkErrors, -} from '@/network'; -import * as keysUtils from '@/keys/utils'; import { promisify, promise, timerStart, timerStop, poll } from '@/utils'; -import { utils as nodesUtils } from '@/nodes'; +import Proxy from '@/network/Proxy'; +import * as networkUtils from '@/network/utils'; +import * as networkErrors from '@/network/errors'; +import * as keysUtils from '@/keys/utils'; +import * as nodesUtils from '@/nodes/utils'; import * as testUtils from '../utils'; /** @@ -110,7 +108,7 @@ function tcpServer(end: boolean = false) { describe(Proxy.name, () => { const localHost = '127.0.0.1' as Host; const port = 0 as Port; - const logger = new Logger(`${Proxy.name} test`, LogLevel.WARN, [ + const logger = new Logger(`${Proxy.name} test`, LogLevel.DEBUG, [ new StreamHandler(), ]); const nodeIdABC = testUtils.generateRandomNodeId(); From 1aa90449c0a6e85b23c3eb175f8a24cb242f7a43 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 17 May 2022 15:46:13 +1000 Subject: [PATCH 033/137] fix: fixing vaultManager tests There are still some tests failing due to cloning and pulling. Seems like a problem with the HTTP API for cloning. --- tests/vaults/VaultManager.test.ts | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index 61796e807..9c7bc4021 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -30,6 +30,7 @@ import * as keysUtils from '@/keys/utils'; import { sleep } from '@/utils'; import VaultInternal from '@/vaults/VaultInternal'; import * as testsUtils from '../utils'; +import { expectRemoteError } from '../utils'; const mockedGenerateDeterministicKeyPair = jest .spyOn(keysUtils, 'generateDeterministicKeyPair') @@ -736,12 +737,13 @@ describe('VaultManager', () => { 'pull', ); - await expect(() => + await expectRemoteError( vaultManager.cloneVault( remoteKeynode1Id, 'not-existing' as VaultName, ), - ).rejects.toThrow(vaultsErrors.ErrorVaultsVaultUndefined); + vaultsErrors.ErrorVaultsVaultUndefined, + ); } finally { await vaultManager?.stop(); await vaultManager?.destroy(); @@ -824,9 +826,10 @@ describe('VaultManager', () => { }); try { // Should reject with no permissions set - await expect(() => + await expectRemoteError( vaultManager.cloneVault(remoteKeynode1Id, remoteVaultId), - ).rejects.toThrow(vaultsErrors.ErrorVaultsPermissionDenied); + vaultsErrors.ErrorVaultsPermissionDenied, + ); // No new vault created expect((await vaultManager.listVaults()).size).toBe(0); } finally { @@ -1519,18 +1522,21 @@ describe('VaultManager', () => { // Scanning vaults // Should throw due to no permission - await expect(async () => { + const testFun = async () => { for await (const _ of vaultManager.scanVaults(targetNodeId)) { // Should throw } - }).rejects.toThrow(vaultsErrors.ErrorVaultsPermissionDenied); + }; + await expectRemoteError( + testFun(), + vaultsErrors.ErrorVaultsPermissionDenied, + ); // Should throw due to lack of scan permission await remoteAgent.gestaltGraph.setGestaltActionByNode(nodeId1, 'notify'); - await expect(async () => { - for await (const _ of vaultManager.scanVaults(targetNodeId)) { - // Should throw - } - }).rejects.toThrow(vaultsErrors.ErrorVaultsPermissionDenied); + await expectRemoteError( + testFun(), + vaultsErrors.ErrorVaultsPermissionDenied, + ); // Setting permissions await remoteAgent.gestaltGraph.setGestaltActionByNode(nodeId1, 'scan'); From aaf158c259239eab77bfe4d8065d34d834e72344 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 17 May 2022 17:29:23 +1000 Subject: [PATCH 034/137] test: fixing client tests --- tests/client/rpcVaults.test.ts | 7 +- tests/client/service/agentLockAll.test.ts | 1 + .../gestaltsGestaltTrustByIdentity.test.ts | 67 ++---- .../service/identitiesAuthenticate.test.ts | 6 +- tests/client/service/identitiesClaim.test.ts | 16 +- .../identitiesInfoConnectedGet.test.ts | 6 +- tests/client/service/keysKeyPairRenew.test.ts | 4 +- tests/client/service/keysKeyPairReset.test.ts | 4 +- tests/client/service/nodesAdd.test.ts | 16 +- tests/client/service/nodesClaim.test.ts | 6 +- tests/client/service/nodesFind.test.ts | 6 +- tests/client/service/nodesPing.test.ts | 6 +- tests/utils.ts | 215 +++++++++--------- 13 files changed, 175 insertions(+), 185 deletions(-) diff --git a/tests/client/rpcVaults.test.ts b/tests/client/rpcVaults.test.ts index 96f3db089..8645e989f 100644 --- a/tests/client/rpcVaults.test.ts +++ b/tests/client/rpcVaults.test.ts @@ -19,6 +19,7 @@ import * as vaultsUtils from '@/vaults/utils'; import * as vaultOps from '@/vaults/VaultOps'; import * as nodesUtils from '@/nodes/utils'; import * as clientUtils from './utils'; +import { expectRemoteError } from '../utils'; jest.mock('@/keys/utils', () => ({ ...jest.requireActual('@/keys/utils'), @@ -247,7 +248,8 @@ describe('Vaults client service', () => { vaultVersionMessage.setVault(vaultMessage); vaultVersionMessage.setVersionId('invalidOid'); const version = vaultsVersion(vaultVersionMessage, callCredentials); - await expect(version).rejects.toThrow( + await expectRemoteError( + version, vaultErrors.ErrorVaultReferenceInvalid, ); @@ -255,7 +257,8 @@ describe('Vaults client service', () => { '7660aa9a2fee90e875c2d19e5deefe882ca1d4d9', ); const version2 = vaultsVersion(vaultVersionMessage, callCredentials); - await expect(version2).rejects.toThrow( + await expectRemoteError( + version2, vaultErrors.ErrorVaultReferenceMissing, ); }); diff --git a/tests/client/service/agentLockAll.test.ts b/tests/client/service/agentLockAll.test.ts index 4ae0d6665..9fd74aab4 100644 --- a/tests/client/service/agentLockAll.test.ts +++ b/tests/client/service/agentLockAll.test.ts @@ -76,6 +76,7 @@ describe('agentLockall', () => { authenticate, sessionManager, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts index 74ecff0e3..ba706add1 100644 --- a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts +++ b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts @@ -1,7 +1,6 @@ import type { NodeIdEncoded } from '@/nodes/types'; import type { ClaimLinkIdentity } from '@/claims/types'; import type { ChainData } from '@/sigchain/types'; -import type { Gestalt } from '@/gestalts/types'; import type { IdentityId } from '@/identities/types'; import type { Host, Port } from '@/network/types'; import fs from 'fs'; @@ -25,7 +24,6 @@ import GRPCServer from '@/grpc/GRPCServer'; import GRPCClientClient from '@/client/GRPCClientClient'; import gestaltsGestaltTrustByIdentity from '@/client/service/gestaltsGestaltTrustByIdentity'; import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; -import { poll } from '@/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as identitiesPB from '@/proto/js/polykey/v1/identities/identities_pb'; import * as claimsUtils from '@/claims/utils'; @@ -35,6 +33,7 @@ import * as clientUtils from '@/client/utils/utils'; import * as nodesUtils from '@/nodes/utils'; import * as testUtils from '../../utils'; import TestProvider from '../../identities/TestProvider'; +import { expectRemoteError } from '../../utils'; describe('gestaltsGestaltTrustByIdentity', () => { const logger = new Logger( @@ -300,34 +299,15 @@ describe('gestaltsGestaltTrustByIdentity', () => { request.setIdentityId(connectedIdentity); // Should fail on first attempt - need to allow time for the identity to be // linked to a node via discovery - await expect( + await expectRemoteError( grpcClient.gestaltsGestaltTrustByIdentity( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing); - // Wait for both identity and node to be set in GG - await poll( - async () => { - const gestalts = await poll>( - async () => { - return await gestaltGraph.getGestalts(); - }, - (_, result) => { - if (result.length === 1) return true; - return false; - }, - 100, - ); - return gestalts[0]; - }, - (_, result) => { - if (result === undefined) return false; - if (Object.keys(result.matrix).length === 2) return true; - return false; - }, - 100, + gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, ); + // Wait for both identity and node to be set in GG + await discovery.waitForDrained(); const response = await grpcClient.gestaltsGestaltTrustByIdentity( request, clientUtils.encodeAuthFromPassword(password), @@ -351,20 +331,22 @@ describe('gestaltsGestaltTrustByIdentity', () => { request.setProviderId(testProvider.id); request.setIdentityId('disconnected-user'); // Should fail on first attempt - attempt to find a connected node - await expect( + await expectRemoteError( grpcClient.gestaltsGestaltTrustByIdentity( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing); + gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, + ); // Wait and try again - should fail again because the identity has no // linked nodes we can trust - await expect( + await expectRemoteError( grpcClient.gestaltsGestaltTrustByIdentity( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing); + gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, + ); }); test('trust extends to entire gestalt', async () => { await gestaltGraph.linkNodeAndIdentity( @@ -415,35 +397,16 @@ describe('gestaltsGestaltTrustByIdentity', () => { request.setIdentityId(connectedIdentity); // Should fail on first attempt - need to allow time for the identity to be // linked to a node via discovery - await expect( + await expectRemoteError( grpcClient.gestaltsGestaltTrustByIdentity( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing); + gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, + ); // Wait and try again - should succeed second time // Wait for both identity and node to be set in GG - await poll( - async () => { - const gestalts = await poll>( - async () => { - return await gestaltGraph.getGestalts(); - }, - (_, result) => { - if (result.length === 1) return true; - return false; - }, - 100, - ); - return gestalts[0]; - }, - (_, result) => { - if (result === undefined) return false; - if (Object.keys(result.matrix).length === 2) return true; - return false; - }, - 100, - ); + await discovery.waitForDrained(); const response = await grpcClient.gestaltsGestaltTrustByIdentity( request, clientUtils.encodeAuthFromPassword(password), diff --git a/tests/client/service/identitiesAuthenticate.test.ts b/tests/client/service/identitiesAuthenticate.test.ts index 73bce737e..21b4f78dc 100644 --- a/tests/client/service/identitiesAuthenticate.test.ts +++ b/tests/client/service/identitiesAuthenticate.test.ts @@ -16,6 +16,7 @@ import * as validationErrors from '@/validation/errors'; import * as clientUtils from '@/client/utils/utils'; import * as nodesUtils from '@/nodes/utils'; import TestProvider from '../../identities/TestProvider'; +import { expectRemoteError } from '../../utils'; describe('identitiesAuthenticate', () => { const logger = new Logger('identitiesAuthenticate test', LogLevel.WARN, [ @@ -125,13 +126,14 @@ describe('identitiesAuthenticate', () => { test('cannot authenticate invalid provider', async () => { const request = new identitiesPB.Provider(); request.setProviderId(''); - await expect( + await expectRemoteError( grpcClient .identitiesAuthenticate( request, clientUtils.encodeAuthFromPassword(password), ) .next(), - ).rejects.toThrow(validationErrors.ErrorValidation); + validationErrors.ErrorValidation, + ); }); }); diff --git a/tests/client/service/identitiesClaim.test.ts b/tests/client/service/identitiesClaim.test.ts index 6259afaea..70185582a 100644 --- a/tests/client/service/identitiesClaim.test.ts +++ b/tests/client/service/identitiesClaim.test.ts @@ -27,6 +27,7 @@ import * as nodesUtils from '@/nodes/utils'; import * as validationErrors from '@/validation/errors'; import * as testUtils from '../../utils'; import TestProvider from '../../identities/TestProvider'; +import { expectRemoteError } from '../../utils'; describe('identitiesClaim', () => { const logger = new Logger('identitiesClaim test', LogLevel.WARN, [ @@ -208,27 +209,30 @@ describe('identitiesClaim', () => { const request = new identitiesPB.Provider(); request.setIdentityId(''); request.setProviderId(testToken.providerId); - await expect( + await expectRemoteError( grpcClient.identitiesClaim( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(validationErrors.ErrorValidation); + validationErrors.ErrorValidation, + ); request.setIdentityId(testToken.identityId); request.setProviderId(''); - await expect( + await expectRemoteError( grpcClient.identitiesClaim( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(validationErrors.ErrorValidation); + validationErrors.ErrorValidation, + ); request.setIdentityId(''); request.setProviderId(''); - await expect( + await expectRemoteError( grpcClient.identitiesClaim( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(validationErrors.ErrorValidation); + validationErrors.ErrorValidation, + ); }); }); diff --git a/tests/client/service/identitiesInfoConnectedGet.test.ts b/tests/client/service/identitiesInfoConnectedGet.test.ts index 300567584..532690fe4 100644 --- a/tests/client/service/identitiesInfoConnectedGet.test.ts +++ b/tests/client/service/identitiesInfoConnectedGet.test.ts @@ -16,6 +16,7 @@ import * as clientUtils from '@/client/utils/utils'; import * as nodesUtils from '@/nodes/utils'; import * as identitiesErrors from '@/identities/errors'; import TestProvider from '../../identities/TestProvider'; +import { expectRemoteError } from '../../utils'; describe('identitiesInfoConnectedGet', () => { const logger = new Logger('identitiesInfoConnectedGet test', LogLevel.WARN, [ @@ -729,13 +730,14 @@ describe('identitiesInfoConnectedGet', () => { // This feature is not implemented yet - should throw error const request = new identitiesPB.ProviderSearch(); request.setDisconnected(true); - await expect( + await expectRemoteError( grpcClient .identitiesInfoConnectedGet( request, clientUtils.encodeAuthFromPassword(password), ) .next(), - ).rejects.toThrow(identitiesErrors.ErrorProviderUnimplemented); + identitiesErrors.ErrorProviderUnimplemented, + ); }); }); diff --git a/tests/client/service/keysKeyPairRenew.test.ts b/tests/client/service/keysKeyPairRenew.test.ts index 550f793dd..8a792254b 100644 --- a/tests/client/service/keysKeyPairRenew.test.ts +++ b/tests/client/service/keysKeyPairRenew.test.ts @@ -111,7 +111,7 @@ describe('keysKeyPairRenew', () => { certChainPem: await keyManager.getRootCertChainPem(), }; const nodeIdStatus1 = (await status.readStatus())!.data.nodeId; - expect(mockedRefreshBuckets.mock.calls).toHaveLength(0); + expect(mockedRefreshBuckets).toHaveBeenCalledTimes(0); expect(fwdTLSConfig1).toEqual(expectedTLSConfig1); expect(serverTLSConfig1).toEqual(expectedTLSConfig1); expect(nodeId1.equals(nodeIdStatus1)).toBe(true); @@ -134,7 +134,7 @@ describe('keysKeyPairRenew', () => { certChainPem: await keyManager.getRootCertChainPem(), }; const nodeIdStatus2 = (await status.readStatus())!.data.nodeId; - expect(mockedRefreshBuckets.mock.calls).toHaveLength(1); + expect(mockedRefreshBuckets).toHaveBeenCalled(); expect(fwdTLSConfig2).toEqual(expectedTLSConfig2); expect(serverTLSConfig2).toEqual(expectedTLSConfig2); expect(rootKeyPair2.privateKey).not.toBe(rootKeyPair1.privateKey); diff --git a/tests/client/service/keysKeyPairReset.test.ts b/tests/client/service/keysKeyPairReset.test.ts index 754d80075..8c41064b1 100644 --- a/tests/client/service/keysKeyPairReset.test.ts +++ b/tests/client/service/keysKeyPairReset.test.ts @@ -111,7 +111,7 @@ describe('keysKeyPairReset', () => { certChainPem: await keyManager.getRootCertChainPem(), }; const nodeIdStatus1 = (await status.readStatus())!.data.nodeId; - expect(mockedRefreshBuckets.mock.calls).toHaveLength(0); + expect(mockedRefreshBuckets).not.toHaveBeenCalled(); expect(fwdTLSConfig1).toEqual(expectedTLSConfig1); expect(serverTLSConfig1).toEqual(expectedTLSConfig1); expect(nodeId1.equals(nodeIdStatus1)).toBe(true); @@ -134,7 +134,7 @@ describe('keysKeyPairReset', () => { certChainPem: await keyManager.getRootCertChainPem(), }; const nodeIdStatus2 = (await status.readStatus())!.data.nodeId; - expect(mockedRefreshBuckets.mock.calls).toHaveLength(1); + expect(mockedRefreshBuckets).toHaveBeenCalled(); expect(fwdTLSConfig2).toEqual(expectedTLSConfig2); expect(serverTLSConfig2).toEqual(expectedTLSConfig2); expect(rootKeyPair2.privateKey).not.toBe(rootKeyPair1.privateKey); diff --git a/tests/client/service/nodesAdd.test.ts b/tests/client/service/nodesAdd.test.ts index 168e64a34..aaff85bc3 100644 --- a/tests/client/service/nodesAdd.test.ts +++ b/tests/client/service/nodesAdd.test.ts @@ -23,6 +23,7 @@ import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; import * as testUtils from '../../utils'; +import { expectRemoteError } from '../../utils'; describe('nodesAdd', () => { const logger = new Logger('nodesAdd test', LogLevel.WARN, [ @@ -175,29 +176,32 @@ describe('nodesAdd', () => { const request = new nodesPB.NodeAddress(); request.setNodeId('vrsc24a1er424epq77dtoveo93meij0pc8ig4uvs9jbeld78n9nl0'); request.setAddress(addressMessage); - await expect( + await expectRemoteError( grpcClient.nodesAdd( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(validationErrors.ErrorValidation); + validationErrors.ErrorValidation, + ); // Invalid port addressMessage.setHost('127.0.0.1'); addressMessage.setPort(111111); - await expect( + await expectRemoteError( grpcClient.nodesAdd( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(validationErrors.ErrorValidation); + validationErrors.ErrorValidation, + ); // Invalid nodeid addressMessage.setPort(11111); request.setNodeId('nodeId'); - await expect( + await expectRemoteError( grpcClient.nodesAdd( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(validationErrors.ErrorValidation); + validationErrors.ErrorValidation, + ); }); }); diff --git a/tests/client/service/nodesClaim.test.ts b/tests/client/service/nodesClaim.test.ts index 2686ce3ed..bcecd0741 100644 --- a/tests/client/service/nodesClaim.test.ts +++ b/tests/client/service/nodesClaim.test.ts @@ -26,6 +26,7 @@ import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; import * as testUtils from '../../utils'; +import { expectRemoteError } from '../../utils'; describe('nodesClaim', () => { const logger = new Logger('nodesClaim test', LogLevel.WARN, [ @@ -229,11 +230,12 @@ describe('nodesClaim', () => { test('cannot claim an invalid node', async () => { const request = new nodesPB.Claim(); request.setNodeId('nodeId'); - await expect( + await expectRemoteError( grpcClient.nodesClaim( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(validationErrors.ErrorValidation); + validationErrors.ErrorValidation, + ); }); }); diff --git a/tests/client/service/nodesFind.test.ts b/tests/client/service/nodesFind.test.ts index 0297bccbd..b01e157a1 100644 --- a/tests/client/service/nodesFind.test.ts +++ b/tests/client/service/nodesFind.test.ts @@ -20,6 +20,7 @@ import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; import * as testUtils from '../../utils'; +import { expectRemoteError } from '../../utils'; describe('nodesFind', () => { const logger = new Logger('nodesFind test', LogLevel.WARN, [ @@ -159,11 +160,12 @@ describe('nodesFind', () => { test('cannot find an invalid node', async () => { const request = new nodesPB.Node(); request.setNodeId('nodeId'); - await expect( + await expectRemoteError( grpcClient.nodesFind( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(validationErrors.ErrorValidation); + validationErrors.ErrorValidation, + ); }); }); diff --git a/tests/client/service/nodesPing.test.ts b/tests/client/service/nodesPing.test.ts index 43dddcba1..d4954bb4a 100644 --- a/tests/client/service/nodesPing.test.ts +++ b/tests/client/service/nodesPing.test.ts @@ -22,6 +22,7 @@ import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; import * as testUtils from '../../utils'; +import { expectRemoteError } from '../../utils'; describe('nodesPing', () => { const logger = new Logger('nodesPing test', LogLevel.WARN, [ @@ -174,11 +175,12 @@ describe('nodesPing', () => { test('cannot ping an invalid node', async () => { const request = new nodesPB.Node(); request.setNodeId('nodeId'); - await expect( + await expectRemoteError( grpcClient.nodesPing( request, clientUtils.encodeAuthFromPassword(password), ), - ).rejects.toThrow(validationErrors.ErrorValidation); + validationErrors.ErrorValidation, + ); }); }); diff --git a/tests/utils.ts b/tests/utils.ts index f6f76c538..38bd48fcd 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,20 +1,20 @@ -// Import type { StatusLive } from '@/status/types'; +import type { StatusLive } from '@/status/types'; import type { NodeId } from '@/nodes/types'; -// Import type { Host } from '@/network/types'; +import type { Host } from '@/network/types'; import path from 'path'; import fs from 'fs'; import lock from 'fd-lock'; -// Import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; -// Import PolykeyAgent from '@/PolykeyAgent'; -// import Status from '@/status/Status'; -// import GRPCClientClient from '@/client/GRPCClientClient'; -// import * as clientUtils from '@/client/utils'; +import PolykeyAgent from '@/PolykeyAgent'; +import Status from '@/status/Status'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import * as clientUtils from '@/client/utils'; import * as keysUtils from '@/keys/utils'; -// Import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import { sleep } from '@/utils'; import * as errors from '@/errors'; -// Import config from '@/config'; +import config from '@/config'; /** * Setup the global keypair @@ -84,101 +84,101 @@ async function setupGlobalKeypair() { * * Ensure client-side side-effects are removed at the end of each test * * Ensure server-side side-effects are removed at the end of each test */ -// async function setupGlobalAgent( -// logger: Logger = new Logger(setupGlobalAgent.name, LogLevel.WARN, [ -// new StreamHandler(), -// ]), -// ) { -// const globalAgentPassword = 'password'; -// const globalAgentDir = path.join(globalThis.dataDir, 'agent'); -// // The references directory will act like our reference count -// await fs.promises.mkdir(path.join(globalAgentDir, 'references'), { -// recursive: true, -// }); -// const pid = process.pid.toString(); -// // Plus 1 to the reference count -// await fs.promises.writeFile(path.join(globalAgentDir, 'references', pid), ''); -// const globalAgentLock = await fs.promises.open( -// path.join(globalThis.dataDir, 'agent.lock'), -// fs.constants.O_WRONLY | fs.constants.O_CREAT, -// ); -// while (!lock(globalAgentLock.fd)) { -// await sleep(1000); -// } -// const status = new Status({ -// statusPath: path.join(globalAgentDir, config.defaults.statusBase), -// statusLockPath: path.join(globalAgentDir, config.defaults.statusLockBase), -// fs, -// }); -// let statusInfo = await status.readStatus(); -// if (statusInfo == null || statusInfo.status === 'DEAD') { -// await PolykeyAgent.createPolykeyAgent({ -// password: globalAgentPassword, -// nodePath: globalAgentDir, -// networkConfig: { -// proxyHost: '127.0.0.1' as Host, -// forwardHost: '127.0.0.1' as Host, -// agentHost: '127.0.0.1' as Host, -// clientHost: '127.0.0.1' as Host, -// }, -// keysConfig: { -// rootKeyPairBits: 2048, -// }, -// seedNodes: {}, // Explicitly no seed nodes on startup -// logger, -// }); -// statusInfo = await status.readStatus(); -// } -// return { -// globalAgentDir, -// globalAgentPassword, -// globalAgentStatus: statusInfo as StatusLive, -// globalAgentClose: async () => { -// // Closing the global agent cannot be done in the globalTeardown -// // This is due to a sequence of reasons: -// // 1. The global agent is not started as a separate process -// // 2. Because we need to be able to mock dependencies -// // 3. This means it is part of a jest worker process -// // 4. Which will block termination of the jest worker process -// // 5. Therefore globalTeardown will never get to execute -// // 6. The global agent is not part of globalSetup -// // 7. Because not all tests need the global agent -// // 8. Therefore setupGlobalAgent is lazy and executed by jest worker processes -// try { -// await fs.promises.rm(path.join(globalAgentDir, 'references', pid)); -// // If the references directory is not empty -// // there are other processes still using the global agent -// try { -// await fs.promises.rmdir(path.join(globalAgentDir, 'references')); -// } catch (e) { -// if (e.code === 'ENOTEMPTY') { -// return; -// } -// throw e; -// } -// // Stopping may occur in a different jest worker process -// // therefore we cannot rely on pkAgent, but instead use GRPC -// const statusInfo = (await status.readStatus()) as StatusLive; -// const grpcClient = await GRPCClientClient.createGRPCClientClient({ -// nodeId: statusInfo.data.nodeId, -// host: statusInfo.data.clientHost, -// port: statusInfo.data.clientPort, -// tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, -// logger, -// }); -// const emptyMessage = new utilsPB.EmptyMessage(); -// const meta = clientUtils.encodeAuthFromPassword(globalAgentPassword); -// // This is asynchronous -// await grpcClient.agentStop(emptyMessage, meta); -// await grpcClient.destroy(); -// await status.waitFor('DEAD'); -// } finally { -// lock.unlock(globalAgentLock.fd); -// await globalAgentLock.close(); -// } -// }, -// }; -// } +async function setupGlobalAgent( + logger: Logger = new Logger(setupGlobalAgent.name, LogLevel.WARN, [ + new StreamHandler(), + ]), +) { + const globalAgentPassword = 'password'; + const globalAgentDir = path.join(globalThis.dataDir, 'agent'); + // The references directory will act like our reference count + await fs.promises.mkdir(path.join(globalAgentDir, 'references'), { + recursive: true, + }); + const pid = process.pid.toString(); + // Plus 1 to the reference count + await fs.promises.writeFile(path.join(globalAgentDir, 'references', pid), ''); + const globalAgentLock = await fs.promises.open( + path.join(globalThis.dataDir, 'agent.lock'), + fs.constants.O_WRONLY | fs.constants.O_CREAT, + ); + while (!lock(globalAgentLock.fd)) { + await sleep(1000); + } + const status = new Status({ + statusPath: path.join(globalAgentDir, config.defaults.statusBase), + statusLockPath: path.join(globalAgentDir, config.defaults.statusLockBase), + fs, + }); + let statusInfo = await status.readStatus(); + if (statusInfo == null || statusInfo.status === 'DEAD') { + await PolykeyAgent.createPolykeyAgent({ + password: globalAgentPassword, + nodePath: globalAgentDir, + networkConfig: { + proxyHost: '127.0.0.1' as Host, + forwardHost: '127.0.0.1' as Host, + agentHost: '127.0.0.1' as Host, + clientHost: '127.0.0.1' as Host, + }, + keysConfig: { + rootKeyPairBits: 2048, + }, + seedNodes: {}, // Explicitly no seed nodes on startup + logger, + }); + statusInfo = await status.readStatus(); + } + return { + globalAgentDir, + globalAgentPassword, + globalAgentStatus: statusInfo as StatusLive, + globalAgentClose: async () => { + // Closing the global agent cannot be done in the globalTeardown + // This is due to a sequence of reasons: + // 1. The global agent is not started as a separate process + // 2. Because we need to be able to mock dependencies + // 3. This means it is part of a jest worker process + // 4. Which will block termination of the jest worker process + // 5. Therefore globalTeardown will never get to execute + // 6. The global agent is not part of globalSetup + // 7. Because not all tests need the global agent + // 8. Therefore setupGlobalAgent is lazy and executed by jest worker processes + try { + await fs.promises.rm(path.join(globalAgentDir, 'references', pid)); + // If the references directory is not empty + // there are other processes still using the global agent + try { + await fs.promises.rmdir(path.join(globalAgentDir, 'references')); + } catch (e) { + if (e.code === 'ENOTEMPTY') { + return; + } + throw e; + } + // Stopping may occur in a different jest worker process + // therefore we cannot rely on pkAgent, but instead use GRPC + const statusInfo = (await status.readStatus()) as StatusLive; + const grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: statusInfo.data.nodeId, + host: statusInfo.data.clientHost, + port: statusInfo.data.clientPort, + tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, + logger, + }); + const emptyMessage = new utilsPB.EmptyMessage(); + const meta = clientUtils.encodeAuthFromPassword(globalAgentPassword); + // This is asynchronous + await grpcClient.agentStop(emptyMessage, meta); + await grpcClient.destroy(); + await status.waitFor('DEAD'); + } finally { + lock.unlock(globalAgentLock.fd); + await globalAgentLock.close(); + } + }, + }; +} function generateRandomNodeId(): NodeId { const random = keysUtils.getRandomBytesSync(16).toString('hex'); @@ -197,4 +197,9 @@ const expectRemoteError = async ( } }; -export { setupGlobalKeypair, generateRandomNodeId, expectRemoteError }; +export { + setupGlobalKeypair, + generateRandomNodeId, + expectRemoteError, + setupGlobalAgent, +}; From 607c126cf857d795dd65a25300af21b0ae97aa68 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 17 May 2022 18:28:58 +1000 Subject: [PATCH 035/137] test: fixes for agent tests --- tests/agent/GRPCClientAgent.test.ts | 1 + tests/agent/service/nodesCrossSignClaim.test.ts | 8 ++------ tests/agent/service/notificationsSend.test.ts | 14 ++++++++------ tests/agent/utils.ts | 11 +++++++---- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/tests/agent/GRPCClientAgent.test.ts b/tests/agent/GRPCClientAgent.test.ts index 78808e361..2a9392e74 100644 --- a/tests/agent/GRPCClientAgent.test.ts +++ b/tests/agent/GRPCClientAgent.test.ts @@ -156,6 +156,7 @@ describe(GRPCClientAgent.name, () => { acl, gestaltGraph, proxy, + db, }); client = await testAgentUtils.openTestAgentClient(port); await proxy.start({ diff --git a/tests/agent/service/nodesCrossSignClaim.test.ts b/tests/agent/service/nodesCrossSignClaim.test.ts index 5b3f6c53e..bc676db86 100644 --- a/tests/agent/service/nodesCrossSignClaim.test.ts +++ b/tests/agent/service/nodesCrossSignClaim.test.ts @@ -22,7 +22,7 @@ describe('nodesCrossSignClaim', () => { const logger = new Logger('nodesCrossSignClaim test', LogLevel.WARN, [ new StreamHandler(), ]); - const password = 'helloworld'; + const password = 'hello-world'; let dataDir: string; let nodePath: string; let grpcServer: GRPCServer; @@ -78,6 +78,7 @@ describe('nodesCrossSignClaim', () => { keyManager: pkAgent.keyManager, nodeManager: pkAgent.nodeManager, sigchain: pkAgent.sigchain, + db: pkAgent.db, logger, }), }; @@ -137,7 +138,6 @@ describe('nodesCrossSignClaim', () => { // 2. Singly signed intermediary claim const response = await genClaims.read(); // Check X's sigchain is locked at start - expect(pkAgent.sigchain.locked).toBe(true); expect(response.done).toBe(false); expect(response.value).toBeInstanceOf(nodesPB.CrossSign); const receivedMessage = response.value as nodesPB.CrossSign; @@ -176,14 +176,12 @@ describe('nodesCrossSignClaim', () => { doublySignedClaim: doublyResponse, }); // Just before we complete the last step, check X's sigchain is still locked - expect(pkAgent.sigchain.locked).toBe(true); await genClaims.write(doublyMessage); // Expect the stream to be closed. const finalResponse = await genClaims.read(); expect(finalResponse.done).toBe(true); expect(genClaims.stream.destroyed).toBe(true); // Check X's sigchain is released at end. - expect(pkAgent.sigchain.locked).toBe(false); // Check claim is in both node's sigchains // Rather, check it's in X's sigchain const chain = await pkAgent.sigchain.getChainData(); @@ -208,7 +206,6 @@ describe('nodesCrossSignClaim', () => { await expect(() => genClaims.read()).rejects.toThrow(ErrorPolykeyRemote); expect(genClaims.stream.destroyed).toBe(true); // Check sigchain's lock is released - expect(pkAgent.sigchain.locked).toBe(false); // Revert side effects await pkAgent.sigchain.stop(); await pkAgent.sigchain.destroy(); @@ -228,7 +225,6 @@ describe('nodesCrossSignClaim', () => { await expect(() => genClaims.read()).rejects.toThrow(ErrorPolykeyRemote); expect(genClaims.stream.destroyed).toBe(true); // Check sigchain's lock is released - expect(pkAgent.sigchain.locked).toBe(false); // Revert side effects await pkAgent.sigchain.stop(); await pkAgent.sigchain.destroy(); diff --git a/tests/agent/service/notificationsSend.test.ts b/tests/agent/service/notificationsSend.test.ts index 3732b407e..5d51289e0 100644 --- a/tests/agent/service/notificationsSend.test.ts +++ b/tests/agent/service/notificationsSend.test.ts @@ -28,6 +28,7 @@ import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import * as notificationsUtils from '@/notifications/utils'; import * as testUtils from '../../utils'; +import { expectRemoteError } from '../../utils'; describe('notificationsSend', () => { const logger = new Logger('notificationsSend test', LogLevel.WARN, [ @@ -222,9 +223,10 @@ describe('notificationsSend', () => { }; const request1 = new notificationsPB.AgentNotification(); request1.setContent(notification1.toString()); - await expect(async () => + await expectRemoteError( grpcClient.notificationsSend(request1), - ).rejects.toThrow(notificationsErrors.ErrorNotificationsParse); + notificationsErrors.ErrorNotificationsParse, + ); // Check notification was not received let receivedNotifications = await notificationsManager.readNotifications(); expect(receivedNotifications).toHaveLength(0); @@ -249,9 +251,10 @@ describe('notificationsSend', () => { .sign(privateKey); const request2 = new notificationsPB.AgentNotification(); request2.setContent(signedNotification); - await expect(async () => + await expectRemoteError( grpcClient.notificationsSend(request2), - ).rejects.toThrow(notificationsErrors.ErrorNotificationsValidationFailed); + notificationsErrors.ErrorNotificationsValidationFailed, + ); // Check notification was not received receivedNotifications = await notificationsManager.readNotifications(); expect(receivedNotifications).toHaveLength(0); @@ -274,9 +277,8 @@ describe('notificationsSend', () => { ); const request = new notificationsPB.AgentNotification(); request.setContent(signedNotification); - await expect(async () => + await expectRemoteError( grpcClient.notificationsSend(request), - ).rejects.toThrow( notificationsErrors.ErrorNotificationsPermissionsNotFound, ); // Check notification was not received diff --git a/tests/agent/utils.ts b/tests/agent/utils.ts index 8cf77303e..296707684 100644 --- a/tests/agent/utils.ts +++ b/tests/agent/utils.ts @@ -3,20 +3,21 @@ import type { Host, Port, ProxyConfig } from '@/network/types'; import type { IAgentServiceServer } from '@/proto/js/polykey/v1/agent_service_grpc_pb'; import type { KeyManager } from '@/keys'; import type { VaultManager } from '@/vaults'; -import type { NodeGraph, NodeConnectionManager, NodeManager } from '@/nodes'; +import type { NodeConnectionManager, NodeGraph, NodeManager } from '@/nodes'; import type { Sigchain } from '@/sigchain'; import type { NotificationsManager } from '@/notifications'; import type { ACL } from '@/acl'; import type { GestaltGraph } from '@/gestalts'; import type { NodeId } from 'nodes/types'; import type Proxy from 'network/Proxy'; +import type { DB } from '@matrixai/db'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import { promisify } from '@/utils'; import { + AgentServiceService, createAgentService, GRPCClientAgent, - AgentServiceService, } from '@/agent'; import * as testUtils from '../utils'; @@ -31,6 +32,7 @@ async function openTestAgentServer({ acl, gestaltGraph, proxy, + db, }: { keyManager: KeyManager; vaultManager: VaultManager; @@ -42,6 +44,7 @@ async function openTestAgentServer({ acl: ACL; gestaltGraph: GestaltGraph; proxy: Proxy; + db: DB; }) { const agentService: IAgentServiceServer = createAgentService({ keyManager, @@ -54,6 +57,7 @@ async function openTestAgentServer({ acl, gestaltGraph, proxy, + db, }); const server = new grpc.Server(); @@ -80,7 +84,7 @@ async function openTestAgentClient( const logger = new Logger('AgentClientTest', LogLevel.WARN, [ new StreamHandler(), ]); - const agentClient = await GRPCClientAgent.createGRPCClientAgent({ + return await GRPCClientAgent.createGRPCClientAgent({ nodeId: nodeId ?? testUtils.generateRandomNodeId(), host: '127.0.0.1' as Host, port: port as Port, @@ -89,7 +93,6 @@ async function openTestAgentClient( proxyConfig, timeout: 30000, }); - return agentClient; } async function closeTestAgentClient(client: GRPCClientAgent) { From e71c53634fecb710cd91153b8201264e35a48d74 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 17 May 2022 18:43:08 +1000 Subject: [PATCH 036/137] test: fixes for grpc tests --- tests/grpc/GRPCClient.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/grpc/GRPCClient.test.ts b/tests/grpc/GRPCClient.test.ts index de8618005..31028187e 100644 --- a/tests/grpc/GRPCClient.test.ts +++ b/tests/grpc/GRPCClient.test.ts @@ -18,6 +18,7 @@ import * as clientUtils from '@/client/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as utils from './utils'; import * as testUtils from '../utils'; +import { expectRemoteError } from '../utils'; describe('GRPCClient', () => { const logger = new Logger('GRPCClient Test', LogLevel.WARN, [ @@ -173,7 +174,7 @@ describe('GRPCClient', () => { const m2 = new utilsPB.EchoMessage(); m2.setChallenge('error'); pCall = client.unary(m2); - await expect(pCall).rejects.toThrow(grpcErrors.ErrorGRPC); + await expectRemoteError(pCall, grpcErrors.ErrorGRPC); meta = await pCall.meta; // Expect reflected reflected session token expect(clientUtils.decodeAuthToSession(meta)).toBe( From 0ef9299a6c07407701e4c7140403f1e5260e6e94 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 18 May 2022 16:08:31 +1000 Subject: [PATCH 037/137] feat: error serialisation/deserialisation + metadata --- src/ErrorPolykey.ts | 83 +++----- src/agent/GRPCClientAgent.ts | 30 +++ src/agent/service/nodesChainDataGet.ts | 4 +- .../service/nodesClosestLocalNodesGet.ts | 9 +- .../service/nodesHolePunchMessageSend.ts | 8 +- src/agent/service/notificationsSend.ts | 6 +- src/client/GRPCClientClient.ts | 192 ++++++++++++++++++ .../service/gestaltsActionsGetByNode.ts | 7 +- .../service/gestaltsActionsSetByIdentity.ts | 7 +- .../service/gestaltsActionsSetByNode.ts | 7 +- .../service/gestaltsActionsUnsetByIdentity.ts | 7 +- .../service/gestaltsActionsUnsetByNode.ts | 7 +- .../service/gestaltsDiscoveryByIdentity.ts | 2 +- src/client/service/gestaltsDiscoveryByNode.ts | 2 +- .../service/gestaltsGestaltGetByIdentity.ts | 7 +- .../service/gestaltsGestaltGetByNode.ts | 7 +- src/client/service/gestaltsGestaltList.ts | 4 +- .../service/gestaltsGestaltTrustByIdentity.ts | 4 +- .../service/gestaltsGestaltTrustByNode.ts | 4 +- src/client/service/identitiesAuthenticate.ts | 9 +- .../service/identitiesAuthenticatedGet.ts | 2 +- src/client/service/identitiesClaim.ts | 15 +- .../service/identitiesInfoConnectedGet.ts | 2 +- src/client/service/identitiesInfoGet.ts | 2 +- src/client/service/identitiesProvidersList.ts | 4 +- src/client/service/identitiesTokenDelete.ts | 7 +- src/client/service/identitiesTokenGet.ts | 7 +- src/client/service/identitiesTokenPut.ts | 7 +- src/client/service/index.ts | 4 +- src/client/service/keysCertsChainGet.ts | 4 +- src/client/service/keysCertsGet.ts | 4 +- src/client/service/keysDecrypt.ts | 4 +- src/client/service/keysEncrypt.ts | 4 +- src/client/service/keysKeyPairRenew.ts | 4 +- src/client/service/keysKeyPairReset.ts | 4 +- src/client/service/keysKeyPairRoot.ts | 4 +- src/client/service/keysPasswordChange.ts | 4 +- src/client/service/keysSign.ts | 4 +- src/client/service/keysVerify.ts | 4 +- src/client/service/nodesAdd.ts | 7 +- src/client/service/nodesClaim.ts | 9 +- src/client/service/nodesFind.ts | 9 +- src/client/service/nodesPing.ts | 7 +- src/client/service/notificationsClear.ts | 4 +- src/client/service/notificationsRead.ts | 4 +- src/client/service/notificationsSend.ts | 9 +- src/client/service/vaultsPermissionGet.ts | 2 +- src/client/utils/utils.ts | 4 +- src/grpc/GRPCClient.ts | 8 + src/grpc/utils/utils.ts | 165 +++++++++++---- tests/client/service/agentLockAll.test.ts | 1 + 51 files changed, 519 insertions(+), 206 deletions(-) diff --git a/src/ErrorPolykey.ts b/src/ErrorPolykey.ts index deba43ef2..4ee452242 100644 --- a/src/ErrorPolykey.ts +++ b/src/ErrorPolykey.ts @@ -1,61 +1,42 @@ -import type { POJO } from './types'; +import type { Class } from '@matrixai/errors'; import { AbstractError } from '@matrixai/errors'; import sysexits from './utils/sysexits'; class ErrorPolykey extends AbstractError { static description: string = 'Polykey error'; exitCode: number = sysexits.GENERAL; - public toJSON( - _key: string = '', - options: { - description?: boolean; - message?: boolean; - exitCode?: boolean; - timestamp?: boolean; - data?: boolean; - cause?: boolean; - stack?: boolean; - } = {}, - ): { - type: string; - data: { - description?: string; - message?: string; - exitCode?: number; - timestamp?: Date; - data?: POJO; - cause?: T; - stack?: string; - }; - } { - options.description ??= true; - options.message ??= true; - options.exitCode ??= true; - options.timestamp ??= true; - options.data ??= true; - options.cause ??= true; - options.stack ??= true; - const data: POJO = {}; - if (options.description) data.description = this.description; - if (options.message) data.message = this.message; - if (options.exitCode) data.exitCode = this.exitCode; - if (options.timestamp) data.timestamp = this.timestamp; - if (options.data) data.data = this.data; - if (options.cause) { - // Propagate the options down the exception chain - // but only if the cause is another AbstractError - if (this.cause instanceof ErrorPolykey) { - data.cause = this.cause.toJSON('cause', options); - } else { - // Use `replacer` to further encode this object - data.cause = this.cause; - } + + public static fromJSON>( + this: T, + json: any, + ): InstanceType { + if ( + typeof json !== 'object' || + json.type !== this.name || + typeof json.data !== 'object' || + typeof json.data.message !== 'string' || + isNaN(Date.parse(json.data.timestamp)) || + typeof json.data.data !== 'object' || + typeof json.data.exitCode !== 'string' || + !('cause' in json.data) || + ('stack' in json.data && typeof json.data.stack !== 'string') + ) { + throw new TypeError(`Cannot decode JSON to ${this.name}`); } - if (options.stack) data.stack = this.stack; - return { - type: this.name, - data, - }; + const e = new this(json.data.message, { + timestamp: new Date(json.data.timestamp), + data: json.data.data, + cause: json.data.cause, + }); + e.exitCode = json.data.exitCode; + e.stack = json.data.stack; + return e; + } + + public toJSON(): any { + const json = super.toJSON(); + json.data.exitCode = this.exitCode; + return json; } } diff --git a/src/agent/GRPCClientAgent.ts b/src/agent/GRPCClientAgent.ts index 4190f66b6..dd68e2db5 100644 --- a/src/agent/GRPCClientAgent.ts +++ b/src/agent/GRPCClientAgent.ts @@ -79,6 +79,9 @@ class GRPCClientAgent extends GRPCClient { public echo(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.echo, )(...args); } @@ -92,6 +95,9 @@ class GRPCClientAgent extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsGitInfoGet, )(...args); } @@ -106,6 +112,9 @@ class GRPCClientAgent extends GRPCClient { > { return grpcUtils.promisifyDuplexStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsGitPackGet, )(...args); } @@ -119,6 +128,9 @@ class GRPCClientAgent extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsScan, )(...args); } @@ -127,6 +139,9 @@ class GRPCClientAgent extends GRPCClient { public nodesClosestLocalNodesGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.nodesClosestLocalNodesGet, )(...args); } @@ -135,6 +150,9 @@ class GRPCClientAgent extends GRPCClient { public nodesClaimsGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.nodesClaimsGet, )(...args); } @@ -143,6 +161,9 @@ class GRPCClientAgent extends GRPCClient { public nodesChainDataGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.nodesChainDataGet, )(...args); } @@ -151,6 +172,9 @@ class GRPCClientAgent extends GRPCClient { public nodesHolePunchMessageSend(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.nodesHolePunchMessageSend, )(...args); } @@ -159,6 +183,9 @@ class GRPCClientAgent extends GRPCClient { public notificationsSend(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.notificationsSend, )(...args); } @@ -176,6 +203,9 @@ class GRPCClientAgent extends GRPCClient { nodesPB.CrossSign >( this.client, + this.nodeId, + this.host, + this.port, this.client.nodesCrossSignClaim, )(...args); } diff --git a/src/agent/service/nodesChainDataGet.ts b/src/agent/service/nodesChainDataGet.ts index 4301dff01..f2970228f 100644 --- a/src/agent/service/nodesChainDataGet.ts +++ b/src/agent/service/nodesChainDataGet.ts @@ -1,9 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; -import type { Sigchain } from '../../sigchain'; +import type Sigchain from '../../sigchain/Sigchain'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type { ClaimIdEncoded } from '../../claims/types'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; /** diff --git a/src/agent/service/nodesClosestLocalNodesGet.ts b/src/agent/service/nodesClosestLocalNodesGet.ts index dc709195b..ee031f478 100644 --- a/src/agent/service/nodesClosestLocalNodesGet.ts +++ b/src/agent/service/nodesClosestLocalNodesGet.ts @@ -1,10 +1,11 @@ import type * as grpc from '@grpc/grpc-js'; -import type { NodeConnectionManager } from '../../nodes'; +import type NodeConnectionManager from '../../nodes/NodeConnectionManager'; import type { NodeId } from '../../nodes/types'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { utils as nodesUtils } from '../../nodes'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import * as nodesUtils from '../../nodes/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; diff --git a/src/agent/service/nodesHolePunchMessageSend.ts b/src/agent/service/nodesHolePunchMessageSend.ts index 438af3775..592d0f482 100644 --- a/src/agent/service/nodesHolePunchMessageSend.ts +++ b/src/agent/service/nodesHolePunchMessageSend.ts @@ -1,12 +1,14 @@ import type * as grpc from '@grpc/grpc-js'; -import type { NodeManager, NodeConnectionManager } from '../../nodes'; +import type NodeManager from '../../nodes/NodeManager'; +import type NodeConnectionManager from '../../nodes/NodeConnectionManager'; import type KeyManager from '../../keys/KeyManager'; import type { NodeId } from '../../nodes/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type Logger from '@matrixai/logger'; import * as networkUtils from '../../network/utils'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/agent/service/notificationsSend.ts b/src/agent/service/notificationsSend.ts index f11a18c95..6baef6f9f 100644 --- a/src/agent/service/notificationsSend.ts +++ b/src/agent/service/notificationsSend.ts @@ -1,9 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; -import type { NotificationsManager } from '../../notifications'; +import type NotificationsManager from '../../notifications/NotificationsManager'; import type * as notificationsPB from '../../proto/js/polykey/v1/notifications/notifications_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { utils as notificationsUtils } from '../../notifications'; +import * as grpcUtils from '../../grpc/utils'; +import * as notificationsUtils from '../../notifications/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function notificationsSend({ diff --git a/src/client/GRPCClientClient.ts b/src/client/GRPCClientClient.ts index 3b07305ea..87ff45b6c 100644 --- a/src/client/GRPCClientClient.ts +++ b/src/client/GRPCClientClient.ts @@ -91,6 +91,9 @@ class GRPCClientClient extends GRPCClient { public agentStatus(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.agentStatus, )(...args); } @@ -99,6 +102,9 @@ class GRPCClientClient extends GRPCClient { public agentStop(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.agentStop, )(...args); } @@ -107,6 +113,9 @@ class GRPCClientClient extends GRPCClient { public agentUnlock(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.agentUnlock, )(...args); } @@ -115,6 +124,9 @@ class GRPCClientClient extends GRPCClient { public agentLockAll(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.agentLockAll, )(...args); } @@ -128,6 +140,9 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsList, )(...args); } @@ -136,6 +151,9 @@ class GRPCClientClient extends GRPCClient { public vaultsCreate(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsCreate, )(...args); } @@ -144,6 +162,9 @@ class GRPCClientClient extends GRPCClient { public vaultsRename(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsRename, )(...args); } @@ -152,6 +173,9 @@ class GRPCClientClient extends GRPCClient { public vaultsDelete(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsDelete, )(...args); } @@ -160,6 +184,9 @@ class GRPCClientClient extends GRPCClient { public vaultsClone(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsClone, )(...args); } @@ -168,6 +195,9 @@ class GRPCClientClient extends GRPCClient { public vaultsPull(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsPull, )(...args); } @@ -181,6 +211,9 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsScan, )(...args); } @@ -189,6 +222,9 @@ class GRPCClientClient extends GRPCClient { public vaultsPermissionGet(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsPermissionGet, )(...args); } @@ -197,6 +233,9 @@ class GRPCClientClient extends GRPCClient { public vaultsPermissionSet(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsPermissionSet, )(...args); } @@ -205,6 +244,9 @@ class GRPCClientClient extends GRPCClient { public vaultsPermissionUnset(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsPermissionUnset, )(...args); } @@ -218,6 +260,9 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsSecretsList, )(...args); } @@ -226,6 +271,9 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsMkdir(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsSecretsMkdir, )(...args); } @@ -234,6 +282,9 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsDelete(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsSecretsDelete, )(...args); } @@ -242,6 +293,9 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsEdit(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsSecretsEdit, )(...args); } @@ -250,6 +304,9 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsSecretsGet, )(...args); } @@ -258,6 +315,9 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsStat(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsSecretsStat, )(...args); } @@ -266,6 +326,9 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsRename(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsSecretsRename, )(...args); } @@ -274,6 +337,9 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsNew(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsSecretsNew, )(...args); } @@ -282,6 +348,9 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsNewDir(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsSecretsNewDir, )(...args); } @@ -290,6 +359,9 @@ class GRPCClientClient extends GRPCClient { public vaultsVersion(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsVersion, )(...args); } @@ -303,6 +375,9 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.vaultsLog, )(...args); } @@ -311,6 +386,9 @@ class GRPCClientClient extends GRPCClient { public keysKeyPairRoot(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.keysKeyPairRoot, )(...args); } @@ -319,6 +397,9 @@ class GRPCClientClient extends GRPCClient { public keysKeyPairReset(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.keysKeyPairReset, )(...args); } @@ -327,6 +408,9 @@ class GRPCClientClient extends GRPCClient { public keysKeyPairRenew(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.keysKeyPairRenew, )(...args); } @@ -335,6 +419,9 @@ class GRPCClientClient extends GRPCClient { public keysEncrypt(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.keysEncrypt, )(...args); } @@ -343,6 +430,9 @@ class GRPCClientClient extends GRPCClient { public keysDecrypt(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.keysDecrypt, )(...args); } @@ -351,6 +441,9 @@ class GRPCClientClient extends GRPCClient { public keysSign(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.keysSign, )(...args); } @@ -359,6 +452,9 @@ class GRPCClientClient extends GRPCClient { public keysVerify(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.keysVerify, )(...args); } @@ -367,6 +463,9 @@ class GRPCClientClient extends GRPCClient { public keysPasswordChange(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.keysPasswordChange, )(...args); } @@ -375,6 +474,9 @@ class GRPCClientClient extends GRPCClient { public keysCertsGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.keysCertsGet, )(...args); } @@ -388,6 +490,9 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.keysCertsChainGet, )(...args); } @@ -401,6 +506,9 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsGestaltList, )(...args); } @@ -409,6 +517,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsGestaltGetByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsGestaltGetByIdentity, )(...args); } @@ -417,6 +528,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsGestaltGetByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsGestaltGetByNode, )(...args); } @@ -425,6 +539,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsDiscoveryByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsDiscoveryByNode, )(...args); } @@ -433,6 +550,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsDiscoveryByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsDiscoveryByIdentity, )(...args); } @@ -441,6 +561,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsGetByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsActionsGetByNode, )(...args); } @@ -449,6 +572,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsGetByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsActionsGetByIdentity, )(...args); } @@ -457,6 +583,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsSetByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsActionsSetByNode, )(...args); } @@ -465,6 +594,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsSetByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsActionsSetByIdentity, )(...args); } @@ -473,6 +605,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsUnsetByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsActionsUnsetByNode, )(...args); } @@ -481,6 +616,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsUnsetByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsActionsUnsetByIdentity, )(...args); } @@ -489,6 +627,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsGestaltTrustByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsGestaltTrustByNode, )(...args); } @@ -497,6 +638,9 @@ class GRPCClientClient extends GRPCClient { public gestaltsGestaltTrustByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.gestaltsGestaltTrustByIdentity, )(...args); } @@ -505,6 +649,9 @@ class GRPCClientClient extends GRPCClient { public identitiesTokenPut(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.identitiesTokenPut, )(...args); } @@ -513,6 +660,9 @@ class GRPCClientClient extends GRPCClient { public identitiesTokenGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.identitiesTokenGet, )(...args); } @@ -521,6 +671,9 @@ class GRPCClientClient extends GRPCClient { public identitiesTokenDelete(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.identitiesTokenDelete, )(...args); } @@ -529,6 +682,9 @@ class GRPCClientClient extends GRPCClient { public identitiesProvidersList(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.identitiesProvidersList, )(...args); } @@ -537,6 +693,9 @@ class GRPCClientClient extends GRPCClient { public nodesAdd(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.nodesAdd, )(...args); } @@ -545,6 +704,9 @@ class GRPCClientClient extends GRPCClient { public nodesPing(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.nodesPing, )(...args); } @@ -553,6 +715,9 @@ class GRPCClientClient extends GRPCClient { public nodesClaim(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.nodesClaim, )(...args); } @@ -561,6 +726,9 @@ class GRPCClientClient extends GRPCClient { public nodesFind(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.nodesFind, )(...args); } @@ -569,6 +737,9 @@ class GRPCClientClient extends GRPCClient { public identitiesAuthenticate(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.identitiesAuthenticate, )(...args); } @@ -577,6 +748,9 @@ class GRPCClientClient extends GRPCClient { public identitiesInfoConnectedGet(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.identitiesInfoConnectedGet, )(...args); } @@ -585,6 +759,9 @@ class GRPCClientClient extends GRPCClient { public identitiesInfoGet(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.identitiesInfoGet, )(...args); } @@ -593,6 +770,9 @@ class GRPCClientClient extends GRPCClient { public identitiesClaim(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.identitiesClaim, )(...args); } @@ -601,6 +781,9 @@ class GRPCClientClient extends GRPCClient { public identitiesAuthenticatedGet(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, + this.nodeId, + this.host, + this.port, this.client.identitiesAuthenticatedGet, )(...args); } @@ -609,6 +792,9 @@ class GRPCClientClient extends GRPCClient { public notificationsSend(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.notificationsSend, )(...args); } @@ -617,6 +803,9 @@ class GRPCClientClient extends GRPCClient { public notificationsRead(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.notificationsRead, )(...args); } @@ -625,6 +814,9 @@ class GRPCClientClient extends GRPCClient { public notificationsClear(...args) { return grpcUtils.promisifyUnaryCall( this.client, + this.nodeId, + this.host, + this.port, this.client.notificationsClear, )(...args); } diff --git a/src/client/service/gestaltsActionsGetByNode.ts b/src/client/service/gestaltsActionsGetByNode.ts index 77b6c54fd..162b6be9f 100644 --- a/src/client/service/gestaltsActionsGetByNode.ts +++ b/src/client/service/gestaltsActionsGetByNode.ts @@ -1,11 +1,12 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { NodeId } from '../../nodes/types'; -import type { GestaltGraph } from '../../gestalts'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; diff --git a/src/client/service/gestaltsActionsSetByIdentity.ts b/src/client/service/gestaltsActionsSetByIdentity.ts index 34140fec9..318ca90b6 100644 --- a/src/client/service/gestaltsActionsSetByIdentity.ts +++ b/src/client/service/gestaltsActionsSetByIdentity.ts @@ -1,12 +1,13 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { GestaltGraph } from '../../gestalts'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { GestaltAction } from '../../gestalts/types'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/client/service/gestaltsActionsSetByNode.ts b/src/client/service/gestaltsActionsSetByNode.ts index 0c801c350..cd035f0cf 100644 --- a/src/client/service/gestaltsActionsSetByNode.ts +++ b/src/client/service/gestaltsActionsSetByNode.ts @@ -1,12 +1,13 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { GestaltGraph } from '../../gestalts'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { GestaltAction } from '../../gestalts/types'; import type { NodeId } from '../../nodes/types'; import type * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/client/service/gestaltsActionsUnsetByIdentity.ts b/src/client/service/gestaltsActionsUnsetByIdentity.ts index 9ab5ac61e..8cbd2596a 100644 --- a/src/client/service/gestaltsActionsUnsetByIdentity.ts +++ b/src/client/service/gestaltsActionsUnsetByIdentity.ts @@ -1,12 +1,13 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { GestaltGraph } from '../../gestalts'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { GestaltAction } from '../../gestalts/types'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/client/service/gestaltsActionsUnsetByNode.ts b/src/client/service/gestaltsActionsUnsetByNode.ts index 795f9c4fc..958a18060 100644 --- a/src/client/service/gestaltsActionsUnsetByNode.ts +++ b/src/client/service/gestaltsActionsUnsetByNode.ts @@ -1,12 +1,13 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { GestaltGraph } from '../../gestalts'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { GestaltAction } from '../../gestalts/types'; import type { NodeId } from '../../nodes/types'; import type * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/client/service/gestaltsDiscoveryByIdentity.ts b/src/client/service/gestaltsDiscoveryByIdentity.ts index c8e515ab7..9834d4e7c 100644 --- a/src/client/service/gestaltsDiscoveryByIdentity.ts +++ b/src/client/service/gestaltsDiscoveryByIdentity.ts @@ -1,6 +1,6 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { Discovery } from '../../discovery'; +import type Discovery from '../../discovery/Discovery'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; import type Logger from '@matrixai/logger'; diff --git a/src/client/service/gestaltsDiscoveryByNode.ts b/src/client/service/gestaltsDiscoveryByNode.ts index 26e575c51..ed8ab18e6 100644 --- a/src/client/service/gestaltsDiscoveryByNode.ts +++ b/src/client/service/gestaltsDiscoveryByNode.ts @@ -1,6 +1,6 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { Discovery } from '../../discovery'; +import type Discovery from '../../discovery/Discovery'; import type { NodeId } from '../../nodes/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type Logger from '@matrixai/logger'; diff --git a/src/client/service/gestaltsGestaltGetByIdentity.ts b/src/client/service/gestaltsGestaltGetByIdentity.ts index 5f2257a82..c303995ee 100644 --- a/src/client/service/gestaltsGestaltGetByIdentity.ts +++ b/src/client/service/gestaltsGestaltGetByIdentity.ts @@ -1,11 +1,12 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { GestaltGraph } from '../../gestalts'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; diff --git a/src/client/service/gestaltsGestaltGetByNode.ts b/src/client/service/gestaltsGestaltGetByNode.ts index a0ea6f03c..4cb9cf96d 100644 --- a/src/client/service/gestaltsGestaltGetByNode.ts +++ b/src/client/service/gestaltsGestaltGetByNode.ts @@ -1,11 +1,12 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type { NodeId } from '../../nodes/types'; -import type { GestaltGraph } from '../../gestalts'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; diff --git a/src/client/service/gestaltsGestaltList.ts b/src/client/service/gestaltsGestaltList.ts index 305cd3b7d..690988c20 100644 --- a/src/client/service/gestaltsGestaltList.ts +++ b/src/client/service/gestaltsGestaltList.ts @@ -1,10 +1,10 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { GestaltGraph } from '../../gestalts'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { Gestalt } from '../../gestalts/types'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; function gestaltsGestaltList({ diff --git a/src/client/service/gestaltsGestaltTrustByIdentity.ts b/src/client/service/gestaltsGestaltTrustByIdentity.ts index df7b60dc4..a5359bc82 100644 --- a/src/client/service/gestaltsGestaltTrustByIdentity.ts +++ b/src/client/service/gestaltsGestaltTrustByIdentity.ts @@ -1,8 +1,8 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { GestaltGraph } from '../../gestalts'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { IdentityId, ProviderId } from '../../identities/types'; -import type { Discovery } from '../../discovery'; +import type Discovery from '../../discovery/Discovery'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; import type Logger from '@matrixai/logger'; import { validateSync } from '../../validation'; diff --git a/src/client/service/gestaltsGestaltTrustByNode.ts b/src/client/service/gestaltsGestaltTrustByNode.ts index 8ebe7660b..bad8dc219 100644 --- a/src/client/service/gestaltsGestaltTrustByNode.ts +++ b/src/client/service/gestaltsGestaltTrustByNode.ts @@ -1,7 +1,7 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { GestaltGraph } from '../../gestalts'; -import type { Discovery } from '../../discovery'; +import type GestaltGraph from '../../gestalts/GestaltGraph'; +import type Discovery from '../../discovery/Discovery'; import type { NodeId } from '../../nodes/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type Logger from '@matrixai/logger'; diff --git a/src/client/service/identitiesAuthenticate.ts b/src/client/service/identitiesAuthenticate.ts index e2e39162f..05c3e05d3 100644 --- a/src/client/service/identitiesAuthenticate.ts +++ b/src/client/service/identitiesAuthenticate.ts @@ -1,11 +1,12 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { IdentitiesManager } from '../../identities'; +import type IdentitiesManager from '../../identities/IdentitiesManager'; import type { ProviderId } from '../../identities/types'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { errors as identitiesErrors } from '../../identities'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import * as identitiesErrors from '../../identities/errors'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync, never } from '../../utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; diff --git a/src/client/service/identitiesAuthenticatedGet.ts b/src/client/service/identitiesAuthenticatedGet.ts index d344c14a6..82262f89d 100644 --- a/src/client/service/identitiesAuthenticatedGet.ts +++ b/src/client/service/identitiesAuthenticatedGet.ts @@ -1,6 +1,6 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { IdentitiesManager } from '../../identities'; +import type IdentitiesManager from '../../identities/IdentitiesManager'; import type { ProviderId } from '../../identities/types'; import type Logger from '@matrixai/logger'; import { validateSync } from '../../validation'; diff --git a/src/client/service/identitiesClaim.ts b/src/client/service/identitiesClaim.ts index 2367998df..93a947e42 100644 --- a/src/client/service/identitiesClaim.ts +++ b/src/client/service/identitiesClaim.ts @@ -1,15 +1,16 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type KeyManager from '../../keys/KeyManager'; -import type { Sigchain } from '../../sigchain'; -import type { IdentitiesManager } from '../../identities'; +import type Sigchain from '../../sigchain/Sigchain'; +import type IdentitiesManager from '../../identities/IdentitiesManager'; import type { IdentityId, ProviderId } from '../../identities/types'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { utils as claimsUtils } from '../../claims'; -import { utils as nodesUtils } from '../../nodes'; -import { errors as identitiesErrors } from '../../identities'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import * as claimsUtils from '../../claims/utils'; +import * as nodesUtils from '../../nodes/utils'; +import * as identitiesErrors from '../../identities/errors'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; diff --git a/src/client/service/identitiesInfoConnectedGet.ts b/src/client/service/identitiesInfoConnectedGet.ts index f232e3a4d..b9d7ac441 100644 --- a/src/client/service/identitiesInfoConnectedGet.ts +++ b/src/client/service/identitiesInfoConnectedGet.ts @@ -1,6 +1,6 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { IdentitiesManager } from '../../identities'; +import type IdentitiesManager from '../../identities/IdentitiesManager'; import type { IdentityData, IdentityId, diff --git a/src/client/service/identitiesInfoGet.ts b/src/client/service/identitiesInfoGet.ts index 31a8139c8..5f456dac5 100644 --- a/src/client/service/identitiesInfoGet.ts +++ b/src/client/service/identitiesInfoGet.ts @@ -1,6 +1,6 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { IdentitiesManager } from '../../identities'; +import type IdentitiesManager from '../../identities/IdentitiesManager'; import type { IdentityData, IdentityId, diff --git a/src/client/service/identitiesProvidersList.ts b/src/client/service/identitiesProvidersList.ts index 8fa533a9c..35751c3fb 100644 --- a/src/client/service/identitiesProvidersList.ts +++ b/src/client/service/identitiesProvidersList.ts @@ -1,9 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { IdentitiesManager } from '../../identities'; +import type IdentitiesManager from '../../identities/IdentitiesManager'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; function identitiesProvidersList({ diff --git a/src/client/service/identitiesTokenDelete.ts b/src/client/service/identitiesTokenDelete.ts index 69bba5775..347e37bb4 100644 --- a/src/client/service/identitiesTokenDelete.ts +++ b/src/client/service/identitiesTokenDelete.ts @@ -1,11 +1,12 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { IdentitiesManager } from '../../identities'; +import type IdentitiesManager from '../../identities/IdentitiesManager'; import type { IdentityId, ProviderId } from '../../identities/types'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/client/service/identitiesTokenGet.ts b/src/client/service/identitiesTokenGet.ts index cb7987156..7844382a8 100644 --- a/src/client/service/identitiesTokenGet.ts +++ b/src/client/service/identitiesTokenGet.ts @@ -1,10 +1,11 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { IdentitiesManager } from '../../identities'; +import type IdentitiesManager from '../../identities/IdentitiesManager'; import type { IdentityId, ProviderId } from '../../identities/types'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; diff --git a/src/client/service/identitiesTokenPut.ts b/src/client/service/identitiesTokenPut.ts index cb532d4c1..babfd8db7 100644 --- a/src/client/service/identitiesTokenPut.ts +++ b/src/client/service/identitiesTokenPut.ts @@ -1,11 +1,12 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { IdentitiesManager } from '../../identities'; +import type IdentitiesManager from '../../identities/IdentitiesManager'; import type { IdentityId, ProviderId, TokenData } from '../../identities/types'; import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/client/service/index.ts b/src/client/service/index.ts index dc7ac4ff7..1e74eb9d8 100644 --- a/src/client/service/index.ts +++ b/src/client/service/index.ts @@ -1,6 +1,6 @@ import type { DB } from '@matrixai/db'; import type PolykeyAgent from '../../PolykeyAgent'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type { VaultManager } from '../../vaults'; import type { NodeManager, @@ -10,7 +10,7 @@ import type { import type { IdentitiesManager } from '../../identities'; import type { GestaltGraph } from '../../gestalts'; import type { SessionManager } from '../../sessions'; -import type { NotificationsManager } from '../../notifications'; +import type NotificationsManager from '../../notifications/NotificationsManager'; import type { Discovery } from '../../discovery'; import type { Sigchain } from '../../sigchain'; import type { GRPCServer } from '../../grpc'; diff --git a/src/client/service/keysCertsChainGet.ts b/src/client/service/keysCertsChainGet.ts index b62c85783..6290a313c 100644 --- a/src/client/service/keysCertsChainGet.ts +++ b/src/client/service/keysCertsChainGet.ts @@ -1,9 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysCertsChainGet({ diff --git a/src/client/service/keysCertsGet.ts b/src/client/service/keysCertsGet.ts index 6d63cfba8..eabde463b 100644 --- a/src/client/service/keysCertsGet.ts +++ b/src/client/service/keysCertsGet.ts @@ -1,9 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysCertsGet({ diff --git a/src/client/service/keysDecrypt.ts b/src/client/service/keysDecrypt.ts index 05e68e066..ed1776cda 100644 --- a/src/client/service/keysDecrypt.ts +++ b/src/client/service/keysDecrypt.ts @@ -1,8 +1,8 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysDecrypt({ diff --git a/src/client/service/keysEncrypt.ts b/src/client/service/keysEncrypt.ts index 2c84444fb..35159f870 100644 --- a/src/client/service/keysEncrypt.ts +++ b/src/client/service/keysEncrypt.ts @@ -1,8 +1,8 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysEncrypt({ diff --git a/src/client/service/keysKeyPairRenew.ts b/src/client/service/keysKeyPairRenew.ts index c2d88acca..dcd90d7c1 100644 --- a/src/client/service/keysKeyPairRenew.ts +++ b/src/client/service/keysKeyPairRenew.ts @@ -1,9 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function keysKeyPairRenew({ diff --git a/src/client/service/keysKeyPairReset.ts b/src/client/service/keysKeyPairReset.ts index 82e73277e..87498f733 100644 --- a/src/client/service/keysKeyPairReset.ts +++ b/src/client/service/keysKeyPairReset.ts @@ -1,9 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function keysKeyPairReset({ diff --git a/src/client/service/keysKeyPairRoot.ts b/src/client/service/keysKeyPairRoot.ts index 9f20b410b..7bfc95549 100644 --- a/src/client/service/keysKeyPairRoot.ts +++ b/src/client/service/keysKeyPairRoot.ts @@ -1,9 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysKeyPairRoot({ diff --git a/src/client/service/keysPasswordChange.ts b/src/client/service/keysPasswordChange.ts index 21ad66425..639e60ac9 100644 --- a/src/client/service/keysPasswordChange.ts +++ b/src/client/service/keysPasswordChange.ts @@ -1,9 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type * as sessionsPB from '../../proto/js/polykey/v1/sessions/sessions_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function keysPasswordChange({ diff --git a/src/client/service/keysSign.ts b/src/client/service/keysSign.ts index 14f722a0c..b998e0561 100644 --- a/src/client/service/keysSign.ts +++ b/src/client/service/keysSign.ts @@ -1,8 +1,8 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; function keysSign({ diff --git a/src/client/service/keysVerify.ts b/src/client/service/keysVerify.ts index 26918bc3d..efbfb7b4c 100644 --- a/src/client/service/keysVerify.ts +++ b/src/client/service/keysVerify.ts @@ -1,9 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function keysVerify({ diff --git a/src/client/service/nodesAdd.ts b/src/client/service/nodesAdd.ts index 7cbfb739f..cda85ee22 100644 --- a/src/client/service/nodesAdd.ts +++ b/src/client/service/nodesAdd.ts @@ -1,12 +1,13 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { NodeManager } from '../../nodes'; +import type NodeManager from '../../nodes/NodeManager'; import type { NodeId, NodeAddress } from '../../nodes/types'; import type { Host, Hostname, Port } from '../../network/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/client/service/nodesClaim.ts b/src/client/service/nodesClaim.ts index b82731c05..3c165d579 100644 --- a/src/client/service/nodesClaim.ts +++ b/src/client/service/nodesClaim.ts @@ -1,12 +1,13 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { NodeManager } from '../../nodes'; +import type NodeManager from '../../nodes/NodeManager'; import type { NodeId } from '../../nodes/types'; -import type { NotificationsManager } from '../../notifications'; +import type NotificationsManager from '../../notifications/NotificationsManager'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/client/service/nodesFind.ts b/src/client/service/nodesFind.ts index b8cb887db..284e50748 100644 --- a/src/client/service/nodesFind.ts +++ b/src/client/service/nodesFind.ts @@ -1,11 +1,12 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { NodeConnectionManager } from '../../nodes'; +import type NodeConnectionManager from '../../nodes/NodeConnectionManager'; import type { NodeId } from '../../nodes/types'; import type Logger from '@matrixai/logger'; -import { utils as nodesUtils } from '../../nodes'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as nodesUtils from '../../nodes/utils'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; diff --git a/src/client/service/nodesPing.ts b/src/client/service/nodesPing.ts index 2356f2072..449905cc7 100644 --- a/src/client/service/nodesPing.ts +++ b/src/client/service/nodesPing.ts @@ -1,11 +1,12 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { NodeManager } from '../../nodes'; +import type NodeManager from '../../nodes/NodeManager'; import type { NodeId } from '../../nodes/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/client/service/notificationsClear.ts b/src/client/service/notificationsClear.ts index 7d2ba80cc..2fd077c9b 100644 --- a/src/client/service/notificationsClear.ts +++ b/src/client/service/notificationsClear.ts @@ -1,8 +1,8 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { NotificationsManager } from '../../notifications'; +import type NotificationsManager from '../../notifications/NotificationsManager'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function notificationsClear({ diff --git a/src/client/service/notificationsRead.ts b/src/client/service/notificationsRead.ts index f8bccc692..630940764 100644 --- a/src/client/service/notificationsRead.ts +++ b/src/client/service/notificationsRead.ts @@ -1,8 +1,8 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { NotificationsManager } from '../../notifications'; +import type NotificationsManager from '../../notifications/NotificationsManager'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; +import * as grpcUtils from '../../grpc/utils'; import * as notificationsPB from '../../proto/js/polykey/v1/notifications/notifications_pb'; function notificationsRead({ diff --git a/src/client/service/notificationsSend.ts b/src/client/service/notificationsSend.ts index c30512611..4ff96fea6 100644 --- a/src/client/service/notificationsSend.ts +++ b/src/client/service/notificationsSend.ts @@ -1,12 +1,13 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { NotificationsManager } from '../../notifications'; +import type NotificationsManager from '../../notifications/NotificationsManager'; import type { NodeId } from '../../nodes/types'; import type * as notificationsPB from '../../proto/js/polykey/v1/notifications/notifications_pb'; import type Logger from '@matrixai/logger'; -import { utils as grpcUtils } from '../../grpc'; -import { utils as notificationsUtils } from '../../notifications'; -import { validateSync, utils as validationUtils } from '../../validation'; +import * as grpcUtils from '../../grpc/utils'; +import * as notificationsUtils from '../../notifications/utils'; +import { validateSync } from '../../validation'; +import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/client/service/vaultsPermissionGet.ts b/src/client/service/vaultsPermissionGet.ts index 8dd0866c3..1682044ad 100644 --- a/src/client/service/vaultsPermissionGet.ts +++ b/src/client/service/vaultsPermissionGet.ts @@ -1,7 +1,7 @@ +import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; import type { VaultName } from '../../vaults/types'; -import type * as grpc from '@grpc/grpc-js'; import type { VaultActions } from '../../vaults/types'; import type ACL from '../../acl/ACL'; import type { NodeId, NodeIdEncoded } from 'nodes/types'; diff --git a/src/client/utils/utils.ts b/src/client/utils/utils.ts index f922128bb..d49173a6f 100644 --- a/src/client/utils/utils.ts +++ b/src/client/utils/utils.ts @@ -8,8 +8,8 @@ import type Session from '../../sessions/Session'; import type SessionManager from '../../sessions/SessionManager'; import type { SessionToken } from '../../sessions/types'; import type { Authenticate } from '../types'; -import * as grpc from '@grpc/grpc-js'; import * as base64 from 'multiformats/bases/base64'; +import * as grpc from '@grpc/grpc-js'; import * as clientErrors from '../errors'; /** @@ -130,7 +130,7 @@ function decodeAuthToSession( if (auth == null || !auth.startsWith('Bearer ')) { return; } - return auth.substr(7) as SessionToken; + return auth.substring(7) as SessionToken; } export { diff --git a/src/grpc/GRPCClient.ts b/src/grpc/GRPCClient.ts index 22a7c65e5..4e88291a1 100644 --- a/src/grpc/GRPCClient.ts +++ b/src/grpc/GRPCClient.ts @@ -267,6 +267,14 @@ abstract class GRPCClient { ); } + /** + * Gets information about the client + * Useful for error reporting + */ + public getClientInfo() { + return { nodeId: this.nodeId, host: this.host, port: this.port }; + } + /** * Gets the leaf server certificate if the connection is encrypted * Don't use this when using network proxies diff --git a/src/grpc/utils/utils.ts b/src/grpc/utils/utils.ts index 7db50484c..4efb787f3 100644 --- a/src/grpc/utils/utils.ts +++ b/src/grpc/utils/utils.ts @@ -28,11 +28,14 @@ import type { AsyncGeneratorDuplexStreamClient, } from '../types'; import type { CertificatePemChain, PrivateKeyPem } from '../../keys/types'; +import type { Host, Port } from '../../network/types'; +import type { NodeId } from '../../nodes/types'; import { Buffer } from 'buffer'; import { AbstractError } from '@matrixai/errors'; import * as grpc from '@grpc/grpc-js'; import * as grpcErrors from '../errors'; import * as errors from '../../errors'; +import * as nodesUtils from '../../nodes/utils'; import { promisify, promise, never } from '../../utils/utils'; /** @@ -182,7 +185,10 @@ function fromError( * Use this on the receiving side to receive exceptions */ function toError(e: ServiceError): errors.ErrorPolykey { - const errorData = e.metadata.get('error')[0] as string; + const errorData = e.metadata.get('error')[0].toString(); + const nodeId = e.metadata.get('nodeId')[0].toString(); + const host = e.metadata.get('host')[0].toString(); + const port = parseInt(e.metadata.get('port')[0].toString()); // Grpc.status is an enum // this will iterate the enum values then enum keys // they will all be of string type @@ -193,7 +199,14 @@ function toError(e: ServiceError): errors.ErrorPolykey { if (isNaN(parseInt(key)) && e.code === grpc.status[key]) { if (key === 'UNKNOWN' && errorData != null) { const error: Error = JSON.parse(errorData, reviver); - return new errors.ErrorPolykeyRemote(error.message, { cause: error }); + return new errors.ErrorPolykeyRemote(error.message, { + data: { + nodeId, + host, + port, + }, + cause: error, + }); } else { return new grpcErrors.ErrorGRPCClientCall(e.message, { data: { @@ -215,16 +228,13 @@ function toError(e: ServiceError): errors.ErrorPolykey { * serialises other errors */ function replacer(key: string, value: any): any { - if (value instanceof AbstractError) { - // Include the standard properties from an AbstractError + if (value instanceof AggregateError) { + // AggregateError has an `errors` property return { - type: value.name, + type: value.constructor.name, data: { - description: value.description, + errors: value.errors, message: value.message, - timestamp: value.timestamp, - data: value.data, - cause: value.cause, stack: value.stack, }, }; @@ -261,14 +271,16 @@ function sensitiveReplacer(key: string, value: any) { * Error constructors for non-Polykey errors * Allows these errors to be reconstructed from GRPC metadata */ -const otherErrors = { - Error: Error, - EvalError: EvalError, - RangeError: RangeError, - ReferenceError: ReferenceError, - SyntaxError: SyntaxError, - TypeError: TypeError, - URIError: URIError, +const standardErrors = { + Error, + TypeError, + SyntaxError, + ReferenceError, + EvalError, + RangeError, + URIError, + AggregateError, + AbstractError, }; /** @@ -285,34 +297,58 @@ function reviver(key: string, value: any): any { typeof value.type === 'string' && typeof value.data === 'object' ) { - const message = value.data.message ?? ''; - if (value.type in errors) { - const error = new errors[value.type](message, { - timestamp: value.data.timestamp, - data: value.data.data, - cause: value.data.cause, - }); - error.exitCode = value.data.exitCode; - if (value.data.stack) { - error.stack = value.data.stack; - } - return error; - } else if (value.type in otherErrors) { - const error = new otherErrors[value.type](message); - if (value.data.stack) { - error.stack = value.data.stack; + try { + let eClass = errors[value.type]; + if (eClass != null) return eClass.fromJSON(value); + eClass = standardErrors[value.type]; + if (eClass != null) { + let e; + switch (eClass) { + case AbstractError: + return eClass.fromJSON(); + case AggregateError: + if ( + !Array.isArray(value.data.errors) || + typeof value.data.message !== 'string' || + ('stack' in value.data && typeof value.data.stack !== 'string') + ) { + throw new TypeError(`cannot decode JSON to ${value.type}`); + } + e = new eClass(value.data.errors, value.data.message); + e.stack = value.data.stack; + break; + default: + if ( + typeof value.data.message !== 'string' || + ('stack' in value.data && typeof value.data.stack !== 'string') + ) { + throw new TypeError(`Cannot decode JSON to ${value.type}`); + } + e = new eClass(value.data.message); + e.stack = value.data.stack; + break; + } + return e; } - return error; - } else { - const error = new errors.ErrorPolykeyUnknown('', { data: value }); - if (value.data.stack) { - error.stack = value.data.stack; + } catch (e) { + // If `TypeError` which represents decoding failure + // then return value as-is + // Any other exception is a bug + if (!(e instanceof TypeError)) { + throw e; } - return error; } + // Other values are returned as-is + return value; } else if (key === '') { - // The value is not an error - const error = new errors.ErrorPolykeyUnknown('', { data: value }); + // Root key will be '' + // Reaching here means the root JSON value is not a valid exception + // Therefore ErrorPolykeyUnknown is only ever returned at the top-level + const error = new errors.ErrorPolykeyUnknown('Unknown error JSON', { + data: { + json: value, + }, + }); return error; } else if (key === 'timestamp') { // Encode timestamps @@ -334,6 +370,9 @@ function reviver(key: string, value: any): any { */ function promisifyUnaryCall( client: Client, + nodeId: NodeId, + host: Host, + port: Port, f: (...args: any[]) => ClientUnaryCall, ): (...args: any[]) => PromiseUnaryCall { return (...args) => { @@ -345,6 +384,9 @@ function promisifyUnaryCall( const { p: pMeta, resolveP: resolveMetaP } = promise(); const callback = (error: ServiceError, ...values) => { if (error != null) { + error.metadata.set('nodeId', nodesUtils.encodeNodeId(nodeId)); + error.metadata.set('host', host); + error.metadata.set('port', port.toString()); rejectP(toError(error)); return; } @@ -370,12 +412,21 @@ function promisifyUnaryCall( */ function generatorReadable( stream: ClientReadableStream, + nodeId: NodeId, + host: Host, + port: Port, ): AsyncGeneratorReadableStream>; function generatorReadable( stream: ServerReadableStream, + nodeId: NodeId, + host: Host, + port: Port, ): AsyncGeneratorReadableStream>; function generatorReadable( stream: ClientReadableStream | ServerReadableStream, + nodeId: NodeId, + host: Host, + port: Port, ) { const gf = async function* () { try { @@ -397,6 +448,9 @@ function generatorReadable( } } catch (e) { stream.destroy(); + e.metadata.set('nodeId', nodesUtils.encodeNodeId(nodeId)); + e.metadata.set('host', host); + e.metadata.set('port', port.toString()); throw toError(e); } }; @@ -414,6 +468,9 @@ function generatorReadable( */ function promisifyReadableStreamCall( client: grpc.Client, + nodeId: NodeId, + host: Host, + port: Port, f: (...args: any[]) => ClientReadableStream, ): ( ...args: any[] @@ -426,6 +483,9 @@ function promisifyReadableStreamCall( }); const g = generatorReadable( stream, + nodeId, + host, + port, ) as AsyncGeneratorReadableStreamClient>; g.meta = pMeta; return g; @@ -484,6 +544,9 @@ function generatorWritable( */ function promisifyWritableStreamCall( client: grpc.Client, + nodeId: NodeId, + host: Host, + port: Port, f: (...args: any[]) => ClientWritableStream, ): ( ...args: any[] @@ -499,6 +562,9 @@ function promisifyWritableStreamCall( }; const callback = (error, ...values) => { if (error != null) { + error.metadata.set('nodeId', nodesUtils.encodeNodeId(nodeId)); + error.metadata.set('host', host); + error.metadata.set('port', port.toString()); return rejectP(toError(error)); } return resolveP(values.length === 1 ? values[0] : values); @@ -531,17 +597,26 @@ function promisifyWritableStreamCall( */ function generatorDuplex( stream: ClientDuplexStream, + nodeId: NodeId, + host: Host, + port: Port, sensitive: boolean, ): AsyncGeneratorDuplexStream>; function generatorDuplex( stream: ServerDuplexStream, + nodeId: NodeId, + host: Host, + port: Port, sensitive: boolean, ): AsyncGeneratorDuplexStream>; function generatorDuplex( stream: ClientDuplexStream | ServerDuplexStream, + nodeId: NodeId, + host: Host, + port: Port, sensitive: boolean = false, ) { - const gR = generatorReadable(stream as any); + const gR = generatorReadable(stream as any, nodeId, host, port); const gW = generatorWritable(stream as any, sensitive); const gf = async function* () { let vR: any, vW: any; @@ -591,6 +666,9 @@ function generatorDuplex( */ function promisifyDuplexStreamCall( client: grpc.Client, + nodeId: NodeId, + host: Host, + port: Port, f: (...args: any[]) => ClientDuplexStream, ): ( ...args: any[] @@ -607,6 +685,9 @@ function promisifyDuplexStreamCall( }); const g = generatorDuplex( stream, + nodeId, + host, + port, false, ) as AsyncGeneratorDuplexStreamClient< TRead, diff --git a/tests/client/service/agentLockAll.test.ts b/tests/client/service/agentLockAll.test.ts index 9fd74aab4..a024cc05c 100644 --- a/tests/client/service/agentLockAll.test.ts +++ b/tests/client/service/agentLockAll.test.ts @@ -89,6 +89,7 @@ describe('agentLockall', () => { nodeId: keyManager.getNodeId(), host: '127.0.0.1' as Host, port: grpcServer.getPort(), + timeout: 5000, logger, }); }); From 09b83a3f18b7199a3b123ff63285847078b7e5a3 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 18 May 2022 18:26:27 +1000 Subject: [PATCH 038/137] feat: adding transactions to agent service handlers --- src/agent/service/nodesChainDataGet.ts | 7 +- .../service/nodesClosestLocalNodesGet.ts | 12 +- src/agent/service/nodesCrossSignClaim.ts | 3 +- .../service/nodesHolePunchMessageSend.ts | 25 +++-- src/agent/service/notificationsSend.ts | 9 +- src/agent/service/vaultsGitInfoGet.ts | 105 ++++++++++-------- src/agent/service/vaultsGitPackGet.ts | 89 ++++++++------- src/agent/service/vaultsScan.ts | 27 +++-- src/nodes/NodeConnectionManager.ts | 5 +- src/nodes/NodeGraph.ts | 11 +- src/nodes/NodeManager.ts | 9 +- src/vaults/VaultManager.ts | 5 +- tests/agent/service/notificationsSend.test.ts | 1 + 13 files changed, 185 insertions(+), 123 deletions(-) diff --git a/src/agent/service/nodesChainDataGet.ts b/src/agent/service/nodesChainDataGet.ts index f2970228f..492c8ca73 100644 --- a/src/agent/service/nodesChainDataGet.ts +++ b/src/agent/service/nodesChainDataGet.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type Sigchain from '../../sigchain/Sigchain'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type { ClaimIdEncoded } from '../../claims/types'; @@ -11,9 +12,11 @@ import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; */ function nodesChainDataGet({ sigchain, + db, logger, }: { sigchain: Sigchain; + db: DB; logger: Logger; }) { return async ( @@ -22,7 +25,9 @@ function nodesChainDataGet({ ): Promise => { try { const response = new nodesPB.ChainData(); - const chainData = await sigchain.getChainData(); + const chainData = await db.withTransactionF(async (tran) => + sigchain.getChainData(tran), + ); // Iterate through each claim in the chain, and serialize for transport let claimIdEncoded: ClaimIdEncoded; for (claimIdEncoded in chainData) { diff --git a/src/agent/service/nodesClosestLocalNodesGet.ts b/src/agent/service/nodesClosestLocalNodesGet.ts index ee031f478..bd562bbe5 100644 --- a/src/agent/service/nodesClosestLocalNodesGet.ts +++ b/src/agent/service/nodesClosestLocalNodesGet.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type NodeConnectionManager from '../../nodes/NodeConnectionManager'; import type { NodeId } from '../../nodes/types'; import type Logger from '@matrixai/logger'; @@ -15,9 +16,11 @@ import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; */ function nodesClosestLocalNodesGet({ nodeConnectionManager, + db, logger, }: { nodeConnectionManager: NodeConnectionManager; + db: DB; logger: Logger; }) { return async ( @@ -42,8 +45,13 @@ function nodesClosestLocalNodesGet({ }, ); // Get all local nodes that are closest to the target node from the request - const closestNodes = await nodeConnectionManager.getClosestLocalNodes( - nodeId, + const closestNodes = await db.withTransactionF( + async (tran) => + await nodeConnectionManager.getClosestLocalNodes( + nodeId, + undefined, + tran, + ), ); for (const node of closestNodes) { const addressMessage = new nodesPB.Address(); diff --git a/src/agent/service/nodesCrossSignClaim.ts b/src/agent/service/nodesCrossSignClaim.ts index b21ed882c..a24420142 100644 --- a/src/agent/service/nodesCrossSignClaim.ts +++ b/src/agent/service/nodesCrossSignClaim.ts @@ -7,7 +7,6 @@ import type Sigchain from '../../sigchain/Sigchain'; import type KeyManager from '../../keys/KeyManager'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type Logger from '@matrixai/logger'; -import { withF } from '@matrixai/resources'; import * as grpcUtils from '../../grpc/utils'; import * as claimsUtils from '../../claims/utils'; import * as claimsErrors from '../../claims/errors'; @@ -34,7 +33,7 @@ function nodesCrossSignClaim({ ) => { const genClaims = grpcUtils.generatorDuplex(call, true); try { - await withF([db.transaction()], async ([tran]) => { + await db.withTransactionF(async (tran) => { const readStatus = await genClaims.read(); // If nothing to read, end and destroy if (readStatus.done) { diff --git a/src/agent/service/nodesHolePunchMessageSend.ts b/src/agent/service/nodesHolePunchMessageSend.ts index 592d0f482..c1b681054 100644 --- a/src/agent/service/nodesHolePunchMessageSend.ts +++ b/src/agent/service/nodesHolePunchMessageSend.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type NodeManager from '../../nodes/NodeManager'; import type NodeConnectionManager from '../../nodes/NodeConnectionManager'; import type KeyManager from '../../keys/KeyManager'; @@ -16,11 +17,13 @@ function nodesHolePunchMessageSend({ keyManager, nodeManager, nodeConnectionManager, + db, logger, }: { keyManager: KeyManager; nodeManager: NodeManager; nodeConnectionManager: NodeConnectionManager; + db: DB; logger: Logger; }) { return async ( @@ -54,16 +57,18 @@ function nodesHolePunchMessageSend({ // Firstly, check if this node is the desired node // If so, then we want to make this node start sending hole punching packets // back to the source node. - if (keyManager.getNodeId().equals(targetId)) { - const [host, port] = networkUtils.parseAddress( - call.request.getProxyAddress(), - ); - await nodeConnectionManager.holePunchReverse(host, port); - // Otherwise, find if node in table - // If so, ask the nodeManager to relay to the node - } else if (await nodeManager.knowsNode(sourceId)) { - await nodeConnectionManager.relayHolePunchMessage(call.request); - } + await db.withTransactionF(async (tran) => { + if (keyManager.getNodeId().equals(targetId)) { + const [host, port] = networkUtils.parseAddress( + call.request.getProxyAddress(), + ); + await nodeConnectionManager.holePunchReverse(host, port); + // Otherwise, find if node in table + // If so, ask the nodeManager to relay to the node + } else if (await nodeManager.knowsNode(sourceId, tran)) { + await nodeConnectionManager.relayHolePunchMessage(call.request); + } + }); callback(null, response); return; } catch (e) { diff --git a/src/agent/service/notificationsSend.ts b/src/agent/service/notificationsSend.ts index 6baef6f9f..07aaf0933 100644 --- a/src/agent/service/notificationsSend.ts +++ b/src/agent/service/notificationsSend.ts @@ -2,15 +2,18 @@ import type * as grpc from '@grpc/grpc-js'; import type NotificationsManager from '../../notifications/NotificationsManager'; import type * as notificationsPB from '../../proto/js/polykey/v1/notifications/notifications_pb'; import type Logger from '@matrixai/logger'; +import type { DB } from '@matrixai/db'; import * as grpcUtils from '../../grpc/utils'; import * as notificationsUtils from '../../notifications/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function notificationsSend({ notificationsManager, + db, logger, }: { notificationsManager: NotificationsManager; + db: DB; logger: Logger; }) { return async ( @@ -21,10 +24,12 @@ function notificationsSend({ callback: grpc.sendUnaryData, ): Promise => { try { - const response = new utilsPB.EmptyMessage(); const jwt = call.request.getContent(); const notification = await notificationsUtils.verifyAndDecodeNotif(jwt); - await notificationsManager.receiveNotification(notification); + await db.withTransactionF(async (tran) => { + await notificationsManager.receiveNotification(notification, tran); + }); + const response = new utilsPB.EmptyMessage(); callback(null, response); return; } catch (e) { diff --git a/src/agent/service/vaultsGitInfoGet.ts b/src/agent/service/vaultsGitInfoGet.ts index 6f4ae9873..4a9893985 100644 --- a/src/agent/service/vaultsGitInfoGet.ts +++ b/src/agent/service/vaultsGitInfoGet.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type ACL from '../../acl/ACL'; @@ -15,11 +16,13 @@ import * as agentErrors from '../errors'; function vaultsGitInfoGet({ vaultManager, acl, + db, logger, connectionInfoGet, }: { vaultManager: VaultManager; acl: ACL; + db: DB; logger: Logger; connectionInfoGet: ConnectionInfoGet; }) { @@ -35,56 +38,64 @@ function vaultsGitInfoGet({ } let vaultName; const vaultNameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(vaultNameOrId as VaultName); - vaultName = vaultNameOrId; - if (vaultId == null) { - try { - vaultId = validationUtils.parseVaultId(vaultNameOrId); - vaultName = (await vaultManager.getVaultMeta(vaultId))?.vaultName; - } catch (e) { - throw new vaultsErrors.ErrorVaultsVaultUndefined(e.message, { - cause: e, - }); - } - } - // Getting the NodeId from the ReverseProxy connection info - const connectionInfo = connectionInfoGet(call); - // If this is getting run the connection exists - // It SHOULD exist here - if (connectionInfo == null) { - throw new agentErrors.ErrorConnectionInfoMissing(); - } - const nodeId = connectionInfo.remoteNodeId; - const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); - const actionType = validationUtils.parseVaultAction(request.getAction()); - const permissions = await acl.getNodePerm(nodeId); - if (permissions == null) { - throw new vaultsErrors.ErrorVaultsPermissionDenied( - `No permissions found for ${nodeIdEncoded}`, + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + vaultNameOrId as VaultName, + tran, ); - } - const vaultPerms = permissions.vaults[vaultId]; - if (vaultPerms?.[actionType] !== null) { - throw new vaultsErrors.ErrorVaultsPermissionDenied( - `${nodeIdEncoded} does not have permission to ${actionType} from vault ${vaultsUtils.encodeVaultId( - vaultId, - )}`, + vaultName = vaultNameOrId; + if (vaultId == null) { + try { + vaultId = validationUtils.parseVaultId(vaultNameOrId); + vaultName = (await vaultManager.getVaultMeta(vaultId, tran)) + ?.vaultName; + } catch (e) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(e.message, { + cause: e, + }); + } + } + // Getting the NodeId from the ReverseProxy connection info + const connectionInfo = connectionInfoGet(call); + // If this is getting run the connection exists + // It SHOULD exist here + if (connectionInfo == null) { + throw new agentErrors.ErrorConnectionInfoMissing(); + } + const nodeId = connectionInfo.remoteNodeId; + const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); + const actionType = validationUtils.parseVaultAction( + request.getAction(), ); - } - const meta = new grpc.Metadata(); - meta.set('vaultName', vaultName); - meta.set('vaultId', vaultsUtils.encodeVaultId(vaultId)); - genWritable.stream.sendMetadata(meta); - const response = new vaultsPB.PackChunk(); - const responseGen = vaultManager.handleInfoRequest(vaultId); - for await (const byte of responseGen) { - if (byte !== null) { - response.setChunk(byte); - await genWritable.next(response); - } else { - await genWritable.next(null); + const permissions = await acl.getNodePerm(nodeId, tran); + if (permissions == null) { + throw new vaultsErrors.ErrorVaultsPermissionDenied( + `No permissions found for ${nodeIdEncoded}`, + ); } - } + const vaultPerms = permissions.vaults[vaultId]; + if (vaultPerms?.[actionType] !== null) { + throw new vaultsErrors.ErrorVaultsPermissionDenied( + `${nodeIdEncoded} does not have permission to ${actionType} from vault ${vaultsUtils.encodeVaultId( + vaultId, + )}`, + ); + } + const meta = new grpc.Metadata(); + meta.set('vaultName', vaultName); + meta.set('vaultId', vaultsUtils.encodeVaultId(vaultId)); + genWritable.stream.sendMetadata(meta); + const response = new vaultsPB.PackChunk(); + const responseGen = vaultManager.handleInfoRequest(vaultId, tran); + for await (const byte of responseGen) { + if (byte !== null) { + response.setChunk(byte); + await genWritable.next(response); + } else { + await genWritable.next(null); + } + } + }); await genWritable.next(null); } catch (e) { await genWritable.throw(e); diff --git a/src/agent/service/vaultsGitPackGet.ts b/src/agent/service/vaultsGitPackGet.ts index e96398529..988dda47c 100644 --- a/src/agent/service/vaultsGitPackGet.ts +++ b/src/agent/service/vaultsGitPackGet.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type { ConnectionInfoGet } from '../../agent/types'; @@ -16,11 +17,13 @@ import * as agentErrors from '../errors'; function vaultsGitPackGet({ vaultManager, acl, + db, logger, connectionInfoGet, }: { vaultManager: VaultManager; acl: ACL; + db: DB; logger: Logger; connectionInfoGet: ConnectionInfoGet; }) { @@ -48,49 +51,55 @@ function vaultsGitPackGet({ if (vaultNameOrId == null) { throw new grpcErrors.ErrorGRPC('vault-name not in metadata'); } - let vaultId = await vaultManager.getVaultId(vaultNameOrId as VaultName); - vaultId = vaultId ?? vaultsUtils.decodeVaultId(vaultNameOrId); - if (vaultId == null) { - // Throwing permission error to hide information about vaults existence - throw new vaultsErrors.ErrorVaultsPermissionDenied( - `No permissions found for ${nodeIdEncoded}`, + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + vaultNameOrId as VaultName, + tran, ); - } - // Checking permissions - const permissions = await acl.getNodePerm(nodeId); - const vaultPerms = permissions?.vaults[vaultId]; - const actionType = validationUtils.parseVaultAction( - meta.get('vaultAction').pop(), - ); - if (vaultPerms?.[actionType] !== null) { - throw new vaultsErrors.ErrorVaultsPermissionDenied( - `${nodeIdEncoded} does not have permission to ${actionType} from vault ${vaultsUtils.encodeVaultId( - vaultId, - )}`, + vaultId = vaultId ?? vaultsUtils.decodeVaultId(vaultNameOrId); + if (vaultId == null) { + // Throwing permission error to hide information about vaults existence + throw new vaultsErrors.ErrorVaultsPermissionDenied( + `No permissions found for ${nodeIdEncoded}`, + ); + } + // Checking permissions + const permissions = await acl.getNodePerm(nodeId, tran); + const vaultPerms = permissions?.vaults[vaultId]; + const actionType = validationUtils.parseVaultAction( + meta.get('vaultAction').pop(), ); - } - const response = new vaultsPB.PackChunk(); - const [sideBand, progressStream] = await vaultManager.handlePackRequest( - vaultId, - Buffer.from(body), - ); - response.setChunk(Buffer.from('0008NAK\n')); - await genDuplex.write(response); - const responseBuffers: Uint8Array[] = []; - await new Promise((resolve, reject) => { - sideBand.on('data', async (data: Uint8Array) => { - responseBuffers.push(data); - }); - sideBand.on('end', async () => { - response.setChunk(Buffer.concat(responseBuffers)); - await genDuplex.write(response); - resolve(); - }); - sideBand.on('error', (err) => { - reject(err); + if (vaultPerms?.[actionType] !== null) { + throw new vaultsErrors.ErrorVaultsPermissionDenied( + `${nodeIdEncoded} does not have permission to ${actionType} from vault ${vaultsUtils.encodeVaultId( + vaultId, + )}`, + ); + } + const response = new vaultsPB.PackChunk(); + const [sideBand, progressStream] = await vaultManager.handlePackRequest( + vaultId, + Buffer.from(body), + tran, + ); + response.setChunk(Buffer.from('0008NAK\n')); + await genDuplex.write(response); + const responseBuffers: Uint8Array[] = []; + await new Promise((resolve, reject) => { + sideBand.on('data', async (data: Uint8Array) => { + responseBuffers.push(data); + }); + sideBand.on('end', async () => { + response.setChunk(Buffer.concat(responseBuffers)); + await genDuplex.write(response); + resolve(); + }); + sideBand.on('error', (err) => { + reject(err); + }); + progressStream.write(Buffer.from('0014progress is at 50%\n')); + progressStream.end(); }); - progressStream.write(Buffer.from('0014progress is at 50%\n')); - progressStream.end(); }); await genDuplex.next(null); } catch (e) { diff --git a/src/agent/service/vaultsScan.ts b/src/agent/service/vaultsScan.ts index bd7cb004b..2fd04d5e5 100644 --- a/src/agent/service/vaultsScan.ts +++ b/src/agent/service/vaultsScan.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type VaultManager from '../../vaults/VaultManager'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type { ConnectionInfoGet } from '../../agent/types'; @@ -12,10 +13,12 @@ function vaultsScan({ vaultManager, logger, connectionInfoGet, + db, }: { vaultManager: VaultManager; logger: Logger; connectionInfoGet: ConnectionInfoGet; + db: DB; }) { return async ( call: grpc.ServerWritableStream, @@ -31,17 +34,19 @@ function vaultsScan({ } const nodeId = connectionInfo.remoteNodeId; try { - const listResponse = vaultManager.handleScanVaults(nodeId); - for await (const { - vaultId, - vaultName, - vaultPermissions, - } of listResponse) { - listMessage.setVaultId(vaultsUtils.encodeVaultId(vaultId)); - listMessage.setVaultName(vaultName); - listMessage.setVaultPermissionsList(vaultPermissions); - await genWritable.next(listMessage); - } + await db.withTransactionF(async (tran) => { + const listResponse = vaultManager.handleScanVaults(nodeId, tran); + for await (const { + vaultId, + vaultName, + vaultPermissions, + } of listResponse) { + listMessage.setVaultId(vaultsUtils.encodeVaultId(vaultId)); + listMessage.setVaultName(vaultName); + listMessage.setVaultPermissionsList(vaultPermissions); + await genWritable.next(listMessage); + } + }); await genWritable.next(null); } catch (e) { await genWritable.throw(e); diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 23572a0c7..812b18832 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -11,6 +11,7 @@ import type { SeedNodes, NodeIdString, } from './types'; +import type { DBTransaction } from '@matrixai/db'; import Logger from '@matrixai/logger'; import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; import { IdInternal } from '@matrixai/id'; @@ -448,6 +449,7 @@ class NodeConnectionManager { * @param targetNodeId the node ID to find other nodes closest to it * @param numClosest the number of closest nodes to return (by default, returns * according to the maximum number of nodes per bucket) + * @param tran * @returns a mapping containing exactly k nodeIds -> nodeAddresses (unless the * current node has less than k nodes in all of its buckets, in which case it * returns all nodes it has knowledge of) @@ -456,9 +458,10 @@ class NodeConnectionManager { public async getClosestLocalNodes( targetNodeId: NodeId, numClosest: number = this.nodeGraph.maxNodesPerBucket, + tran?: DBTransaction, ): Promise> { // Retrieve all nodes from buckets in database - const buckets = await this.nodeGraph.getAllBuckets(); + const buckets = await this.nodeGraph.getAllBuckets(tran); // Iterate over all of the nodes in each bucket const distanceToNodes: Array = []; buckets.forEach(function (bucket) { diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index 7cd35ee13..ddf2ff7b3 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -110,6 +110,7 @@ class NodeGraph { /** * Retrieves the node Address * @param nodeId node ID of the target node + * @param tran * @returns Node Address of the target node */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) @@ -136,16 +137,21 @@ class NodeGraph { * Determines whether a node ID -> node address mapping exists in this node's * node table. * @param targetNodeId the node ID of the node to find + * @param tran * @returns true if the node exists in the table, false otherwise */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async knowsNode(targetNodeId: NodeId): Promise { - return !!(await this.getNode(targetNodeId)); + public async knowsNode( + targetNodeId: NodeId, + tran?: DBTransaction, + ): Promise { + return !!(await this.getNode(targetNodeId, tran)); } /** * Returns the specified bucket if it exists * @param bucketIndex + * @param tran */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async getBucket( @@ -255,6 +261,7 @@ class NodeGraph { /** * Removes a node from the bucket database * @param nodeId + * @param tran */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async unsetNode(nodeId: NodeId, tran?: DBTransaction): Promise { diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 61820d706..fe57b8001 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -318,11 +318,14 @@ class NodeManager { /** * Determines whether a node ID -> node address mapping exists in the NodeGraph * @param targetNodeId the node ID of the node to find + * @param tran * @returns true if the node exists in the table, false otherwise */ - public async knowsNode(targetNodeId: NodeId): Promise { - // FIXME: use tran - return await this.nodeGraph.knowsNode(targetNodeId); + public async knowsNode( + targetNodeId: NodeId, + tran?: DBTransaction, + ): Promise { + return await this.nodeGraph.knowsNode(targetNodeId, tran); } /** diff --git a/src/vaults/VaultManager.ts b/src/vaults/VaultManager.ts index beb8a525a..2f8fe364f 100644 --- a/src/vaults/VaultManager.ts +++ b/src/vaults/VaultManager.ts @@ -864,9 +864,10 @@ class VaultManager { vaultPermissions: VaultAction[]; }> { if (tran == null) { - const fml = (tran) => this.handleScanVaults(nodeId, tran); + // Lambda to maintain `this` context + const handleScanVaults = (tran) => this.handleScanVaults(nodeId, tran); return yield* this.db.withTransactionG(async function* (tran) { - return yield* fml(tran); + return yield* handleScanVaults(tran); }); } diff --git a/tests/agent/service/notificationsSend.test.ts b/tests/agent/service/notificationsSend.test.ts index 5d51289e0..c0b79e91c 100644 --- a/tests/agent/service/notificationsSend.test.ts +++ b/tests/agent/service/notificationsSend.test.ts @@ -139,6 +139,7 @@ describe('notificationsSend', () => { notificationsSend: notificationsSend({ notificationsManager, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); From 18a4d77ab0a9fcf60ba5a4d76e439638e8c995de Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Thu, 19 May 2022 11:05:04 +1000 Subject: [PATCH 039/137] fix: toError deserialization There was a bug with the `fromJSON` method where it couldn't deserialise an error with an undefined cause (because this is removed by the replacer). --- src/ErrorPolykey.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ErrorPolykey.ts b/src/ErrorPolykey.ts index 4ee452242..b7286859e 100644 --- a/src/ErrorPolykey.ts +++ b/src/ErrorPolykey.ts @@ -17,8 +17,7 @@ class ErrorPolykey extends AbstractError { typeof json.data.message !== 'string' || isNaN(Date.parse(json.data.timestamp)) || typeof json.data.data !== 'object' || - typeof json.data.exitCode !== 'string' || - !('cause' in json.data) || + typeof json.data.exitCode !== 'number' || ('stack' in json.data && typeof json.data.stack !== 'string') ) { throw new TypeError(`Cannot decode JSON to ${this.name}`); From 97beee94a2c534060a02f9d26d97d8cb3aa2f370 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Thu, 19 May 2022 16:05:24 +1000 Subject: [PATCH 040/137] feat: adding metadata of sending node to errors --- src/agent/GRPCClientAgent.ts | 80 ++-- src/agent/service/nodesCrossSignClaim.ts | 3 +- src/agent/service/vaultsGitPackGet.ts | 6 +- src/client/GRPCClientClient.ts | 512 ++++++++++++++--------- src/grpc/utils/utils.ts | 88 ++-- 5 files changed, 408 insertions(+), 281 deletions(-) diff --git a/src/agent/GRPCClientAgent.ts b/src/agent/GRPCClientAgent.ts index dd68e2db5..bfc1c4d65 100644 --- a/src/agent/GRPCClientAgent.ts +++ b/src/agent/GRPCClientAgent.ts @@ -79,9 +79,11 @@ class GRPCClientAgent extends GRPCClient { public echo(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.echo, )(...args); } @@ -95,9 +97,11 @@ class GRPCClientAgent extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsGitInfoGet, )(...args); } @@ -112,9 +116,11 @@ class GRPCClientAgent extends GRPCClient { > { return grpcUtils.promisifyDuplexStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsGitPackGet, )(...args); } @@ -128,9 +134,11 @@ class GRPCClientAgent extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsScan, )(...args); } @@ -139,9 +147,11 @@ class GRPCClientAgent extends GRPCClient { public nodesClosestLocalNodesGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.nodesClosestLocalNodesGet, )(...args); } @@ -150,9 +160,11 @@ class GRPCClientAgent extends GRPCClient { public nodesClaimsGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.nodesClaimsGet, )(...args); } @@ -161,9 +173,11 @@ class GRPCClientAgent extends GRPCClient { public nodesChainDataGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.nodesChainDataGet, )(...args); } @@ -172,9 +186,11 @@ class GRPCClientAgent extends GRPCClient { public nodesHolePunchMessageSend(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.nodesHolePunchMessageSend, )(...args); } @@ -183,9 +199,11 @@ class GRPCClientAgent extends GRPCClient { public notificationsSend(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.notificationsSend, )(...args); } @@ -203,9 +221,11 @@ class GRPCClientAgent extends GRPCClient { nodesPB.CrossSign >( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.nodesCrossSignClaim, )(...args); } diff --git a/src/agent/service/nodesCrossSignClaim.ts b/src/agent/service/nodesCrossSignClaim.ts index a24420142..f0a3e2a9a 100644 --- a/src/agent/service/nodesCrossSignClaim.ts +++ b/src/agent/service/nodesCrossSignClaim.ts @@ -31,7 +31,8 @@ function nodesCrossSignClaim({ return async ( call: grpc.ServerDuplexStream, ) => { - const genClaims = grpcUtils.generatorDuplex(call, true); + const nodeId = keyManager.getNodeId(); + const genClaims = grpcUtils.generatorDuplex(call, { nodeId }, true); try { await db.withTransactionF(async (tran) => { const readStatus = await genClaims.read(); diff --git a/src/agent/service/vaultsGitPackGet.ts b/src/agent/service/vaultsGitPackGet.ts index 988dda47c..8d9561512 100644 --- a/src/agent/service/vaultsGitPackGet.ts +++ b/src/agent/service/vaultsGitPackGet.ts @@ -4,6 +4,7 @@ import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type { ConnectionInfoGet } from '../../agent/types'; import type ACL from '../../acl/ACL'; +import type KeyManager from '../../keys/KeyManager'; import type Logger from '@matrixai/logger'; import * as nodesUtils from '../../nodes/utils'; import * as grpcErrors from '../../grpc/errors'; @@ -18,19 +19,22 @@ function vaultsGitPackGet({ vaultManager, acl, db, + keyManager, logger, connectionInfoGet, }: { vaultManager: VaultManager; acl: ACL; db: DB; + keyManager: KeyManager; logger: Logger; connectionInfoGet: ConnectionInfoGet; }) { return async ( call: grpc.ServerDuplexStream, ): Promise => { - const genDuplex = grpcUtils.generatorDuplex(call, true); + const nodeId = keyManager.getNodeId(); + const genDuplex = grpcUtils.generatorDuplex(call, { nodeId }, true); try { const clientBodyBuffers: Uint8Array[] = []; const clientRequest = (await genDuplex.read()).value; diff --git a/src/client/GRPCClientClient.ts b/src/client/GRPCClientClient.ts index 87ff45b6c..e866ec475 100644 --- a/src/client/GRPCClientClient.ts +++ b/src/client/GRPCClientClient.ts @@ -91,9 +91,11 @@ class GRPCClientClient extends GRPCClient { public agentStatus(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.agentStatus, )(...args); } @@ -102,9 +104,11 @@ class GRPCClientClient extends GRPCClient { public agentStop(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.agentStop, )(...args); } @@ -113,9 +117,11 @@ class GRPCClientClient extends GRPCClient { public agentUnlock(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.agentUnlock, )(...args); } @@ -124,9 +130,11 @@ class GRPCClientClient extends GRPCClient { public agentLockAll(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.agentLockAll, )(...args); } @@ -140,9 +148,11 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsList, )(...args); } @@ -151,9 +161,11 @@ class GRPCClientClient extends GRPCClient { public vaultsCreate(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsCreate, )(...args); } @@ -162,9 +174,11 @@ class GRPCClientClient extends GRPCClient { public vaultsRename(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsRename, )(...args); } @@ -173,9 +187,11 @@ class GRPCClientClient extends GRPCClient { public vaultsDelete(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsDelete, )(...args); } @@ -184,9 +200,11 @@ class GRPCClientClient extends GRPCClient { public vaultsClone(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsClone, )(...args); } @@ -195,9 +213,11 @@ class GRPCClientClient extends GRPCClient { public vaultsPull(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsPull, )(...args); } @@ -211,9 +231,11 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsScan, )(...args); } @@ -222,9 +244,11 @@ class GRPCClientClient extends GRPCClient { public vaultsPermissionGet(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsPermissionGet, )(...args); } @@ -233,9 +257,11 @@ class GRPCClientClient extends GRPCClient { public vaultsPermissionSet(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsPermissionSet, )(...args); } @@ -244,9 +270,11 @@ class GRPCClientClient extends GRPCClient { public vaultsPermissionUnset(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsPermissionUnset, )(...args); } @@ -260,9 +288,11 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsSecretsList, )(...args); } @@ -271,9 +301,11 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsMkdir(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsSecretsMkdir, )(...args); } @@ -282,9 +314,11 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsDelete(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsSecretsDelete, )(...args); } @@ -293,9 +327,11 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsEdit(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsSecretsEdit, )(...args); } @@ -304,9 +340,11 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsSecretsGet, )(...args); } @@ -315,9 +353,11 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsStat(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsSecretsStat, )(...args); } @@ -326,9 +366,11 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsRename(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsSecretsRename, )(...args); } @@ -337,9 +379,11 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsNew(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsSecretsNew, )(...args); } @@ -348,9 +392,11 @@ class GRPCClientClient extends GRPCClient { public vaultsSecretsNewDir(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsSecretsNewDir, )(...args); } @@ -359,9 +405,11 @@ class GRPCClientClient extends GRPCClient { public vaultsVersion(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsVersion, )(...args); } @@ -375,9 +423,11 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.vaultsLog, )(...args); } @@ -386,9 +436,11 @@ class GRPCClientClient extends GRPCClient { public keysKeyPairRoot(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.keysKeyPairRoot, )(...args); } @@ -397,9 +449,11 @@ class GRPCClientClient extends GRPCClient { public keysKeyPairReset(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.keysKeyPairReset, )(...args); } @@ -408,9 +462,11 @@ class GRPCClientClient extends GRPCClient { public keysKeyPairRenew(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.keysKeyPairRenew, )(...args); } @@ -419,9 +475,11 @@ class GRPCClientClient extends GRPCClient { public keysEncrypt(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.keysEncrypt, )(...args); } @@ -430,9 +488,11 @@ class GRPCClientClient extends GRPCClient { public keysDecrypt(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.keysDecrypt, )(...args); } @@ -441,9 +501,11 @@ class GRPCClientClient extends GRPCClient { public keysSign(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.keysSign, )(...args); } @@ -452,9 +514,11 @@ class GRPCClientClient extends GRPCClient { public keysVerify(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.keysVerify, )(...args); } @@ -463,9 +527,11 @@ class GRPCClientClient extends GRPCClient { public keysPasswordChange(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.keysPasswordChange, )(...args); } @@ -474,9 +540,11 @@ class GRPCClientClient extends GRPCClient { public keysCertsGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.keysCertsGet, )(...args); } @@ -490,9 +558,11 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.keysCertsChainGet, )(...args); } @@ -506,9 +576,11 @@ class GRPCClientClient extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsGestaltList, )(...args); } @@ -517,9 +589,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsGestaltGetByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsGestaltGetByIdentity, )(...args); } @@ -528,9 +602,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsGestaltGetByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsGestaltGetByNode, )(...args); } @@ -539,9 +615,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsDiscoveryByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsDiscoveryByNode, )(...args); } @@ -550,9 +628,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsDiscoveryByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsDiscoveryByIdentity, )(...args); } @@ -561,9 +641,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsGetByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsActionsGetByNode, )(...args); } @@ -572,9 +654,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsGetByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsActionsGetByIdentity, )(...args); } @@ -583,9 +667,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsSetByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsActionsSetByNode, )(...args); } @@ -594,9 +680,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsSetByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsActionsSetByIdentity, )(...args); } @@ -605,9 +693,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsUnsetByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsActionsUnsetByNode, )(...args); } @@ -616,9 +706,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsActionsUnsetByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsActionsUnsetByIdentity, )(...args); } @@ -627,9 +719,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsGestaltTrustByNode(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsGestaltTrustByNode, )(...args); } @@ -638,9 +732,11 @@ class GRPCClientClient extends GRPCClient { public gestaltsGestaltTrustByIdentity(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.gestaltsGestaltTrustByIdentity, )(...args); } @@ -649,9 +745,11 @@ class GRPCClientClient extends GRPCClient { public identitiesTokenPut(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.identitiesTokenPut, )(...args); } @@ -660,9 +758,11 @@ class GRPCClientClient extends GRPCClient { public identitiesTokenGet(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.identitiesTokenGet, )(...args); } @@ -671,9 +771,11 @@ class GRPCClientClient extends GRPCClient { public identitiesTokenDelete(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.identitiesTokenDelete, )(...args); } @@ -682,9 +784,11 @@ class GRPCClientClient extends GRPCClient { public identitiesProvidersList(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.identitiesProvidersList, )(...args); } @@ -693,9 +797,11 @@ class GRPCClientClient extends GRPCClient { public nodesAdd(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.nodesAdd, )(...args); } @@ -704,9 +810,11 @@ class GRPCClientClient extends GRPCClient { public nodesPing(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.nodesPing, )(...args); } @@ -715,9 +823,11 @@ class GRPCClientClient extends GRPCClient { public nodesClaim(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.nodesClaim, )(...args); } @@ -726,9 +836,11 @@ class GRPCClientClient extends GRPCClient { public nodesFind(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.nodesFind, )(...args); } @@ -737,9 +849,11 @@ class GRPCClientClient extends GRPCClient { public identitiesAuthenticate(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.identitiesAuthenticate, )(...args); } @@ -748,9 +862,11 @@ class GRPCClientClient extends GRPCClient { public identitiesInfoConnectedGet(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.identitiesInfoConnectedGet, )(...args); } @@ -759,9 +875,11 @@ class GRPCClientClient extends GRPCClient { public identitiesInfoGet(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.identitiesInfoGet, )(...args); } @@ -770,9 +888,11 @@ class GRPCClientClient extends GRPCClient { public identitiesClaim(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.identitiesClaim, )(...args); } @@ -781,9 +901,11 @@ class GRPCClientClient extends GRPCClient { public identitiesAuthenticatedGet(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.identitiesAuthenticatedGet, )(...args); } @@ -792,9 +914,11 @@ class GRPCClientClient extends GRPCClient { public notificationsSend(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.notificationsSend, )(...args); } @@ -803,9 +927,11 @@ class GRPCClientClient extends GRPCClient { public notificationsRead(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.notificationsRead, )(...args); } @@ -814,9 +940,11 @@ class GRPCClientClient extends GRPCClient { public notificationsClear(...args) { return grpcUtils.promisifyUnaryCall( this.client, - this.nodeId, - this.host, - this.port, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + }, this.client.notificationsClear, )(...args); } diff --git a/src/grpc/utils/utils.ts b/src/grpc/utils/utils.ts index 4efb787f3..4b7335fd5 100644 --- a/src/grpc/utils/utils.ts +++ b/src/grpc/utils/utils.ts @@ -28,14 +28,13 @@ import type { AsyncGeneratorDuplexStreamClient, } from '../types'; import type { CertificatePemChain, PrivateKeyPem } from '../../keys/types'; -import type { Host, Port } from '../../network/types'; -import type { NodeId } from '../../nodes/types'; +import type { POJO } from '../../types'; import { Buffer } from 'buffer'; import { AbstractError } from '@matrixai/errors'; import * as grpc from '@grpc/grpc-js'; import * as grpcErrors from '../errors'; import * as errors from '../../errors'; -import * as nodesUtils from '../../nodes/utils'; +import * as networkUtils from '../../network/utils'; import { promisify, promise, never } from '../../utils/utils'; /** @@ -186,9 +185,7 @@ function fromError( */ function toError(e: ServiceError): errors.ErrorPolykey { const errorData = e.metadata.get('error')[0].toString(); - const nodeId = e.metadata.get('nodeId')[0].toString(); - const host = e.metadata.get('host')[0].toString(); - const port = parseInt(e.metadata.get('port')[0].toString()); + const connInfo = e.metadata.get('metadata')[0].toString(); // Grpc.status is an enum // this will iterate the enum values then enum keys // they will all be of string type @@ -200,11 +197,7 @@ function toError(e: ServiceError): errors.ErrorPolykey { if (key === 'UNKNOWN' && errorData != null) { const error: Error = JSON.parse(errorData, reviver); return new errors.ErrorPolykeyRemote(error.message, { - data: { - nodeId, - host, - port, - }, + data: JSON.parse(connInfo), cause: error, }); } else { @@ -370,9 +363,7 @@ function reviver(key: string, value: any): any { */ function promisifyUnaryCall( client: Client, - nodeId: NodeId, - host: Host, - port: Port, + metadata: POJO, f: (...args: any[]) => ClientUnaryCall, ): (...args: any[]) => PromiseUnaryCall { return (...args) => { @@ -384,9 +375,7 @@ function promisifyUnaryCall( const { p: pMeta, resolveP: resolveMetaP } = promise(); const callback = (error: ServiceError, ...values) => { if (error != null) { - error.metadata.set('nodeId', nodesUtils.encodeNodeId(nodeId)); - error.metadata.set('host', host); - error.metadata.set('port', port.toString()); + error.metadata.set('metadata', JSON.stringify(metadata)); rejectP(toError(error)); return; } @@ -412,22 +401,27 @@ function promisifyUnaryCall( */ function generatorReadable( stream: ClientReadableStream, - nodeId: NodeId, - host: Host, - port: Port, + metadata: POJO, ): AsyncGeneratorReadableStream>; function generatorReadable( stream: ServerReadableStream, - nodeId: NodeId, - host: Host, - port: Port, + metadata: POJO, ): AsyncGeneratorReadableStream>; function generatorReadable( stream: ClientReadableStream | ServerReadableStream, - nodeId: NodeId, - host: Host, - port: Port, + metadata: POJO, ) { + const peerAddress = stream + .getPeer() + .match( + /([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}:\d{1,5}|(\d{1,3}\.){3}\d{1,3}:\d{1,5}/, + ); + if (!('host' in metadata) && peerAddress != null) { + metadata.host = networkUtils.parseAddress(peerAddress[0])[0]; + } + if (!('port' in metadata) && peerAddress != null) { + metadata.port = networkUtils.parseAddress(peerAddress[0])[1]; + } const gf = async function* () { try { let vR = yield; @@ -448,9 +442,7 @@ function generatorReadable( } } catch (e) { stream.destroy(); - e.metadata.set('nodeId', nodesUtils.encodeNodeId(nodeId)); - e.metadata.set('host', host); - e.metadata.set('port', port.toString()); + e.metadata.set('metadata', JSON.stringify(metadata)); throw toError(e); } }; @@ -468,9 +460,7 @@ function generatorReadable( */ function promisifyReadableStreamCall( client: grpc.Client, - nodeId: NodeId, - host: Host, - port: Port, + metadata: POJO, f: (...args: any[]) => ClientReadableStream, ): ( ...args: any[] @@ -483,9 +473,7 @@ function promisifyReadableStreamCall( }); const g = generatorReadable( stream, - nodeId, - host, - port, + metadata, ) as AsyncGeneratorReadableStreamClient>; g.meta = pMeta; return g; @@ -544,9 +532,7 @@ function generatorWritable( */ function promisifyWritableStreamCall( client: grpc.Client, - nodeId: NodeId, - host: Host, - port: Port, + metadata: POJO, f: (...args: any[]) => ClientWritableStream, ): ( ...args: any[] @@ -562,9 +548,7 @@ function promisifyWritableStreamCall( }; const callback = (error, ...values) => { if (error != null) { - error.metadata.set('nodeId', nodesUtils.encodeNodeId(nodeId)); - error.metadata.set('host', host); - error.metadata.set('port', port.toString()); + error.metadata.set('metadata', JSON.stringify(metadata)); return rejectP(toError(error)); } return resolveP(values.length === 1 ? values[0] : values); @@ -597,26 +581,20 @@ function promisifyWritableStreamCall( */ function generatorDuplex( stream: ClientDuplexStream, - nodeId: NodeId, - host: Host, - port: Port, + metadata: POJO, sensitive: boolean, ): AsyncGeneratorDuplexStream>; function generatorDuplex( stream: ServerDuplexStream, - nodeId: NodeId, - host: Host, - port: Port, + metadata: POJO, sensitive: boolean, ): AsyncGeneratorDuplexStream>; function generatorDuplex( stream: ClientDuplexStream | ServerDuplexStream, - nodeId: NodeId, - host: Host, - port: Port, + metadata: POJO, sensitive: boolean = false, ) { - const gR = generatorReadable(stream as any, nodeId, host, port); + const gR = generatorReadable(stream as any, metadata); const gW = generatorWritable(stream as any, sensitive); const gf = async function* () { let vR: any, vW: any; @@ -666,9 +644,7 @@ function generatorDuplex( */ function promisifyDuplexStreamCall( client: grpc.Client, - nodeId: NodeId, - host: Host, - port: Port, + metadata: POJO, f: (...args: any[]) => ClientDuplexStream, ): ( ...args: any[] @@ -685,9 +661,7 @@ function promisifyDuplexStreamCall( }); const g = generatorDuplex( stream, - nodeId, - host, - port, + metadata, false, ) as AsyncGeneratorDuplexStreamClient< TRead, From fbf13a0d8099c05a80b9488ea2855cb311490999 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 19 May 2022 17:33:34 +1000 Subject: [PATCH 041/137] feat: adding transactions to client service handlers --- src/bin/utils/utils.ts | 26 ++++++-- src/client/service/agentLockAll.ts | 7 +- .../service/gestaltsActionsGetByIdentity.ts | 3 + .../service/gestaltsActionsGetByNode.ts | 7 +- .../service/gestaltsActionsSetByIdentity.ts | 14 ++-- .../service/gestaltsActionsSetByNode.ts | 7 +- .../service/gestaltsActionsUnsetByIdentity.ts | 14 ++-- .../service/gestaltsActionsUnsetByNode.ts | 7 +- .../service/gestaltsGestaltGetByIdentity.ts | 8 ++- .../service/gestaltsGestaltGetByNode.ts | 7 +- src/client/service/gestaltsGestaltList.ts | 7 +- .../service/gestaltsGestaltTrustByIdentity.ts | 47 ++++++++------ .../service/gestaltsGestaltTrustByNode.ts | 30 +++++---- src/client/service/identitiesClaim.ts | 20 ++++-- src/client/service/identitiesTokenDelete.ts | 7 +- src/client/service/identitiesTokenGet.ts | 7 +- src/client/service/identitiesTokenPut.ts | 16 ++++- src/client/service/nodesAdd.ts | 17 +++-- src/client/service/nodesClaim.ts | 36 +++++----- src/client/service/notificationsClear.ts | 7 +- src/client/service/notificationsRead.ts | 16 +++-- src/client/service/vaultsClone.ts | 7 +- src/client/service/vaultsCreate.ts | 7 +- src/client/service/vaultsDelete.ts | 14 +++- src/client/service/vaultsList.ts | 10 +-- src/client/service/vaultsLog.ts | 28 +++++--- src/client/service/vaultsPermissionGet.ts | 19 ++++-- src/client/service/vaultsPermissionSet.ts | 60 +++++++++-------- src/client/service/vaultsPermissionUnset.ts | 65 ++++++++++--------- src/client/service/vaultsPull.ts | 53 ++++++++------- src/client/service/vaultsRename.ts | 18 +++-- src/client/service/vaultsSecretsDelete.ts | 22 +++++-- src/client/service/vaultsSecretsEdit.ts | 24 +++++-- src/client/service/vaultsSecretsGet.ts | 29 ++++++--- src/client/service/vaultsSecretsList.ts | 25 ++++--- src/client/service/vaultsSecretsMkdir.ts | 24 +++++-- src/client/service/vaultsSecretsNew.ts | 24 +++++-- src/client/service/vaultsSecretsNewDir.ts | 22 +++++-- src/client/service/vaultsSecretsRename.ts | 24 +++++-- src/client/service/vaultsSecretsStat.ts | 24 +++++-- src/client/service/vaultsVersion.ts | 44 ++++++++----- src/nodes/NodeManager.ts | 36 +++++----- tests/client/rpcVaults.test.ts | 5 ++ ...staltsActionsSetUnsetGetByIdentity.test.ts | 2 + .../gestaltsActionsSetUnsetGetByNode.test.ts | 3 + .../gestaltsGestaltGetByIdentity.test.ts | 1 + .../service/gestaltsGestaltGetByNode.test.ts | 1 + .../service/gestaltsGestaltList.test.ts | 1 + .../gestaltsGestaltTrustByIdentity.test.ts | 1 + .../gestaltsGestaltTrustByNode.test.ts | 1 + tests/client/service/identitiesClaim.test.ts | 1 + .../identitiesTokenPutDeleteGet.test.ts | 3 + tests/client/service/nodesAdd.test.ts | 1 + tests/client/service/nodesClaim.test.ts | 1 + .../client/service/notificationsClear.test.ts | 1 + .../client/service/notificationsRead.test.ts | 1 + 56 files changed, 623 insertions(+), 289 deletions(-) diff --git a/src/bin/utils/utils.ts b/src/bin/utils/utils.ts index c902337e8..5477228a9 100644 --- a/src/bin/utils/utils.ts +++ b/src/bin/utils/utils.ts @@ -6,6 +6,7 @@ import * as binProcessors from './processors'; import * as binErrors from '../errors'; import * as clientUtils from '../../client/utils'; import * as clientErrors from '../../client/errors'; +import * as errors from '../../errors'; /** * Convert verbosity to LogLevel @@ -122,9 +123,10 @@ async function retryAuthentication( throw e; } // If it is exception is not missing or denied, then throw the exception + const [cause] = remoteErrorCause(e); if ( - !(e instanceof clientErrors.ErrorClientAuthMissing) && - !(e instanceof clientErrors.ErrorClientAuthDenied) + !(cause instanceof clientErrors.ErrorClientAuthMissing) && + !(cause instanceof clientErrors.ErrorClientAuthDenied) ) { throw e; } @@ -141,14 +143,30 @@ async function retryAuthentication( try { return await f(meta); } catch (e) { + const [cause] = remoteErrorCause(e); // The auth cannot be missing, so when it is denied do we retry - if (!(e instanceof clientErrors.ErrorClientAuthDenied)) { + if (!(cause instanceof clientErrors.ErrorClientAuthDenied)) { throw e; } } } } -export { verboseToLogLevel, outputFormatter, retryAuthentication }; +function remoteErrorCause(e: any): [any, number] { + let errorCause = e; + let depth = 0; + while (e instanceof errors.ErrorPolykeyRemote) { + errorCause = e.cause; + depth++; + } + return [errorCause, depth]; +} + +export { + verboseToLogLevel, + outputFormatter, + retryAuthentication, + remoteErrorCause, +}; export type { OutputObject }; diff --git a/src/client/service/agentLockAll.ts b/src/client/service/agentLockAll.ts index 02caef2c1..f1d4c4d03 100644 --- a/src/client/service/agentLockAll.ts +++ b/src/client/service/agentLockAll.ts @@ -1,5 +1,5 @@ -import type { DB } from '@matrixai/db'; import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { SessionManager } from '../../sessions'; import type Logger from '@matrixai/logger'; @@ -26,9 +26,8 @@ function agentLockAll({ const response = new utilsPB.EmptyMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - await withF( - [db.transaction()], - async ([tran]) => await sessionManager.resetKey(tran), + await db.withTransactionF( + async (tran) => await sessionManager.resetKey(tran), ); callback(null, response); return; diff --git a/src/client/service/gestaltsActionsGetByIdentity.ts b/src/client/service/gestaltsActionsGetByIdentity.ts index db6faa41e..14da28205 100644 --- a/src/client/service/gestaltsActionsGetByIdentity.ts +++ b/src/client/service/gestaltsActionsGetByIdentity.ts @@ -1,5 +1,6 @@ import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { IdentityId, ProviderId } from '../../identities/types'; @@ -14,10 +15,12 @@ import * as permissionsPB from '../../proto/js/polykey/v1/permissions/permission function gestaltsActionsGetByIdentity({ authenticate, gestaltGraph, + db, logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + db: DB; logger: Logger; }) { return async ( diff --git a/src/client/service/gestaltsActionsGetByNode.ts b/src/client/service/gestaltsActionsGetByNode.ts index 162b6be9f..77ad8360a 100644 --- a/src/client/service/gestaltsActionsGetByNode.ts +++ b/src/client/service/gestaltsActionsGetByNode.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { NodeId } from '../../nodes/types'; import type GestaltGraph from '../../gestalts/GestaltGraph'; @@ -13,10 +14,12 @@ import * as permissionsPB from '../../proto/js/polykey/v1/permissions/permission function gestaltsActionsGetByNode({ authenticate, gestaltGraph, + db, logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + db: DB; logger: Logger; }) { return async ( @@ -38,7 +41,9 @@ function gestaltsActionsGetByNode({ nodeId: call.request.getNodeId(), }, ); - const result = await gestaltGraph.getGestaltActionsByNode(nodeId); + const result = await db.withTransactionF(async (tran) => + gestaltGraph.getGestaltActionsByNode(nodeId, tran), + ); if (result == null) { // Node doesn't exist, so no permissions response.setActionList([]); diff --git a/src/client/service/gestaltsActionsSetByIdentity.ts b/src/client/service/gestaltsActionsSetByIdentity.ts index 318ca90b6..b0975d562 100644 --- a/src/client/service/gestaltsActionsSetByIdentity.ts +++ b/src/client/service/gestaltsActionsSetByIdentity.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { GestaltAction } from '../../gestalts/types'; @@ -14,10 +15,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function gestaltsActionsSetByIdentity({ authenticate, gestaltGraph, + db, logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + db: DB; logger: Logger; }) { return async ( @@ -51,10 +54,13 @@ function gestaltsActionsSetByIdentity({ identityId: call.request.getIdentity()?.getIdentityId(), }, ); - await gestaltGraph.setGestaltActionByIdentity( - providerId, - identityId, - action, + await db.withTransactionF(async (tran) => + gestaltGraph.setGestaltActionByIdentity( + providerId, + identityId, + action, + tran, + ), ); callback(null, response); return; diff --git a/src/client/service/gestaltsActionsSetByNode.ts b/src/client/service/gestaltsActionsSetByNode.ts index cd035f0cf..917e3b198 100644 --- a/src/client/service/gestaltsActionsSetByNode.ts +++ b/src/client/service/gestaltsActionsSetByNode.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { GestaltAction } from '../../gestalts/types'; @@ -14,10 +15,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function gestaltsActionsSetByNode({ authenticate, gestaltGraph, + db, logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + db: DB; logger: Logger; }) { return async ( @@ -42,7 +45,9 @@ function gestaltsActionsSetByNode({ action: call.request.getAction(), }, ); - await gestaltGraph.setGestaltActionByNode(nodeId, action); + await db.withTransactionF(async (tran) => + gestaltGraph.setGestaltActionByNode(nodeId, action, tran), + ); callback(null, response); return; } catch (e) { diff --git a/src/client/service/gestaltsActionsUnsetByIdentity.ts b/src/client/service/gestaltsActionsUnsetByIdentity.ts index 8cbd2596a..cb976d117 100644 --- a/src/client/service/gestaltsActionsUnsetByIdentity.ts +++ b/src/client/service/gestaltsActionsUnsetByIdentity.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { GestaltAction } from '../../gestalts/types'; @@ -14,10 +15,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function gestaltsActionsUnsetByIdentity({ authenticate, gestaltGraph, + db, logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + db: DB; logger: Logger; }) { return async ( @@ -51,10 +54,13 @@ function gestaltsActionsUnsetByIdentity({ identityId: call.request.getIdentity()?.getIdentityId(), }, ); - await gestaltGraph.unsetGestaltActionByIdentity( - providerId, - identityId, - action, + await db.withTransactionF(async (tran) => + gestaltGraph.unsetGestaltActionByIdentity( + providerId, + identityId, + action, + tran, + ), ); callback(null, response); return; diff --git a/src/client/service/gestaltsActionsUnsetByNode.ts b/src/client/service/gestaltsActionsUnsetByNode.ts index 958a18060..2bc5d410f 100644 --- a/src/client/service/gestaltsActionsUnsetByNode.ts +++ b/src/client/service/gestaltsActionsUnsetByNode.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { GestaltAction } from '../../gestalts/types'; @@ -14,10 +15,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function gestaltsActionsUnsetByNode({ authenticate, gestaltGraph, + db, logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + db: DB; logger: Logger; }) { return async ( @@ -42,7 +45,9 @@ function gestaltsActionsUnsetByNode({ action: call.request.getAction(), }, ); - await gestaltGraph.unsetGestaltActionByNode(nodeId, action); + await db.withTransactionF(async (tran) => + gestaltGraph.unsetGestaltActionByNode(nodeId, action, tran), + ); callback(null, response); return; } catch (e) { diff --git a/src/client/service/gestaltsGestaltGetByIdentity.ts b/src/client/service/gestaltsGestaltGetByIdentity.ts index c303995ee..4e4a25d78 100644 --- a/src/client/service/gestaltsGestaltGetByIdentity.ts +++ b/src/client/service/gestaltsGestaltGetByIdentity.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { IdentityId, ProviderId } from '../../identities/types'; @@ -13,10 +14,12 @@ import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; function gestaltsGestaltGetByIdentity({ authenticate, gestaltGraph, + db, logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + db: DB; logger: Logger; }) { return async ( @@ -46,9 +49,8 @@ function gestaltsGestaltGetByIdentity({ identityId: call.request.getIdentityId(), }, ); - const gestalt = await gestaltGraph.getGestaltByIdentity( - providerId, - identityId, + const gestalt = await db.withTransactionF(async (tran) => + gestaltGraph.getGestaltByIdentity(providerId, identityId, tran), ); if (gestalt != null) { response.setGestaltGraph(JSON.stringify(gestalt)); diff --git a/src/client/service/gestaltsGestaltGetByNode.ts b/src/client/service/gestaltsGestaltGetByNode.ts index 4cb9cf96d..28fc02c3f 100644 --- a/src/client/service/gestaltsGestaltGetByNode.ts +++ b/src/client/service/gestaltsGestaltGetByNode.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { NodeId } from '../../nodes/types'; import type GestaltGraph from '../../gestalts/GestaltGraph'; @@ -13,10 +14,12 @@ import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; function gestaltsGestaltGetByNode({ authenticate, gestaltGraph, + db, logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + db: DB; logger: Logger; }) { return async ( @@ -42,7 +45,9 @@ function gestaltsGestaltGetByNode({ nodeId: call.request.getNodeId(), }, ); - const gestalt = await gestaltGraph.getGestaltByNode(nodeId); + const gestalt = await db.withTransactionF(async (tran) => + gestaltGraph.getGestaltByNode(nodeId, tran), + ); if (gestalt != null) { response.setGestaltGraph(JSON.stringify(gestalt)); } diff --git a/src/client/service/gestaltsGestaltList.ts b/src/client/service/gestaltsGestaltList.ts index 690988c20..bb96dd53a 100644 --- a/src/client/service/gestaltsGestaltList.ts +++ b/src/client/service/gestaltsGestaltList.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { Gestalt } from '../../gestalts/types'; @@ -10,10 +11,12 @@ import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; function gestaltsGestaltList({ authenticate, gestaltGraph, + db, logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; + db: DB; logger: Logger; }) { return async ( @@ -24,7 +27,9 @@ function gestaltsGestaltList({ try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const certs: Array = await gestaltGraph.getGestalts(); + const certs: Array = await db.withTransactionF(async (tran) => + gestaltGraph.getGestalts(tran), + ); for (const cert of certs) { gestaltMessage = new gestaltsPB.Gestalt(); gestaltMessage.setName(JSON.stringify(cert)); diff --git a/src/client/service/gestaltsGestaltTrustByIdentity.ts b/src/client/service/gestaltsGestaltTrustByIdentity.ts index a5359bc82..71368e7fb 100644 --- a/src/client/service/gestaltsGestaltTrustByIdentity.ts +++ b/src/client/service/gestaltsGestaltTrustByIdentity.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type { IdentityId, ProviderId } from '../../identities/types'; @@ -15,11 +16,13 @@ function gestaltsGestaltTrustByIdentity({ authenticate, gestaltGraph, discovery, + db, logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; discovery: Discovery; + db: DB; logger: Logger; }) { return async ( @@ -50,25 +53,31 @@ function gestaltsGestaltTrustByIdentity({ }, ); // Set the identity in the gestalt graph if not already - if ( - (await gestaltGraph.getGestaltByIdentity(providerId, identityId)) == - null - ) { - // Queue the new identity for discovery - // This will only add the identity to the GG if it is connected to a - // node (required to set permissions for it) - await discovery.queueDiscoveryByIdentity(providerId, identityId); - } - // We can currently only set permissions for identities that are - // connected to at least one node. If these conditions are not met, this - // will throw an error. Since discovery can take time, you may need to - // reattempt this command if it fails on the first attempt and you expect - // there to be a linked node for the identity. - await gestaltGraph.setGestaltActionByIdentity( - providerId, - identityId, - 'notify', - ); + await db.withTransactionF(async (tran) => { + if ( + (await gestaltGraph.getGestaltByIdentity( + providerId, + identityId, + tran, + )) == null + ) { + // Queue the new identity for discovery + // This will only add the identity to the GG if it is connected to a + // node (required to set permissions for it) + await discovery.queueDiscoveryByIdentity(providerId, identityId); + } + // We can currently only set permissions for identities that are + // connected to at least one node. If these conditions are not met, this + // will throw an error. Since discovery can take time, you may need to + // reattempt this command if it fails on the first attempt and you expect + // there to be a linked node for the identity. + await gestaltGraph.setGestaltActionByIdentity( + providerId, + identityId, + 'notify', + tran, + ); + }); callback(null, response); return; } catch (e) { diff --git a/src/client/service/gestaltsGestaltTrustByNode.ts b/src/client/service/gestaltsGestaltTrustByNode.ts index bad8dc219..097a94b07 100644 --- a/src/client/service/gestaltsGestaltTrustByNode.ts +++ b/src/client/service/gestaltsGestaltTrustByNode.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type Discovery from '../../discovery/Discovery'; @@ -16,11 +17,13 @@ function gestaltsGestaltTrustByNode({ authenticate, gestaltGraph, discovery, + db, logger, }: { authenticate: Authenticate; gestaltGraph: GestaltGraph; discovery: Discovery; + db: DB; logger: Logger; }) { return async ( @@ -46,17 +49,22 @@ function gestaltsGestaltTrustByNode({ nodeId: call.request.getNodeId(), }, ); - // Set the node in the gestalt graph if not already - if ((await gestaltGraph.getGestaltByNode(nodeId)) == null) { - await gestaltGraph.setNode({ - id: nodesUtils.encodeNodeId(nodeId), - chain: {}, - }); - // Queue the new node for discovery - await discovery.queueDiscoveryByNode(nodeId); - } - // Set notify permission - await gestaltGraph.setGestaltActionByNode(nodeId, 'notify'); + await db.withTransactionF(async (tran) => { + // Set the node in the gestalt graph if not already + if ((await gestaltGraph.getGestaltByNode(nodeId, tran)) == null) { + await gestaltGraph.setNode( + { + id: nodesUtils.encodeNodeId(nodeId), + chain: {}, + }, + tran, + ); + // Queue the new node for discovery + await discovery.queueDiscoveryByNode(nodeId); + } + // Set notify permission + await gestaltGraph.setGestaltActionByNode(nodeId, 'notify', tran); + }); callback(null, response); return; } catch (e) { diff --git a/src/client/service/identitiesClaim.ts b/src/client/service/identitiesClaim.ts index 93a947e42..43919bd45 100644 --- a/src/client/service/identitiesClaim.ts +++ b/src/client/service/identitiesClaim.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type KeyManager from '../../keys/KeyManager'; import type Sigchain from '../../sigchain/Sigchain'; @@ -22,12 +23,14 @@ function identitiesClaim({ identitiesManager, sigchain, keyManager, + db, logger, }: { authenticate: Authenticate; identitiesManager: IdentitiesManager; sigchain: Sigchain; keyManager: KeyManager; + db: DB; logger: Logger; }) { return async ( @@ -67,12 +70,17 @@ function identitiesClaim({ throw new identitiesErrors.ErrorProviderUnauthenticated(); } // Create identity claim on our node - const [, claim] = await sigchain.addClaim({ - type: 'identity', - node: nodesUtils.encodeNodeId(keyManager.getNodeId()), - provider: providerId, - identity: identityId, - }); + const [, claim] = await db.withTransactionF(async (tran) => + sigchain.addClaim( + { + type: 'identity', + node: nodesUtils.encodeNodeId(keyManager.getNodeId()), + provider: providerId, + identity: identityId, + }, + tran, + ), + ); // Publish claim on identity const claimDecoded = claimsUtils.decodeClaim(claim); const claimData = await provider.publishClaim(identityId, claimDecoded); diff --git a/src/client/service/identitiesTokenDelete.ts b/src/client/service/identitiesTokenDelete.ts index 347e37bb4..82d0d57d5 100644 --- a/src/client/service/identitiesTokenDelete.ts +++ b/src/client/service/identitiesTokenDelete.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type IdentitiesManager from '../../identities/IdentitiesManager'; import type { IdentityId, ProviderId } from '../../identities/types'; @@ -13,10 +14,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function identitiesTokenDelete({ authenticate, identitiesManager, + db, logger, }: { authenticate: Authenticate; identitiesManager: IdentitiesManager; + db: DB; logger: Logger; }) { return async ( @@ -46,7 +49,9 @@ function identitiesTokenDelete({ identityId: call.request.getIdentityId(), }, ); - await identitiesManager.delToken(providerId, identityId); + await db.withTransactionF(async (tran) => + identitiesManager.delToken(providerId, identityId, tran), + ); callback(null, response); return; } catch (e) { diff --git a/src/client/service/identitiesTokenGet.ts b/src/client/service/identitiesTokenGet.ts index 7844382a8..09199866d 100644 --- a/src/client/service/identitiesTokenGet.ts +++ b/src/client/service/identitiesTokenGet.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type IdentitiesManager from '../../identities/IdentitiesManager'; import type { IdentityId, ProviderId } from '../../identities/types'; @@ -12,10 +13,12 @@ import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_p function identitiesTokenGet({ authenticate, identitiesManager, + db, logger, }: { authenticate: Authenticate; identitiesManager: IdentitiesManager; + db: DB; logger: Logger; }) { return async ( @@ -45,7 +48,9 @@ function identitiesTokenGet({ identityId: call.request.getIdentityId(), }, ); - const tokens = await identitiesManager.getToken(providerId, identityId); + const tokens = await db.withTransactionF(async (tran) => + identitiesManager.getToken(providerId, identityId, tran), + ); response.setToken(JSON.stringify(tokens)); callback(null, response); return; diff --git a/src/client/service/identitiesTokenPut.ts b/src/client/service/identitiesTokenPut.ts index babfd8db7..336f1646a 100644 --- a/src/client/service/identitiesTokenPut.ts +++ b/src/client/service/identitiesTokenPut.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type IdentitiesManager from '../../identities/IdentitiesManager'; import type { IdentityId, ProviderId, TokenData } from '../../identities/types'; @@ -13,10 +14,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function identitiesTokenPut({ authenticate, identitiesManager, + db, logger, }: { authenticate: Authenticate; identitiesManager: IdentitiesManager; + db: DB; logger: Logger; }) { return async ( @@ -49,9 +52,16 @@ function identitiesTokenPut({ identityId: call.request.getProvider()?.getIdentityId(), }, ); - await identitiesManager.putToken(providerId, identityId, { - accessToken: call.request.getToken(), - } as TokenData); + await db.withTransactionF(async (tran) => + identitiesManager.putToken( + providerId, + identityId, + { + accessToken: call.request.getToken(), + } as TokenData, + tran, + ), + ); callback(null, response); return; } catch (e) { diff --git a/src/client/service/nodesAdd.ts b/src/client/service/nodesAdd.ts index cda85ee22..1433e0896 100644 --- a/src/client/service/nodesAdd.ts +++ b/src/client/service/nodesAdd.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type NodeManager from '../../nodes/NodeManager'; import type { NodeId, NodeAddress } from '../../nodes/types'; @@ -19,10 +20,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function nodesAdd({ authenticate, nodeManager, + db, logger, }: { authenticate: Authenticate; nodeManager: NodeManager; + db: DB; logger: Logger; }) { return async ( @@ -56,10 +59,16 @@ function nodesAdd({ port: call.request.getAddress()?.getPort(), }, ); - await nodeManager.setNode(nodeId, { - host, - port, - } as NodeAddress); + await db.withTransactionF(async (tran) => + nodeManager.setNode( + nodeId, + { + host, + port, + } as NodeAddress, + tran, + ), + ); callback(null, response); return; } catch (e) { diff --git a/src/client/service/nodesClaim.ts b/src/client/service/nodesClaim.ts index 3c165d579..4d9cdc783 100644 --- a/src/client/service/nodesClaim.ts +++ b/src/client/service/nodesClaim.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type NodeManager from '../../nodes/NodeManager'; import type { NodeId } from '../../nodes/types'; @@ -20,11 +21,13 @@ function nodesClaim({ authenticate, nodeManager, notificationsManager, + db, logger, }: { authenticate: Authenticate; nodeManager: NodeManager; notificationsManager: NotificationsManager; + db: DB; logger: Logger; }) { return async ( @@ -50,21 +53,24 @@ function nodesClaim({ nodeId: call.request.getNodeId(), }, ); - const gestaltInvite = await notificationsManager.findGestaltInvite( - nodeId, - ); - // Check first whether there is an existing gestalt invite from the remote node - // or if we want to force an invitation rather than a claim - if (gestaltInvite === undefined || call.request.getForceInvite()) { - await notificationsManager.sendNotification(nodeId, { - type: 'GestaltInvite', - }); - response.setSuccess(false); - } else { - // There is an existing invitation, and we want to claim the node - await nodeManager.claimNode(nodeId); - response.setSuccess(true); - } + await db.withTransactionF(async (tran) => { + const gestaltInvite = await notificationsManager.findGestaltInvite( + nodeId, + tran, + ); + // Check first whether there is an existing gestalt invite from the remote node + // or if we want to force an invitation rather than a claim + if (gestaltInvite === undefined || call.request.getForceInvite()) { + await notificationsManager.sendNotification(nodeId, { + type: 'GestaltInvite', + }); + response.setSuccess(false); + } else { + // There is an existing invitation, and we want to claim the node + await nodeManager.claimNode(nodeId, tran); + response.setSuccess(true); + } + }); callback(null, response); return; } catch (e) { diff --git a/src/client/service/notificationsClear.ts b/src/client/service/notificationsClear.ts index 2fd077c9b..56b2fabef 100644 --- a/src/client/service/notificationsClear.ts +++ b/src/client/service/notificationsClear.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type NotificationsManager from '../../notifications/NotificationsManager'; import type Logger from '@matrixai/logger'; @@ -8,10 +9,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function notificationsClear({ authenticate, notificationsManager, + db, logger, }: { authenticate: Authenticate; notificationsManager: NotificationsManager; + db: DB; logger: Logger; }) { return async ( @@ -22,7 +25,9 @@ function notificationsClear({ const response = new utilsPB.EmptyMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - await notificationsManager.clearNotifications(); + await db.withTransactionF(async (tran) => + notificationsManager.clearNotifications(tran), + ); callback(null, response); return; } catch (e) { diff --git a/src/client/service/notificationsRead.ts b/src/client/service/notificationsRead.ts index 630940764..63b94438d 100644 --- a/src/client/service/notificationsRead.ts +++ b/src/client/service/notificationsRead.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type NotificationsManager from '../../notifications/NotificationsManager'; import type Logger from '@matrixai/logger'; @@ -8,10 +9,12 @@ import * as notificationsPB from '../../proto/js/polykey/v1/notifications/notifi function notificationsRead({ authenticate, notificationsManager, + db, logger, }: { authenticate: Authenticate; notificationsManager: NotificationsManager; + db: DB; logger: Logger; }) { return async ( @@ -31,11 +34,14 @@ function notificationsRead({ } else { number = parseInt(numberField); } - const notifications = await notificationsManager.readNotifications({ - unread, - number, - order, - }); + const notifications = await db.withTransactionF(async (tran) => + notificationsManager.readNotifications({ + unread, + number, + order, + tran, + }), + ); const notifMessages: Array = []; for (const notif of notifications) { const notificationsMessage = new notificationsPB.Notification(); diff --git a/src/client/service/vaultsClone.ts b/src/client/service/vaultsClone.ts index 75b6dcf56..bd3693c5c 100644 --- a/src/client/service/vaultsClone.ts +++ b/src/client/service/vaultsClone.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; @@ -11,10 +12,12 @@ import * as vaultsUtils from '../../vaults/utils'; function vaultsClone({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -43,7 +46,9 @@ function vaultsClone({ vaultId = vaultId ?? vaultNameOrId; // Node id const nodeId = validationUtils.parseNodeId(nodeMessage.getNodeId()); - await vaultManager.cloneVault(nodeId, vaultId); + await db.withTransactionF(async (tran) => + vaultManager.cloneVault(nodeId, vaultId, tran), + ); response.setSuccess(true); callback(null, response); return; diff --git a/src/client/service/vaultsCreate.ts b/src/client/service/vaultsCreate.ts index 74224733b..a739604e7 100644 --- a/src/client/service/vaultsCreate.ts +++ b/src/client/service/vaultsCreate.ts @@ -2,6 +2,7 @@ import type { Authenticate } from '../types'; import type { VaultId, VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; @@ -11,10 +12,12 @@ import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; function vaultsCreate({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -26,8 +29,8 @@ function vaultsCreate({ try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - vaultId = await vaultManager.createVault( - call.request.getNameOrId() as VaultName, + vaultId = await db.withTransactionF(async (tran) => + vaultManager.createVault(call.request.getNameOrId() as VaultName, tran), ); response.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); callback(null, response); diff --git a/src/client/service/vaultsDelete.ts b/src/client/service/vaultsDelete.ts index 0f7aa01e7..7a87f2da0 100644 --- a/src/client/service/vaultsDelete.ts +++ b/src/client/service/vaultsDelete.ts @@ -2,6 +2,7 @@ import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; @@ -11,10 +12,12 @@ import * as validationUtils from '../../validation/utils'; function vaultsDelete({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -27,9 +30,14 @@ function vaultsDelete({ const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - await vaultManager.destroyVault(vaultId); + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + await vaultManager.destroyVault(vaultId, tran); + }); response.setSuccess(true); callback(null, response); return; diff --git a/src/client/service/vaultsList.ts b/src/client/service/vaultsList.ts index 794c44909..a4a618275 100644 --- a/src/client/service/vaultsList.ts +++ b/src/client/service/vaultsList.ts @@ -1,6 +1,7 @@ import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; @@ -10,23 +11,24 @@ import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; function vaultsList({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( call: grpc.ServerWritableStream, ): Promise => { - // Call.on('error', (e) => console.error(e)); - // call.on('close', () => console.log('Got close')); - // call.on('finish', () => console.log('Got finish')); const genWritable = grpcUtils.generatorWritable(call, false); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaults = await vaultManager.listVaults(); + const vaults = await db.withTransactionF(async (tran) => + vaultManager.listVaults(tran), + ); for await (const [vaultName, vaultId] of vaults) { const vaultListMessage = new vaultsPB.List(); vaultListMessage.setVaultName(vaultName); diff --git a/src/client/service/vaultsLog.ts b/src/client/service/vaultsLog.ts index 6d720e825..367dd0a1e 100644 --- a/src/client/service/vaultsLog.ts +++ b/src/client/service/vaultsLog.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -11,10 +12,12 @@ import * as validationUtils from '../../validation/utils'; function vaultsLog({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -32,14 +35,23 @@ function vaultsLog({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - // Getting the log - const depth = vaultsLogMessage.getLogDepth(); - let commitId: string | undefined = vaultsLogMessage.getCommitId(); - commitId = commitId ? commitId : undefined; - const log = await vaultManager.withVaults([vaultId], async (vault) => { - return await vault.log(commitId, depth); + const log = await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + // Getting the log + const depth = vaultsLogMessage.getLogDepth(); + let commitId: string | undefined = vaultsLogMessage.getCommitId(); + commitId = commitId ? commitId : undefined; + return await vaultManager.withVaults( + [vaultId], + async (vault) => { + return await vault.log(commitId, depth); + }, + tran, + ); }); const vaultsLogEntryMessage = new vaultsPB.LogEntry(); for (const entry of log) { diff --git a/src/client/service/vaultsPermissionGet.ts b/src/client/service/vaultsPermissionGet.ts index 1682044ad..8e62be35a 100644 --- a/src/client/service/vaultsPermissionGet.ts +++ b/src/client/service/vaultsPermissionGet.ts @@ -1,4 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; import type { VaultName } from '../../vaults/types'; @@ -17,11 +18,13 @@ function vaultsPermissionGet({ authenticate, vaultManager, acl, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; acl: ACL; + db: DB; logger: Logger; }) { return async ( @@ -34,11 +37,17 @@ function vaultsPermissionGet({ call.sendMetadata(metadata); // Getting vaultId const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - - // Getting permissions - const rawPermissions = await acl.getVaultPerm(vaultId); + const [rawPermissions, vaultId] = await db.withTransactionF( + async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + // Getting permissions + return [await acl.getVaultPerm(vaultId, tran), vaultId]; + }, + ); const permissionList: Record = {}; // Getting the relevant information for (const nodeId in rawPermissions) { diff --git a/src/client/service/vaultsPermissionSet.ts b/src/client/service/vaultsPermissionSet.ts index f19ec7da3..f91ccd81f 100644 --- a/src/client/service/vaultsPermissionSet.ts +++ b/src/client/service/vaultsPermissionSet.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -20,6 +21,7 @@ function vaultsPermissionSet({ gestaltGraph, acl, notificationsManager, + db, logger, }: { authenticate: Authenticate; @@ -27,6 +29,7 @@ function vaultsPermissionSet({ gestaltGraph: GestaltGraph; acl: ACL; notificationsManager: NotificationsManager; + db: DB; logger: Logger; }) { return async ( @@ -44,32 +47,37 @@ function vaultsPermissionSet({ callback({ code: grpc.status.NOT_FOUND }, null); return; } - // Parsing VaultId - const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - // Parsing NodeId - const nodeId = validationUtils.parseNodeId(nodeMessage.getNodeId()); - // Parsing actions - const actions = vaultsPermissionsMessage - .getVaultPermissionsList() - .map((vaultAction) => validationUtils.parseVaultAction(vaultAction)); - // Checking if vault exists - const vaultMeta = await vaultManager.getVaultMeta(vaultId); - if (!vaultMeta) throw new vaultsErrors.ErrorVaultsVaultUndefined(); - // Setting permissions - const actionsSet: VaultActions = {}; - await gestaltGraph.setGestaltActionByNode(nodeId, 'scan'); - for (const action of actions) { - await acl.setVaultAction(vaultId, nodeId, action); - actionsSet[action] = null; - } - // Sending notification - await notificationsManager.sendNotification(nodeId, { - type: 'VaultShare', - vaultId: vaultsUtils.encodeVaultId(vaultId), - vaultName: vaultMeta.vaultName, - actions: actionsSet, + await db.withTransactionF(async (tran) => { + // Parsing VaultId + const nameOrId = vaultMessage.getNameOrId(); + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + // Parsing NodeId + const nodeId = validationUtils.parseNodeId(nodeMessage.getNodeId()); + // Parsing actions + const actions = vaultsPermissionsMessage + .getVaultPermissionsList() + .map((vaultAction) => validationUtils.parseVaultAction(vaultAction)); + // Checking if vault exists + const vaultMeta = await vaultManager.getVaultMeta(vaultId, tran); + if (!vaultMeta) throw new vaultsErrors.ErrorVaultsVaultUndefined(); + // Setting permissions + const actionsSet: VaultActions = {}; + await gestaltGraph.setGestaltActionByNode(nodeId, 'scan', tran); + for (const action of actions) { + await acl.setVaultAction(vaultId, nodeId, action, tran); + actionsSet[action] = null; + } + // Sending notification + await notificationsManager.sendNotification(nodeId, { + type: 'VaultShare', + vaultId: vaultsUtils.encodeVaultId(vaultId), + vaultName: vaultMeta.vaultName, + actions: actionsSet, + }); }); // Formatting response const response = new utilsPB.StatusMessage().setSuccess(true); diff --git a/src/client/service/vaultsPermissionUnset.ts b/src/client/service/vaultsPermissionUnset.ts index cd9c0ee9e..8095e21c4 100644 --- a/src/client/service/vaultsPermissionUnset.ts +++ b/src/client/service/vaultsPermissionUnset.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -16,12 +17,14 @@ function vaultsPermissionUnset({ vaultManager, gestaltGraph, acl, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; gestaltGraph: GestaltGraph; acl: ACL; + db: DB; logger: Logger; }) { return async ( @@ -39,37 +42,39 @@ function vaultsPermissionUnset({ callback({ code: grpc.status.NOT_FOUND }, null); return; } - // Parsing VaultId - const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - // Parsing NodeId - const nodeId = validationUtils.parseNodeId(nodeMessage.getNodeId()); - // Parsing actions - const actions = vaultsPermissionsMessage - .getVaultPermissionsList() - .map((vaultAction) => validationUtils.parseVaultAction(vaultAction)); - // Checking if vault exists - const vaultMeta = await vaultManager.getVaultMeta(vaultId); - if (!vaultMeta) throw new vaultsErrors.ErrorVaultsVaultUndefined(); - // Unsetting permissions - await gestaltGraph.setGestaltActionByNode(nodeId, 'scan'); - for (const action of actions) { - await acl.unsetVaultAction(vaultId, nodeId, action); - } - // We need to check if there are still shared vaults - const nodePermissions = await acl.getNodePerm(nodeId); - // Remove scan permissions if no more shared vaults - if (nodePermissions != null) { - // Counting total number of permissions - const totalPermissions = Object.keys(nodePermissions.vaults) - .map((key) => Object.keys(nodePermissions.vaults[key]).length) - .reduce((prev, current) => current + prev); - // If no permissions are left then we remove the scan permission - if (totalPermissions === 0) { - await gestaltGraph.unsetGestaltActionByNode(nodeId, 'scan'); + await db.withTransactionF(async (tran) => { + // Parsing VaultId + const nameOrId = vaultMessage.getNameOrId(); + let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + // Parsing NodeId + const nodeId = validationUtils.parseNodeId(nodeMessage.getNodeId()); + // Parsing actions + const actions = vaultsPermissionsMessage + .getVaultPermissionsList() + .map((vaultAction) => validationUtils.parseVaultAction(vaultAction)); + // Checking if vault exists + const vaultMeta = await vaultManager.getVaultMeta(vaultId, tran); + if (!vaultMeta) throw new vaultsErrors.ErrorVaultsVaultUndefined(); + // Unsetting permissions + await gestaltGraph.setGestaltActionByNode(nodeId, 'scan', tran); + for (const action of actions) { + await acl.unsetVaultAction(vaultId, nodeId, action, tran); } - } + // We need to check if there are still shared vaults + const nodePermissions = await acl.getNodePerm(nodeId, tran); + // Remove scan permissions if no more shared vaults + if (nodePermissions != null) { + // Counting total number of permissions + const totalPermissions = Object.keys(nodePermissions.vaults) + .map((key) => Object.keys(nodePermissions.vaults[key]).length) + .reduce((prev, current) => current + prev); + // If no permissions are left then we remove the scan permission + if (totalPermissions === 0) { + await gestaltGraph.unsetGestaltActionByNode(nodeId, 'scan', tran); + } + } + }); // Formatting response const response = new utilsPB.StatusMessage().setSuccess(true); callback(null, response); diff --git a/src/client/service/vaultsPull.ts b/src/client/service/vaultsPull.ts index 821e3179a..f68a62903 100644 --- a/src/client/service/vaultsPull.ts +++ b/src/client/service/vaultsPull.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; import type { VaultName } from '../../vaults/types'; @@ -12,10 +13,12 @@ import * as vaultsUtils from '../../vaults/utils'; function vaultsPull({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -33,28 +36,34 @@ function vaultsPull({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - let nodeId; - const nodeMessage = call.request.getNode(); - if (nodeMessage == null) { - nodeId = null; - } else { - nodeId = validationUtils.parseNodeId(nodeMessage.getNodeId()); - } - let pullVault; - const pullVaultMessage = call.request.getPullVault(); - if (pullVaultMessage == null) { - pullVault = null; - } else { - pullVault = vaultsUtils.decodeVaultId(pullVaultMessage.getNameOrId()); - pullVault = pullVault ?? pullVaultMessage.getNameOrId(); - if (pullVault == null) pullVault = pullVaultMessage.getNameOrId(); - } - await vaultManager.pullVault({ - vaultId, - pullNodeId: nodeId, - pullVaultNameOrId: pullVault, + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + let nodeId; + const nodeMessage = call.request.getNode(); + if (nodeMessage == null) { + nodeId = null; + } else { + nodeId = validationUtils.parseNodeId(nodeMessage.getNodeId()); + } + let pullVault; + const pullVaultMessage = call.request.getPullVault(); + if (pullVaultMessage == null) { + pullVault = null; + } else { + pullVault = vaultsUtils.decodeVaultId(pullVaultMessage.getNameOrId()); + pullVault = pullVault ?? pullVaultMessage.getNameOrId(); + if (pullVault == null) pullVault = pullVaultMessage.getNameOrId(); + } + await vaultManager.pullVault({ + vaultId, + pullNodeId: nodeId, + pullVaultNameOrId: pullVault, + tran, + }); }); response.setSuccess(true); callback(null, response); diff --git a/src/client/service/vaultsRename.ts b/src/client/service/vaultsRename.ts index 27276c1aa..0689b2506 100644 --- a/src/client/service/vaultsRename.ts +++ b/src/client/service/vaultsRename.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -11,10 +12,12 @@ import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; function vaultsRename({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -31,11 +34,16 @@ function vaultsRename({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - const newName = call.request.getNewName() as VaultName; - await vaultManager.renameVault(vaultId, newName); - response.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const newName = call.request.getNewName() as VaultName; + await vaultManager.renameVault(vaultId, newName); + response.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); + }); callback(null, response); return; } catch (e) { diff --git a/src/client/service/vaultsSecretsDelete.ts b/src/client/service/vaultsSecretsDelete.ts index 6332c1442..46784f9fe 100644 --- a/src/client/service/vaultsSecretsDelete.ts +++ b/src/client/service/vaultsSecretsDelete.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -12,10 +13,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsSecretsDelete({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -32,11 +35,20 @@ function vaultsSecretsDelete({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - const secretName = call.request.getSecretName(); - await vaultManager.withVaults([vaultId], async (vault) => { - await vaultOps.deleteSecret(vault, secretName); + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const secretName = call.request.getSecretName(); + await vaultManager.withVaults( + [vaultId], + async (vault) => { + await vaultOps.deleteSecret(vault, secretName); + }, + tran, + ); }); response.setSuccess(true); callback(null, response); diff --git a/src/client/service/vaultsSecretsEdit.ts b/src/client/service/vaultsSecretsEdit.ts index d502d9808..897a6dd12 100644 --- a/src/client/service/vaultsSecretsEdit.ts +++ b/src/client/service/vaultsSecretsEdit.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -12,10 +13,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsSecretsEdit({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -37,12 +40,21 @@ function vaultsSecretsEdit({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - const secretName = secretMessage.getSecretName(); - const secretContent = Buffer.from(secretMessage.getSecretContent()); - await vaultManager.withVaults([vaultId], async (vault) => { - await vaultOps.updateSecret(vault, secretName, secretContent); + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const secretName = secretMessage.getSecretName(); + const secretContent = Buffer.from(secretMessage.getSecretContent()); + await vaultManager.withVaults( + [vaultId], + async (vault) => { + await vaultOps.updateSecret(vault, secretName, secretContent); + }, + tran, + ); }); response.setSuccess(true); callback(null, response); diff --git a/src/client/service/vaultsSecretsGet.ts b/src/client/service/vaultsSecretsGet.ts index bd3c3a330..cdb2a75fb 100644 --- a/src/client/service/vaultsSecretsGet.ts +++ b/src/client/service/vaultsSecretsGet.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -12,10 +13,12 @@ import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; function vaultsSecretsGet({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -32,16 +35,22 @@ function vaultsSecretsGet({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - const secretName = call.request.getSecretName(); - const secretContent = await vaultManager.withVaults( - [vaultId], - async (vault) => { - return await vaultOps.getSecret(vault, secretName); - }, - ); - response.setSecretContent(secretContent); + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const secretName = call.request.getSecretName(); + const secretContent = await vaultManager.withVaults( + [vaultId], + async (vault) => { + return await vaultOps.getSecret(vault, secretName); + }, + tran, + ); + response.setSecretContent(secretContent); + }); callback(null, response); return; } catch (e) { diff --git a/src/client/service/vaultsSecretsList.ts b/src/client/service/vaultsSecretsList.ts index c9732edbf..8056c7a90 100644 --- a/src/client/service/vaultsSecretsList.ts +++ b/src/client/service/vaultsSecretsList.ts @@ -2,6 +2,7 @@ import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; +import type { DB } from '@matrixai/db'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; import * as validationUtils from '../../validation/utils'; @@ -12,10 +13,12 @@ import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; function vaultsSecretsList({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -27,14 +30,20 @@ function vaultsSecretsList({ call.sendMetadata(metadata); const vaultMessage = call.request; const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - const secrets = await vaultManager.withVaults( - [vaultId], - async (vault) => { - return await vaultOps.listSecrets(vault); - }, - ); + const secrets = await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + return await vaultManager.withVaults( + [vaultId], + async (vault) => { + return await vaultOps.listSecrets(vault); + }, + tran, + ); + }); let secretMessage: secretsPB.Secret; for (const secret of secrets) { secretMessage = new secretsPB.Secret(); diff --git a/src/client/service/vaultsSecretsMkdir.ts b/src/client/service/vaultsSecretsMkdir.ts index 3753571c7..6d5649fb5 100644 --- a/src/client/service/vaultsSecretsMkdir.ts +++ b/src/client/service/vaultsSecretsMkdir.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -12,10 +13,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsSecretsMkdir({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -33,12 +36,21 @@ function vaultsSecretsMkdir({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - await vaultManager.withVaults([vaultId], async (vault) => { - await vaultOps.mkdir(vault, vaultMkdirMessge.getDirName(), { - recursive: vaultMkdirMessge.getRecursive(), - }); + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + await vaultManager.withVaults( + [vaultId], + async (vault) => { + await vaultOps.mkdir(vault, vaultMkdirMessge.getDirName(), { + recursive: vaultMkdirMessge.getRecursive(), + }); + }, + tran, + ); }); response.setSuccess(true); callback(null, response); diff --git a/src/client/service/vaultsSecretsNew.ts b/src/client/service/vaultsSecretsNew.ts index b264631f9..0a6c1920c 100644 --- a/src/client/service/vaultsSecretsNew.ts +++ b/src/client/service/vaultsSecretsNew.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -12,10 +13,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsSecretsNew({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -32,12 +35,21 @@ function vaultsSecretsNew({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - const secret = call.request.getSecretName(); - const content = Buffer.from(call.request.getSecretContent()); - await vaultManager.withVaults([vaultId], async (vault) => { - await vaultOps.addSecret(vault, secret, content); + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const secret = call.request.getSecretName(); + const content = Buffer.from(call.request.getSecretContent()); + await vaultManager.withVaults( + [vaultId], + async (vault) => { + await vaultOps.addSecret(vault, secret, content); + }, + tran, + ); }); response.setSuccess(true); callback(null, response); diff --git a/src/client/service/vaultsSecretsNewDir.ts b/src/client/service/vaultsSecretsNewDir.ts index 36fd2b3af..daf151f58 100644 --- a/src/client/service/vaultsSecretsNewDir.ts +++ b/src/client/service/vaultsSecretsNewDir.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -14,11 +15,13 @@ function vaultsSecretsNewDir({ authenticate, vaultManager, fs, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; fs: FileSystem; + db: DB; logger: Logger; }) { return async ( @@ -35,11 +38,20 @@ function vaultsSecretsNewDir({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - const secretsPath = call.request.getSecretDirectory(); - await vaultManager.withVaults([vaultId], async (vault) => { - await vaultOps.addSecretDirectory(vault, secretsPath, fs); + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const secretsPath = call.request.getSecretDirectory(); + await vaultManager.withVaults( + [vaultId], + async (vault) => { + await vaultOps.addSecretDirectory(vault, secretsPath, fs); + }, + tran, + ); }); response.setSuccess(true); callback(null, response); diff --git a/src/client/service/vaultsSecretsRename.ts b/src/client/service/vaultsSecretsRename.ts index ceeb7160e..fabe0512c 100644 --- a/src/client/service/vaultsSecretsRename.ts +++ b/src/client/service/vaultsSecretsRename.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -12,10 +13,12 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; function vaultsSecretsRename({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -37,12 +40,21 @@ function vaultsSecretsRename({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - const oldSecret = secretMessage.getSecretName(); - const newSecret = call.request.getNewName(); - await vaultManager.withVaults([vaultId], async (vault) => { - await vaultOps.renameSecret(vault, oldSecret, newSecret); + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const oldSecret = secretMessage.getSecretName(); + const newSecret = call.request.getNewName(); + await vaultManager.withVaults( + [vaultId], + async (vault) => { + await vaultOps.renameSecret(vault, oldSecret, newSecret); + }, + tran, + ); }); response.setSuccess(true); callback(null, response); diff --git a/src/client/service/vaultsSecretsStat.ts b/src/client/service/vaultsSecretsStat.ts index ab03c57e4..d30b1e20f 100644 --- a/src/client/service/vaultsSecretsStat.ts +++ b/src/client/service/vaultsSecretsStat.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type VaultManager from '../../vaults/VaultManager'; import type { VaultName } from '../../vaults/types'; import type { Authenticate } from '../types'; @@ -11,10 +12,12 @@ import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; function vaultsSecretsStat({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -31,13 +34,22 @@ function vaultsSecretsStat({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - const secretName = call.request.getSecretName(); - const stat = await vaultManager.withVaults([vaultId], async (vault) => { - return await vaultOps.statSecret(vault, secretName); + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const secretName = call.request.getSecretName(); + const stat = await vaultManager.withVaults( + [vaultId], + async (vault) => { + return await vaultOps.statSecret(vault, secretName); + }, + tran, + ); + response.setJson(JSON.stringify(stat)); }); - response.setJson(JSON.stringify(stat)); callback(null, response); return; } catch (e) { diff --git a/src/client/service/vaultsVersion.ts b/src/client/service/vaultsVersion.ts index fcb32a2fe..18868456b 100644 --- a/src/client/service/vaultsVersion.ts +++ b/src/client/service/vaultsVersion.ts @@ -1,3 +1,4 @@ +import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; @@ -10,10 +11,12 @@ import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; function vaultsVersion({ authenticate, vaultManager, + db, logger, }: { authenticate: Authenticate; vaultManager: VaultManager; + db: DB; logger: Logger; }) { return async ( @@ -33,23 +36,30 @@ function vaultsVersion({ return; } const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - // Doing the deed - const versionId = vaultsVersionMessage.getVersionId(); - const [latestOid, currentVersionId] = await vaultManager.withVaults( - [vaultId], - async (vault) => { - const latestOid = (await vault.log())[0].commitId; - await vault.version(versionId); - const currentVersionId = (await vault.log(versionId, 0))[0]?.commitId; - return [latestOid, currentVersionId]; - }, - ); - // Checking if latest version ID - const isLatestVersion = latestOid === currentVersionId; - // Creating message - response.setIsLatestVersion(isLatestVersion); + await db.withTransactionF(async (tran) => { + let vaultId = await vaultManager.getVaultId( + nameOrId as VaultName, + tran, + ); + vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + // Doing the deed + const versionId = vaultsVersionMessage.getVersionId(); + const [latestOid, currentVersionId] = await vaultManager.withVaults( + [vaultId], + async (vault) => { + const latestOid = (await vault.log())[0].commitId; + await vault.version(versionId); + const currentVersionId = (await vault.log(versionId, 0))[0] + ?.commitId; + return [latestOid, currentVersionId]; + }, + tran, + ); + // Checking if latest version ID + const isLatestVersion = latestOid === currentVersionId; + // Creating message + response.setIsLatestVersion(isLatestVersion); + }); // Sending message callback(null, response); return; diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index fe57b8001..6adf77867 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -306,13 +306,14 @@ class NodeManager { /** * Retrieves the node Address from the NodeGraph * @param nodeId node ID of the target node + * @param tran * @returns Node Address of the target node */ public async getNodeAddress( nodeId: NodeId, + tran?: DBTransaction, ): Promise { - // FIXME: use tran - return await this.nodeGraph.getNode(nodeId); + return await this.nodeGraph.getNode(nodeId, tran); } /** @@ -331,9 +332,11 @@ class NodeManager { /** * Gets the specified bucket from the NodeGraph */ - public async getBucket(bucketIndex: number): Promise { - // FIXME: use tran - return await this.nodeGraph.getBucket(bucketIndex); + public async getBucket( + bucketIndex: number, + tran?: DBTransaction, + ): Promise { + return await this.nodeGraph.getBucket(bucketIndex, tran); } /** @@ -342,9 +345,9 @@ class NodeManager { public async setNode( nodeId: NodeId, nodeAddress: NodeAddress, + tran?: DBTransaction, ): Promise { - // FIXME: use tran - return await this.nodeGraph.setNode(nodeId, nodeAddress); + return await this.nodeGraph.setNode(nodeId, nodeAddress, tran); } /** @@ -353,34 +356,31 @@ class NodeManager { public async updateNode( nodeId: NodeId, nodeAddress?: NodeAddress, + tran?: DBTransaction, ): Promise { - // FIXME: use tran - return await this.nodeGraph.updateNode(nodeId, nodeAddress); + return await this.nodeGraph.updateNode(nodeId, nodeAddress, tran); } /** * Removes a node from the NodeGraph */ - public async unsetNode(nodeId: NodeId): Promise { - // FIXME: use tran - return await this.nodeGraph.unsetNode(nodeId); + public async unsetNode(nodeId: NodeId, tran?: DBTransaction): Promise { + return await this.nodeGraph.unsetNode(nodeId, tran); } /** * Gets all buckets from the NodeGraph */ - public async getAllBuckets(): Promise> { - // FIXME: use tran - return await this.nodeGraph.getAllBuckets(); + public async getAllBuckets(tran?: DBTransaction): Promise> { + return await this.nodeGraph.getAllBuckets(tran); } /** * To be called on key renewal. Re-orders all nodes in all buckets with respect * to the new node ID. */ - public async refreshBuckets(): Promise { - // FIXME: use tran - return await this.nodeGraph.refreshBuckets(); + public async refreshBuckets(tran?: DBTransaction): Promise { + return await this.nodeGraph.refreshBuckets(tran); } } diff --git a/tests/client/rpcVaults.test.ts b/tests/client/rpcVaults.test.ts index 8645e989f..98f4b80af 100644 --- a/tests/client/rpcVaults.test.ts +++ b/tests/client/rpcVaults.test.ts @@ -3,6 +3,7 @@ import type VaultManager from '@/vaults/VaultManager'; import type { VaultId, VaultName } from '@/vaults/types'; import type { ClientServiceClient } from '@/proto/js/polykey/v1/client_service_grpc_pb'; import type { Stat } from 'encryptedfs'; +import type { Host, Port } from '@/network/types'; import os from 'os'; import path from 'path'; import fs from 'fs'; @@ -39,6 +40,8 @@ describe('Vaults client service', () => { 'Vault4' as VaultName, ]; const secretList = ['Secret1', 'Secret2', 'Secret3', 'Secret4']; + const localHost = 'localhost' as Host; + const localPort = 55555 as Port; let client: ClientServiceClient; let server: grpc.Server; @@ -115,6 +118,8 @@ describe('Vaults client service', () => { test('should get vaults', async () => { const listVaults = grpcUtils.promisifyReadableStreamCall( client, + localHost, + localPort, client.vaultsList, ); for (const vaultName of vaultList) { diff --git a/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts b/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts index 09dfaae3b..f20373610 100644 --- a/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts +++ b/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts @@ -73,6 +73,7 @@ describe('gestaltsActionsByIdentity', () => { authenticate, gestaltGraph, logger, + db, }), gestaltsActionsGetByIdentity: gestaltsActionsGetByIdentity({ authenticate, @@ -83,6 +84,7 @@ describe('gestaltsActionsByIdentity', () => { authenticate, gestaltGraph, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsActionsSetUnsetGetByNode.test.ts b/tests/client/service/gestaltsActionsSetUnsetGetByNode.test.ts index cfec8dfda..439f9b754 100644 --- a/tests/client/service/gestaltsActionsSetUnsetGetByNode.test.ts +++ b/tests/client/service/gestaltsActionsSetUnsetGetByNode.test.ts @@ -67,16 +67,19 @@ describe('gestaltsActionsByNode', () => { authenticate, gestaltGraph, logger, + db, }), gestaltsActionsGetByNode: gestaltsActionsGetByNode({ authenticate, gestaltGraph, logger, + db, }), gestaltsActionsUnsetByNode: gestaltsActionsUnsetByNode({ authenticate, gestaltGraph, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsGestaltGetByIdentity.test.ts b/tests/client/service/gestaltsGestaltGetByIdentity.test.ts index cddc5af3f..b6ecc2d71 100644 --- a/tests/client/service/gestaltsGestaltGetByIdentity.test.ts +++ b/tests/client/service/gestaltsGestaltGetByIdentity.test.ts @@ -90,6 +90,7 @@ describe('gestaltsGestaltGetByIdentity', () => { authenticate, gestaltGraph, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsGestaltGetByNode.test.ts b/tests/client/service/gestaltsGestaltGetByNode.test.ts index 2a5848203..1d7a3ceb6 100644 --- a/tests/client/service/gestaltsGestaltGetByNode.test.ts +++ b/tests/client/service/gestaltsGestaltGetByNode.test.ts @@ -87,6 +87,7 @@ describe('gestaltsGestaltGetByNode', () => { authenticate, gestaltGraph, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsGestaltList.test.ts b/tests/client/service/gestaltsGestaltList.test.ts index c724124d7..1075a34f8 100644 --- a/tests/client/service/gestaltsGestaltList.test.ts +++ b/tests/client/service/gestaltsGestaltList.test.ts @@ -93,6 +93,7 @@ describe('gestaltsGestaltList', () => { authenticate, gestaltGraph, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts index ba706add1..ec38cc41d 100644 --- a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts +++ b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts @@ -227,6 +227,7 @@ describe('gestaltsGestaltTrustByIdentity', () => { gestaltGraph, discovery, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/gestaltsGestaltTrustByNode.test.ts b/tests/client/service/gestaltsGestaltTrustByNode.test.ts index 7cb297e67..1c1ad87b0 100644 --- a/tests/client/service/gestaltsGestaltTrustByNode.test.ts +++ b/tests/client/service/gestaltsGestaltTrustByNode.test.ts @@ -226,6 +226,7 @@ describe('gestaltsGestaltTrustByNode', () => { gestaltGraph, discovery, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/identitiesClaim.test.ts b/tests/client/service/identitiesClaim.test.ts index 70185582a..39535394a 100644 --- a/tests/client/service/identitiesClaim.test.ts +++ b/tests/client/service/identitiesClaim.test.ts @@ -150,6 +150,7 @@ describe('identitiesClaim', () => { sigchain, keyManager, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/identitiesTokenPutDeleteGet.test.ts b/tests/client/service/identitiesTokenPutDeleteGet.test.ts index f26eb192b..1752e2f94 100644 --- a/tests/client/service/identitiesTokenPutDeleteGet.test.ts +++ b/tests/client/service/identitiesTokenPutDeleteGet.test.ts @@ -57,16 +57,19 @@ describe('identitiesTokenPutDeleteGet', () => { authenticate, identitiesManager, logger, + db, }), identitiesTokenGet: identitiesTokenGet({ authenticate, identitiesManager, logger, + db, }), identitiesTokenDelete: identitiesTokenDelete({ authenticate, identitiesManager, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/nodesAdd.test.ts b/tests/client/service/nodesAdd.test.ts index aaff85bc3..86923b961 100644 --- a/tests/client/service/nodesAdd.test.ts +++ b/tests/client/service/nodesAdd.test.ts @@ -118,6 +118,7 @@ describe('nodesAdd', () => { authenticate, nodeManager, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/nodesClaim.test.ts b/tests/client/service/nodesClaim.test.ts index bcecd0741..bee8c8ad3 100644 --- a/tests/client/service/nodesClaim.test.ts +++ b/tests/client/service/nodesClaim.test.ts @@ -161,6 +161,7 @@ describe('nodesClaim', () => { nodeManager, notificationsManager, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/notificationsClear.test.ts b/tests/client/service/notificationsClear.test.ts index 62cc7ce63..d8572c584 100644 --- a/tests/client/service/notificationsClear.test.ts +++ b/tests/client/service/notificationsClear.test.ts @@ -136,6 +136,7 @@ describe('notificationsClear', () => { authenticate, notificationsManager, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/notificationsRead.test.ts b/tests/client/service/notificationsRead.test.ts index 393943f5e..73690a54d 100644 --- a/tests/client/service/notificationsRead.test.ts +++ b/tests/client/service/notificationsRead.test.ts @@ -210,6 +210,7 @@ describe('notificationsRead', () => { authenticate, notificationsManager, logger, + db, }), }; grpcServer = new GRPCServer({ logger }); From 3e19974b579e59be6e2e7697b19b528ab41cc381 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 20 May 2022 10:15:20 +1000 Subject: [PATCH 042/137] feat: NodeId in ErrorPolykeyRemote data now encoded --- src/grpc/utils/utils.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/grpc/utils/utils.ts b/src/grpc/utils/utils.ts index 4b7335fd5..f99331585 100644 --- a/src/grpc/utils/utils.ts +++ b/src/grpc/utils/utils.ts @@ -35,6 +35,7 @@ import * as grpc from '@grpc/grpc-js'; import * as grpcErrors from '../errors'; import * as errors from '../../errors'; import * as networkUtils from '../../network/utils'; +import * as nodesUtils from '../../nodes/utils'; import { promisify, promise, never } from '../../utils/utils'; /** @@ -375,6 +376,9 @@ function promisifyUnaryCall( const { p: pMeta, resolveP: resolveMetaP } = promise(); const callback = (error: ServiceError, ...values) => { if (error != null) { + if ('nodeId' in metadata) { + metadata.nodeId = nodesUtils.encodeNodeId(metadata.nodeId); + } error.metadata.set('metadata', JSON.stringify(metadata)); rejectP(toError(error)); return; @@ -422,6 +426,9 @@ function generatorReadable( if (!('port' in metadata) && peerAddress != null) { metadata.port = networkUtils.parseAddress(peerAddress[0])[1]; } + if ('nodeId' in metadata) { + metadata.nodeId = nodesUtils.encodeNodeId(metadata.nodeId); + } const gf = async function* () { try { let vR = yield; @@ -548,6 +555,9 @@ function promisifyWritableStreamCall( }; const callback = (error, ...values) => { if (error != null) { + if ('nodeId' in metadata) { + metadata.nodeId = nodesUtils.encodeNodeId(metadata.nodeId); + } error.metadata.set('metadata', JSON.stringify(metadata)); return rejectP(toError(error)); } From e56f79ea6eecb89c4494418285418415aec0e9ce Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 20 May 2022 16:08:10 +1000 Subject: [PATCH 043/137] feat: updated `NodeConnectionManager`'s resourceAcquire to handle errors properly Making use of the updated API to use the error provided to the resourceRelease. --- src/nodes/NodeConnectionManager.ts | 65 +++++++++++++----------------- 1 file changed, 27 insertions(+), 38 deletions(-) diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 812b18832..9f7632d2f 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -138,8 +138,16 @@ class NodeConnectionManager { connAndLock.timer?.refresh(); // Return tuple of [ResourceRelease, Resource] return [ - async () => { + async (e) => { await release(); + if ( + e instanceof nodesErrors.ErrorNodeConnectionDestroyed || + e instanceof grpcErrors.ErrorGRPC || + e instanceof agentErrors.ErrorAgentClientDestroyed + ) { + // Error with connection, shutting connection down + await this.destroyConnection(targetNodeId); + } }, connAndLock.connection, ]; @@ -159,29 +167,17 @@ class NodeConnectionManager { targetNodeId: NodeId, f: (conn: NodeConnection) => Promise, ): Promise { - try { - return await withF( - [await this.acquireConnection(targetNodeId)], - async ([conn]) => { - this.logger.info( - `withConnF calling function with connection to ${nodesUtils.encodeNodeId( - targetNodeId, - )}`, - ); - return await f(conn); - }, - ); - } catch (err) { - if ( - err instanceof nodesErrors.ErrorNodeConnectionDestroyed || - err instanceof grpcErrors.ErrorGRPC || - err instanceof agentErrors.ErrorAgentClientDestroyed - ) { - // Error with connection, shutting connection down - await this.destroyConnection(targetNodeId); - } - throw err; - } + return await withF( + [await this.acquireConnection(targetNodeId)], + async ([conn]) => { + this.logger.info( + `withConnF calling function with connection to ${nodesUtils.encodeNodeId( + targetNodeId, + )}`, + ); + return await f(conn); + }, + ); } /** @@ -201,21 +197,14 @@ class NodeConnectionManager { ): AsyncGenerator { const acquire = await this.acquireConnection(targetNodeId); const [release, conn] = await acquire(); + let caughtError; try { return yield* await g(conn!); - } catch (err) { - if ( - err instanceof nodesErrors.ErrorNodeConnectionDestroyed || - err instanceof grpcErrors.ErrorGRPC || - err instanceof agentErrors.ErrorAgentClientDestroyed - ) { - // Error with connection, shutting connection down - await release(); - await this.destroyConnection(targetNodeId); - } - throw err; + } catch (e) { + caughtError = e; + throw e; } finally { - await release(); + await release(caughtError); } // Wait for any destruction to complete after locking is removed } @@ -310,7 +299,7 @@ class NodeConnectionManager { ); // If the connection is calling destroyCallback then it SHOULD // exist in the connection map - if (connAndLock == null) throw Error('temp error, bad logic'); + if (connAndLock == null) throw Error('temp eor, bad logic'); // Already locked so already destroying if (connAndLock.lock.readerCount > 0) return; const connectionStatus = connAndLock?.connection?.[status]; @@ -507,7 +496,7 @@ class NodeConnectionManager { this.initialClosestNodes, ); // If we have no nodes at all in our database (even after synchronising), - // then we should throw an error. We aren't going to find any others + // then we should throw an eor. We aren't going to find any others if (shortlist.length === 0) { throw new nodesErrors.ErrorNodeGraphEmptyDatabase(); } From 055c52660dd067d674fdf785d28b19cf1d614abd Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 20 May 2022 18:39:23 +1000 Subject: [PATCH 044/137] feat: updated `NodeConnectionManager` to use `LockBox` for object map locking Using `LockBox` allowed us to greatly simplify using the object map and creating connections. --- src/nodes/NodeConnectionManager.ts | 246 +++++++----------- .../NodeConnectionManager.lifecycle.test.ts | 167 +++++------- .../NodeConnectionManager.termination.test.ts | 60 +++-- .../NodeConnectionManager.timeout.test.ts | 32 +-- 4 files changed, 218 insertions(+), 287 deletions(-) diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 9f7632d2f..e51ccc803 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -5,19 +5,19 @@ import type { Host, Hostname, Port } from '../network/types'; import type { Timer } from '../types'; import type NodeGraph from './NodeGraph'; import type { - NodeId, NodeAddress, NodeData, - SeedNodes, + NodeId, NodeIdString, + SeedNodes, } from './types'; import type { DBTransaction } from '@matrixai/db'; +import { withF } from '@matrixai/resources'; import Logger from '@matrixai/logger'; -import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; +import { ready, StartStop } from '@matrixai/async-init/dist/StartStop'; import { IdInternal } from '@matrixai/id'; import { status } from '@matrixai/async-init'; -import { withF } from '@matrixai/resources'; -import { RWLockWriter } from '@matrixai/async-locks'; +import { LockBox, RWLockWriter } from '@matrixai/async-locks'; import NodeConnection from './NodeConnection'; import * as nodesUtils from './utils'; import * as nodesErrors from './errors'; @@ -28,17 +28,16 @@ import * as agentErrors from '../agent/errors'; import * as grpcErrors from '../grpc/errors'; import * as nodesPB from '../proto/js/polykey/v1/nodes/nodes_pb'; -type ConnectionAndLock = { - connection?: NodeConnection; - timer?: NodeJS.Timer; - lock: RWLockWriter; +type ConnectionAndTimer = { + connection: NodeConnection; + timer: NodeJS.Timer; }; interface NodeConnectionManager extends StartStop {} @StartStop() class NodeConnectionManager { /** - * Time used to estalish `NodeConnection` + * Time used to establish `NodeConnection` */ public readonly connConnectTime: number; @@ -48,7 +47,7 @@ class NodeConnectionManager { public readonly connTimeoutTime: number; /** * Alpha constant for kademlia - * The number of closest nodes to contact initially + * The number of the closest nodes to contact initially */ public readonly initialClosestNodes: number; @@ -67,7 +66,8 @@ class NodeConnectionManager { * A nodeIdString is used for the key here since * NodeIds can't be used to properly retrieve a value from the map. */ - protected connections: Map = new Map(); + protected connections: Map = new Map(); + protected connectionLocks: LockBox = new LockBox(); public constructor({ keyManager, @@ -119,7 +119,7 @@ class NodeConnectionManager { } /** - * For usage with withF, to acquire a connection in a + * For usage with withF, to acquire a connection * This unique acquire function structure of returning the ResourceAcquire * itself is such that we can pass targetNodeId as a parameter (as opposed to * an acquire function with no parameters). @@ -131,11 +131,15 @@ class NodeConnectionManager { targetNodeId: NodeId, ): Promise>> { return async () => { - const connAndLock = await this.getConnection(targetNodeId); + const { connection, timer } = await this.getConnection(targetNodeId); // Acquire the read lock and the release function - const [release] = await connAndLock.lock.read()(); + const [release] = await this.connectionLocks.lock([ + targetNodeId.toString(), + RWLockWriter, + 'write', + ])(); // Resetting TTL timer - connAndLock.timer?.refresh(); + timer?.refresh(); // Return tuple of [ResourceRelease, Resource] return [ async (e) => { @@ -149,7 +153,7 @@ class NodeConnectionManager { await this.destroyConnection(targetNodeId); } }, - connAndLock.connection, + connection, ]; }; } @@ -213,127 +217,82 @@ class NodeConnectionManager { * Create a connection to another node (without performing any function). * This is a NOOP if a connection already exists. * @param targetNodeId Id of node we are creating connection to - * @returns ConnectionAndLock that was create or exists in the connection map. + * @returns ConnectionAndLock that was created or exists in the connection map. */ protected async getConnection( targetNodeId: NodeId, - ): Promise { + ): Promise { this.logger.info( `Getting connection to ${nodesUtils.encodeNodeId(targetNodeId)}`, ); - let connection: NodeConnection | undefined; - let lock: RWLockWriter; - let connAndLock = this.connections.get( - targetNodeId.toString() as NodeIdString, - ); - if (connAndLock != null) { - ({ connection, lock } = connAndLock); - // Connection already exists, so return - if (connection != null) return connAndLock; - // Acquire the write (creation) lock - return await lock.withWriteF(async () => { - // Once lock is released, check again if the conn now exists - connAndLock = this.connections.get( - targetNodeId.toString() as NodeIdString, - ); - if (connAndLock != null && connAndLock.connection != null) { + const targetNodeIdString = targetNodeId.toString() as NodeIdString; + return await this.connectionLocks.withF( + [targetNodeIdString, RWLockWriter, 'write'], + async () => { + const connAndTimer = this.connections.get(targetNodeIdString); + if (connAndTimer != null) { this.logger.info( `existing entry found for ${nodesUtils.encodeNodeId(targetNodeId)}`, ); - return connAndLock; + return connAndTimer; } - this.logger.info( - `existing lock, creating connection to ${nodesUtils.encodeNodeId( - targetNodeId, - )}`, - ); - // Creating the connection and set in map - return await this.establishNodeConnection(targetNodeId, lock); - }); - } else { - lock = new RWLockWriter(); - connAndLock = { lock }; - this.connections.set( - targetNodeId.toString() as NodeIdString, - connAndLock, - ); - return await lock.withWriteF(async () => { this.logger.info( `no existing entry, creating connection to ${nodesUtils.encodeNodeId( targetNodeId, )}`, ); // Creating the connection and set in map - return await this.establishNodeConnection(targetNodeId, lock); - }); - } - } + const targetAddress = await this.findNode(targetNodeId); + // If the stored host is not a valid host (IP address), + // then we assume it to be a hostname + const targetHostname = !networkUtils.isHost(targetAddress.host) + ? (targetAddress.host as string as Hostname) + : undefined; + const targetHost = await networkUtils.resolveHost(targetAddress.host); + // Creating the destroyCallback + const destroyCallback = async () => { + // To avoid deadlock only in the case where this is called + // we want to check for destroying connection and read lock + const connAndTimer = this.connections.get(targetNodeIdString); + // If the connection is calling destroyCallback then it SHOULD + // exist in the connection map + if (connAndTimer == null) return; + // Already locked so already destroying + if (this.connectionLocks.isLocked(targetNodeIdString)) return; + // Connection is already destroying + if (connAndTimer?.connection?.[status] === 'destroying') return; + await this.destroyConnection(targetNodeId); + }; + // Creating new connection + const newConnection = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: targetHost, + targetHostname: targetHostname, + targetPort: targetAddress.port, + proxy: this.proxy, + keyManager: this.keyManager, + nodeConnectionManager: this, + destroyCallback, + connConnectTime: this.connConnectTime, + logger: this.logger.getChild( + `${NodeConnection.name} ${targetHost}:${targetAddress.port}`, + ), + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + }); + // Creating TTL timeout + const timer = setTimeout(async () => { + await this.destroyConnection(targetNodeId); + }, this.connTimeoutTime); - /** - * Strictly a helper function for this.createConnection. Do not call this - * function anywhere else. - * To create a connection to a node, always use createConnection, or - * withConnection. - * This only adds the connection to the connection map if the connection was established. - * @param targetNodeId Id of node we are establishing connection to - * @param lock Lock associated with connection - * @returns ConnectionAndLock that was added to the connection map - */ - protected async establishNodeConnection( - targetNodeId: NodeId, - lock: RWLockWriter, - ): Promise { - const targetAddress = await this.findNode(targetNodeId); - // If the stored host is not a valid host (IP address), then we assume it to - // be a hostname - const targetHostname = !networkUtils.isHost(targetAddress.host) - ? (targetAddress.host as string as Hostname) - : undefined; - const targetHost = await networkUtils.resolveHost(targetAddress.host); - // Creating the destroyCallback - const destroyCallback = async () => { - // To avoid deadlock only in the case where this is called - // we want to check for destroying connection and read lock - const connAndLock = this.connections.get( - targetNodeId.toString() as NodeIdString, - ); - // If the connection is calling destroyCallback then it SHOULD - // exist in the connection map - if (connAndLock == null) throw Error('temp eor, bad logic'); - // Already locked so already destroying - if (connAndLock.lock.readerCount > 0) return; - const connectionStatus = connAndLock?.connection?.[status]; - // Connection is already destroying - if (connectionStatus === 'destroying') return; - await this.destroyConnection(targetNodeId); - }; - const connection = await NodeConnection.createNodeConnection({ - targetNodeId: targetNodeId, - targetHost: targetHost, - targetHostname: targetHostname, - targetPort: targetAddress.port, - proxy: this.proxy, - keyManager: this.keyManager, - nodeConnectionManager: this, - destroyCallback, - connConnectTime: this.connConnectTime, - logger: this.logger.getChild( - `${NodeConnection.name} ${targetHost}:${targetAddress.port}`, - ), - clientFactory: async (args) => - GRPCClientAgent.createGRPCClientAgent(args), - }); - // Creating TTL timeout - const timer = setTimeout(async () => { - await this.destroyConnection(targetNodeId); - }, this.connTimeoutTime); - // Add it to the map of active connections - const connectionAndLock = { connection, lock, timer }; - this.connections.set( - targetNodeId.toString() as NodeIdString, - connectionAndLock, + const newConnAndTimer: ConnectionAndTimer = { + connection: newConnection, + timer: timer, + }; + this.connections.set(targetNodeIdString, newConnAndTimer); + return newConnAndTimer; + }, ); - return connectionAndLock; } /** @@ -341,23 +300,19 @@ class NodeConnectionManager { * @param targetNodeId Id of node we are destroying connection to */ protected async destroyConnection(targetNodeId: NodeId): Promise { - const connAndLock = this.connections.get( - targetNodeId.toString() as NodeIdString, + const targetNodeIdString = targetNodeId.toString() as NodeIdString; + return await this.connectionLocks.withF( + [targetNodeIdString, RWLockWriter, 'write'], + async () => { + const connAndTimer = this.connections.get(targetNodeIdString); + if (connAndTimer?.connection == null) return; + await connAndTimer.connection.destroy(); + // Destroying TTL timer + if (connAndTimer.timer != null) clearTimeout(connAndTimer.timer); + // Updating the connection map + this.connections.delete(targetNodeIdString); + }, ); - if (connAndLock == null) return; - const connection = connAndLock.connection; - if (connection == null) return; - const lock = connAndLock.lock; - - // If the connection exists then we lock, destroy and remove it from the map - await lock.withWriteF(async () => { - // Destroying connection - await connection.destroy(); - // Destroying TTL timer - if (connAndLock.timer != null) clearTimeout(connAndLock.timer); - // Updating the connection map - this.connections.set(targetNodeId.toString() as NodeIdString, { lock }); - }); } /** @@ -389,7 +344,7 @@ class NodeConnectionManager { * sends hole-punching packets back to the server's reverse proxy. * This is not needed to be called when doing hole punching since the * ForwardProxy automatically starts the process. - * @param nodeId Node Id of the node we are connecting to + * @param nodeId Node ID of the node we are connecting to * @param proxyHost Proxy host of the reverse proxy * @param proxyPort Proxy port of the reverse proxy * @param timer Connection timeout timer @@ -429,14 +384,14 @@ class NodeConnectionManager { /** * Finds the set of nodes (of size k) known by the current node (i.e. in its - * buckets database) that have the smallest distance to the target node (i.e. + * bucket's database) that have the smallest distance to the target node (i.e. * are closest to the target node). * i.e. FIND_NODE RPC from Kademlia spec * * Used by the RPC service. * * @param targetNodeId the node ID to find other nodes closest to it - * @param numClosest the number of closest nodes to return (by default, returns + * @param numClosest the number of the closest nodes to return (by default, returns * according to the maximum number of nodes per bucket) * @param tran * @returns a mapping containing exactly k nodeIds -> nodeAddresses (unless the @@ -451,7 +406,7 @@ class NodeConnectionManager { ): Promise> { // Retrieve all nodes from buckets in database const buckets = await this.nodeGraph.getAllBuckets(tran); - // Iterate over all of the nodes in each bucket + // Iterate over all the nodes in each bucket const distanceToNodes: Array = []; buckets.forEach(function (bucket) { for (const nodeIdString of Object.keys(bucket)) { @@ -505,7 +460,7 @@ class NodeConnectionManager { // in nodeConnections - what if there's been more than 1 invocation of // getClosestGlobalNodes()? const contacted: { [nodeId: string]: boolean } = {}; - // Iterate until we've found found and contacted k nodes + // Iterate until we've found and contacted k nodes while (Object.keys(contacted).length <= this.nodeGraph.maxNodesPerBucket) { // While (!foundTarget) { // Remove the node from the front of the array @@ -553,7 +508,7 @@ class NodeConnectionManager { } // To make the number of jumps relatively short, should connect to the nodes // closest to the target first, and ask if they know of any closer nodes - // Then we can simply unshift the first (closest) element from the shortlist + // than we can simply unshift the first (closest) element from the shortlist shortlist.sort(function (a: NodeData, b: NodeData) { if (a.distance > b.distance) { return 1; @@ -607,7 +562,7 @@ class NodeConnectionManager { } /** - * Perform an initial database synchronisation: get the k closest nodes + * Perform an initial database synchronisation: get k of the closest nodes * from each seed node and add them to this database * For now, we also attempt to establish a connection to each of them. * If these nodes are offline, this will impose a performance penalty, @@ -646,7 +601,7 @@ class NodeConnectionManager { * @param relayNodeId node ID of the relay node (i.e. the seed node) * @param sourceNodeId node ID of the current node (i.e. the sender) * @param targetNodeId node ID of the target node to hole punch - * @param proxyAddress stringified address of `proxyHost:proxyPort` + * @param proxyAddress string of address in the form `proxyHost:proxyPort` * @param signature signature to verify source node is sender (signature based * on proxyAddress as message) */ @@ -693,10 +648,9 @@ class NodeConnectionManager { */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) public getSeedNodes(): Array { - const nodeIds = Object.keys(this.seedNodes).map( + return Object.keys(this.seedNodes).map( (nodeIdEncoded) => nodesUtils.decodeNodeId(nodeIdEncoded)!, ); - return nodeIds; } } diff --git a/tests/nodes/NodeConnectionManager.lifecycle.test.ts b/tests/nodes/NodeConnectionManager.lifecycle.test.ts index 66961ca1a..6117ddc41 100644 --- a/tests/nodes/NodeConnectionManager.lifecycle.test.ts +++ b/tests/nodes/NodeConnectionManager.lifecycle.test.ts @@ -78,6 +78,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { let remoteNode1: PolykeyAgent; let remoteNode2: PolykeyAgent; let remoteNodeId1: NodeId; + let remoteNodeIdString1: NodeIdString; let remoteNodeId2: NodeId; const mockedGenerateDeterministicKeyPair = jest.spyOn( @@ -103,6 +104,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { logger: logger.getChild('remoteNode1'), }); remoteNodeId1 = remoteNode1.keyManager.getNodeId(); + remoteNodeIdString1 = remoteNodeId1.toString() as NodeIdString; remoteNode2 = await PolykeyAgent.createPolykeyAgent({ password, nodePath: path.join(dataDir2, 'remoteNode2'), @@ -197,17 +199,15 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { await nodeConnectionManager.start(); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; - const initialConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); - expect(initialConnLock).toBeUndefined(); + // @ts-ignore: kidnap connectionLocks + const connectionLocks = nodeConnectionManager.connectionLocks; + const initialConnection = connections.get(remoteNodeIdString1); + expect(initialConnection).toBeUndefined(); await nodeConnectionManager.withConnF(remoteNodeId1, nop); - const finalConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); + const finalConnection = connections.get(remoteNodeIdString1); // Check entry is in map and lock is released - expect(finalConnLock).toBeDefined(); - expect(finalConnLock?.lock.isLocked()).toBeFalsy(); + expect(finalConnection).toBeDefined(); + expect(connectionLocks.isLocked(remoteNodeIdString1)).toBeFalsy(); } finally { await nodeConnectionManager?.stop(); } @@ -224,32 +224,23 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { await nodeConnectionManager.start(); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; - const initialConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); - expect(initialConnLock).toBeUndefined(); + // @ts-ignore: kidnap connectionLocks + const connectionLocks = nodeConnectionManager.connectionLocks; + const initialConnection = connections.get(remoteNodeIdString1); + expect(initialConnection).toBeUndefined(); await withF( [await nodeConnectionManager.acquireConnection(remoteNodeId1)], async (conn) => { expect(conn).toBeDefined(); - const intermediaryConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); - expect(intermediaryConnLock).toBeDefined(); - expect( - // @ts-ignore get the protected readersLock - intermediaryConnLock?.lock.readersLock.isLocked(), - ).toBeTruthy(); - // @ts-ignore get the protected writersLock - expect(intermediaryConnLock?.lock.writersLock.isLocked()).toBeFalsy(); + const intermediaryConnection = connections.get(remoteNodeIdString1); + expect(intermediaryConnection).toBeDefined(); + expect(connectionLocks.isLocked(remoteNodeIdString1)).toBeTruthy(); }, ); - const finalConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); - expect(finalConnLock).toBeDefined(); + const finalConnection = connections.get(remoteNodeIdString1); + expect(finalConnection).toBeDefined(); // Neither write nor read lock should be locked now - expect(finalConnLock?.lock.isLocked()).toBeFalsy(); + expect(connectionLocks.isLocked(remoteNodeIdString1)).toBeFalsy(); } finally { await nodeConnectionManager?.stop(); } @@ -267,23 +258,17 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { await nodeConnectionManager.start(); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; - const initialConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); - expect(initialConnLock).toBeUndefined(); + // @ts-ignore: kidnap connectionLocks + const connectionLocks = nodeConnectionManager.connectionLocks; + const initialConnection = connections.get(remoteNodeIdString1); + expect(initialConnection).toBeUndefined(); await nodeConnectionManager.withConnF(remoteNodeId1, async () => { - expect( - connections - .get(remoteNodeId1.toString() as NodeIdString) - ?.lock?.isLocked(), - ).toBe(true); + expect(connectionLocks.isLocked(remoteNodeIdString1)).toBe(true); }); - const finalConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); + const finalConnection = connections.get(remoteNodeIdString1); // Check entry is in map and lock is released - expect(finalConnLock).toBeDefined(); - expect(finalConnLock?.lock.isLocked()).toBeFalsy(); + expect(finalConnection).toBeDefined(); + expect(connectionLocks.isLocked(remoteNodeIdString1)).toBeFalsy(); } finally { await nodeConnectionManager?.stop(); } @@ -302,10 +287,10 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; - const initialConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); - expect(initialConnLock).toBeUndefined(); + // @ts-ignore: kidnap connectionLocks + const connectionLocks = nodeConnectionManager.connectionLocks; + const initialConnection = connections.get(remoteNodeIdString1); + expect(initialConnection).toBeUndefined(); const testGenerator = async function* () { for (let i = 0; i < 10; i++) { @@ -322,32 +307,20 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { ); // Connection is not created yet, no locking applied - expect( - connections.get(remoteNodeId1.toString() as NodeIdString), - ).not.toBeDefined(); + expect(connections.get(remoteNodeIdString1)).not.toBeDefined(); // Iterating over generator for await (const _ of gen) { // Should be locked for duration of stream - expect( - connections - .get(remoteNodeId1.toString() as NodeIdString) - ?.lock?.isLocked(), - ).toBe(true); + expect(connectionLocks.isLocked(remoteNodeIdString1)).toBe(true); } // Unlocked after stream finished - expect( - connections - .get(remoteNodeId1.toString() as NodeIdString) - ?.lock?.isLocked(), - ).toBe(false); + expect(connectionLocks.isLocked(remoteNodeIdString1)).toBe(false); - const finalConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); + const finalConnection = connections.get(remoteNodeIdString1); // Check entry is in map and lock is released - expect(finalConnLock).toBeDefined(); - expect(finalConnLock?.lock.isLocked()).toBe(false); + expect(finalConnection).toBeDefined(); + expect(connectionLocks.isLocked(remoteNodeIdString1)).toBe(false); } finally { await nodeConnectionManager?.stop(); } @@ -371,17 +344,21 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { }); // @ts-ignore: kidnap connection map const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnap connectionLocks + const connectionLocks = nodeConnectionManager.connectionLocks; expect(connections.size).toBe(0); await expect(() => nodeConnectionManager?.withConnF(dummyNodeId, nop), ).rejects.toThrow(nodesErrors.ErrorNodeConnectionTimeout); - expect(connections.size).toBe(1); + expect(connections.size).toBe(0); const connLock = connections.get(dummyNodeId.toString() as NodeIdString); // There should still be an entry in the connection map, but it should // only contain a lock - no connection - expect(connLock).toBeDefined(); - expect(connLock?.lock).toBeDefined(); + expect(connLock).not.toBeDefined(); + expect( + connectionLocks.isLocked(dummyNodeId.toString() as NodeIdString), + ).toBe(false); expect(connLock?.connection).toBeUndefined(); // Undo the initial dummy node add @@ -403,10 +380,8 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { // @ts-ignore accessing protected NodeConnectionMap const connections = nodeConnectionManager.connections; expect(connections.size).toBe(0); - const initialConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); - expect(initialConnLock).toBeUndefined(); + const initialConnection = connections.get(remoteNodeIdString1); + expect(initialConnection).toBeUndefined(); await nodeConnectionManager.withConnF(remoteNodeId1, nop); // Check we only have this single connection expect(connections.size).toBe(1); @@ -430,11 +405,11 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { await nodeConnectionManager.start(); // @ts-ignore accessing protected NodeConnectionMap const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnap connectionLocks + const connectionLocks = nodeConnectionManager.connectionLocks; expect(connections.size).toBe(0); - const initialConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); - expect(initialConnLock).toBeUndefined(); + const initialConnection = connections.get(remoteNodeIdString1); + expect(initialConnection).toBeUndefined(); // Concurrently create connection to same target await Promise.all([ nodeConnectionManager.withConnF(remoteNodeId1, nop), @@ -442,12 +417,10 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { ]); // Check only 1 connection exists expect(connections.size).toBe(1); - const finalConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); + const finalConnection = connections.get(remoteNodeIdString1); // Check entry is in map and lock is released - expect(finalConnLock).toBeDefined(); - expect(finalConnLock?.lock.isLocked()).toBeFalsy(); + expect(finalConnection).toBeDefined(); + expect(connectionLocks.isLocked(remoteNodeIdString1)).toBeFalsy(); } finally { await nodeConnectionManager?.stop(); } @@ -465,26 +438,22 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { await nodeConnectionManager.start(); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; - const initialConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); - expect(initialConnLock).toBeUndefined(); + // @ts-ignore: kidnap connectionLocks + const connectionLocks = nodeConnectionManager.connectionLocks; + const initialConnection = connections.get(remoteNodeIdString1); + expect(initialConnection).toBeUndefined(); await nodeConnectionManager.withConnF(remoteNodeId1, nop); - const midConnAndLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); + const midConnAndLock = connections.get(remoteNodeIdString1); // Check entry is in map and lock is released expect(midConnAndLock).toBeDefined(); - expect(midConnAndLock?.lock.isLocked()).toBeFalsy(); + expect(connectionLocks.isLocked(remoteNodeIdString1)).toBeFalsy(); // Destroying the connection // @ts-ignore: private method await nodeConnectionManager.destroyConnection(remoteNodeId1); - const finalConnAndLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); - expect(finalConnAndLock).toBeDefined(); - expect(finalConnAndLock?.lock.isLocked()).toBeFalsy(); + const finalConnAndLock = connections.get(remoteNodeIdString1); + expect(finalConnAndLock).not.toBeDefined(); + expect(connectionLocks.isLocked(remoteNodeIdString1)).toBeFalsy(); expect(finalConnAndLock?.connection).toBeUndefined(); } finally { await nodeConnectionManager?.stop(); @@ -507,20 +476,22 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { // @ts-ignore: Hijack connection map const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnap connectionLocks + const connectionLocks = nodeConnectionManager.connectionLocks; expect(connections.size).toBe(2); - for (const [, connAndLock] of connections) { + for (const [nodeIdString, connAndLock] of connections) { expect(connAndLock.connection).toBeDefined(); expect(connAndLock.timer).toBeDefined(); - expect(connAndLock.lock).toBeDefined(); + expect(connectionLocks.isLocked(nodeIdString)).toBeDefined(); } // Destroying connections await nodeConnectionManager.stop(); - expect(connections.size).toBe(2); - for (const [, connAndLock] of connections) { + expect(connections.size).toBe(0); + for (const [nodeIdString, connAndLock] of connections) { expect(connAndLock.connection).toBeUndefined(); expect(connAndLock.timer).toBeUndefined(); - expect(connAndLock.lock).toBeDefined(); + expect(connectionLocks.isLocked(nodeIdString)).toBeDefined(); } } finally { // Clean up diff --git a/tests/nodes/NodeConnectionManager.termination.test.ts b/tests/nodes/NodeConnectionManager.termination.test.ts index 7cc443d07..3fa14f66c 100644 --- a/tests/nodes/NodeConnectionManager.termination.test.ts +++ b/tests/nodes/NodeConnectionManager.termination.test.ts @@ -377,6 +377,8 @@ describe(`${NodeConnectionManager.name} termination test`, () => { // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnapping connection map + const connectionLocks = nodeConnectionManager.connectionLocks; // Connections should be empty expect(connections.size).toBe(0); @@ -392,10 +394,9 @@ describe(`${NodeConnectionManager.name} termination test`, () => { await polykeyAgent.stop(); // Connection should be removed expect(connections.size).toBe(1); - const connAndLock = connections.get( - agentNodeId.toString() as NodeIdString, - ); - expect(connAndLock?.lock.isLocked()).toBe(false); + expect( + connectionLocks.isLocked(agentNodeId.toString() as NodeIdString), + ).toBe(false); if (firstConnection != null) { expect(firstConnection[destroyed]).toBe(true); } @@ -433,6 +434,8 @@ describe(`${NodeConnectionManager.name} termination test`, () => { // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnapping connection map + const connectionLocks = nodeConnectionManager.connectionLocks; // Connections should be empty expect(connections.size).toBe(0); @@ -464,11 +467,10 @@ describe(`${NodeConnectionManager.name} termination test`, () => { await expect(withConnectionP).rejects.toThrow(); // Connection should be removed - expect(connections.size).toBe(1); - const connAndLock = connections.get( - agentNodeId.toString() as NodeIdString, - ); - expect(connAndLock?.lock.isLocked()).toBe(false); + expect(connections.size).toBe(0); + expect( + connectionLocks.isLocked(agentNodeId.toString() as NodeIdString), + ).toBe(false); if (firstConnection != null) { expect(firstConnection[destroyed]).toBe(true); } @@ -511,6 +513,8 @@ describe(`${NodeConnectionManager.name} termination test`, () => { // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnapping connection map + const connectionLocks = nodeConnectionManager.connectionLocks; // Connections should be empty expect(connections.size).toBe(0); @@ -540,11 +544,10 @@ describe(`${NodeConnectionManager.name} termination test`, () => { await expect(responseP).rejects.toThrow(); // Connection should be removed - expect(connections.size).toBe(1); - const connAndLock = connections.get( - agentNodeId.toString() as NodeIdString, - ); - expect(connAndLock?.lock.isLocked()).toBe(false); + expect(connections.size).toBe(0); + expect( + connectionLocks.isLocked(agentNodeId.toString() as NodeIdString), + ).toBe(false); if (firstConnection != null) { expect(firstConnection[destroyed]).toBe(true); } @@ -582,6 +585,8 @@ describe(`${NodeConnectionManager.name} termination test`, () => { // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnapping connection map + const connectionLocks = nodeConnectionManager.connectionLocks; // Connections should be empty expect(connections.size).toBe(0); @@ -616,11 +621,10 @@ describe(`${NodeConnectionManager.name} termination test`, () => { }).rejects.toThrow(); // Connection should be removed - expect(connections.size).toBe(1); - const connAndLock = connections.get( - agentNodeId.toString() as NodeIdString, - ); - expect(connAndLock?.lock.isLocked()).toBe(false); + expect(connections.size).toBe(0); + expect( + connectionLocks.isLocked(agentNodeId.toString() as NodeIdString), + ).toBe(false); if (firstConnection != null) { expect(firstConnection[destroyed]).toBe(true); } @@ -658,6 +662,8 @@ describe(`${NodeConnectionManager.name} termination test`, () => { // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnapping connection map + const connectionLocks = nodeConnectionManager.connectionLocks; // Connections should be empty expect(connections.size).toBe(0); @@ -693,10 +699,9 @@ describe(`${NodeConnectionManager.name} termination test`, () => { // Connection should be removed expect(connections.size).toBe(1); - const connAndLock = connections.get( - agentNodeId.toString() as NodeIdString, - ); - expect(connAndLock?.lock.isLocked()).toBe(false); + expect( + connectionLocks.isLocked(agentNodeId.toString() as NodeIdString), + ).toBe(false); if (firstConnection != null) { expect(firstConnection[destroyed]).toBe(true); } @@ -734,6 +739,8 @@ describe(`${NodeConnectionManager.name} termination test`, () => { // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnapping connection map + const connectionLocks = nodeConnectionManager.connectionLocks; // Connections should be empty expect(connections.size).toBe(0); @@ -763,10 +770,9 @@ describe(`${NodeConnectionManager.name} termination test`, () => { // Connection should be removed expect(connections.size).toBe(1); - const connAndLock = connections.get( - agentNodeId.toString() as NodeIdString, - ); - expect(connAndLock?.lock.isLocked()).toBe(false); + expect( + connectionLocks.isLocked(agentNodeId.toString() as NodeIdString), + ).toBe(false); if (firstConnection != null) { expect(firstConnection[destroyed]).toBe(true); } diff --git a/tests/nodes/NodeConnectionManager.timeout.test.ts b/tests/nodes/NodeConnectionManager.timeout.test.ts index 5e48eaaaf..7b93b596d 100644 --- a/tests/nodes/NodeConnectionManager.timeout.test.ts +++ b/tests/nodes/NodeConnectionManager.timeout.test.ts @@ -192,13 +192,15 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { await nodeConnectionManager.start(); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnap connections + const connectionLocks = nodeConnectionManager.connectionLocks; await nodeConnectionManager.withConnF(remoteNodeId1, nop); const connAndLock = connections.get( remoteNodeId1.toString() as NodeIdString, ); // Check entry is in map and lock is released expect(connAndLock).toBeDefined(); - expect(connAndLock?.lock.isLocked()).toBeFalsy(); + expect(connectionLocks.isLocked(remoteNodeId1.toString())).toBeFalsy(); expect(connAndLock?.timer).toBeDefined(); expect(connAndLock?.connection).toBeDefined(); @@ -207,10 +209,8 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { const finalConnAndLock = connections.get( remoteNodeId1.toString() as NodeIdString, ); - expect(finalConnAndLock).toBeDefined(); - expect(finalConnAndLock?.lock.isLocked()).toBeFalsy(); - expect(finalConnAndLock?.timer).toBeUndefined(); - expect(finalConnAndLock?.connection).toBeUndefined(); + expect(finalConnAndLock).not.toBeDefined(); + expect(connectionLocks.isLocked(remoteNodeId1.toString())).toBeFalsy(); } finally { await nodeConnectionManager?.stop(); } @@ -229,13 +229,15 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { await nodeConnectionManager.start(); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnap connections + const connectionLocks = nodeConnectionManager.connectionLocks; await nodeConnectionManager.withConnF(remoteNodeId1, nop); const connAndLock = connections.get( remoteNodeId1.toString() as NodeIdString, ); // Check entry is in map and lock is released expect(connAndLock).toBeDefined(); - expect(connAndLock?.lock.isLocked()).toBeFalsy(); + expect(connectionLocks.isLocked(remoteNodeId1.toString())).toBeFalsy(); expect(connAndLock?.timer).toBeDefined(); expect(connAndLock?.connection).toBeDefined(); @@ -251,7 +253,7 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { remoteNodeId1.toString() as NodeIdString, ); expect(midConnAndLock).toBeDefined(); - expect(midConnAndLock?.lock.isLocked()).toBeFalsy(); + expect(connectionLocks.isLocked(remoteNodeId1.toString())).toBeFalsy(); expect(midConnAndLock?.timer).toBeDefined(); expect(midConnAndLock?.connection).toBeDefined(); @@ -260,10 +262,8 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { const finalConnAndLock = connections.get( remoteNodeId1.toString() as NodeIdString, ); - expect(finalConnAndLock).toBeDefined(); - expect(finalConnAndLock?.lock.isLocked()).toBeFalsy(); - expect(finalConnAndLock?.timer).toBeUndefined(); - expect(finalConnAndLock?.connection).toBeUndefined(); + expect(finalConnAndLock).not.toBeDefined(); + expect(connectionLocks.isLocked(remoteNodeId1.toString())).toBeFalsy(); } finally { await nodeConnectionManager?.stop(); } @@ -281,13 +281,15 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { await nodeConnectionManager.start(); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; + // @ts-ignore: kidnap connections + const connectionLocks = nodeConnectionManager.connectionLocks; await nodeConnectionManager.withConnF(remoteNodeId1, nop); const midConnAndLock = connections.get( remoteNodeId1.toString() as NodeIdString, ); // Check entry is in map and lock is released expect(midConnAndLock).toBeDefined(); - expect(midConnAndLock?.lock.isLocked()).toBeFalsy(); + expect(connectionLocks.isLocked(remoteNodeId1.toString())).toBeFalsy(); expect(midConnAndLock?.timer).toBeDefined(); // Destroying the connection @@ -296,10 +298,8 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { const finalConnAndLock = connections.get( remoteNodeId1.toString() as NodeIdString, ); - expect(finalConnAndLock).toBeDefined(); - expect(finalConnAndLock?.lock.isLocked()).toBeFalsy(); - expect(finalConnAndLock?.connection).toBeUndefined(); - expect(finalConnAndLock?.timer).toBeUndefined(); + expect(finalConnAndLock).not.toBeDefined(); + expect(connectionLocks.isLocked(remoteNodeId1.toString())).toBeFalsy(); } finally { await nodeConnectionManager?.stop(); } From c2566202880e4f1801e870d65ebe7fcb03952048 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Mon, 23 May 2022 12:57:29 +1000 Subject: [PATCH 045/137] feat: updated `VaultManager` to use `LockBox` for object map locking Using `LockBox` allowed us to greatly simplify using the object map and creating vaults. --- src/vaults/VaultManager.ts | 368 +++++++++++++----------------- tests/vaults/VaultManager.test.ts | 325 +++++++++++++------------- 2 files changed, 326 insertions(+), 367 deletions(-) diff --git a/src/vaults/VaultManager.ts b/src/vaults/VaultManager.ts index 2f8fe364f..ecf795a7f 100644 --- a/src/vaults/VaultManager.ts +++ b/src/vaults/VaultManager.ts @@ -1,5 +1,4 @@ import type { DB, DBTransaction, LevelPath } from '@matrixai/db'; -import type { ResourceAcquire, ResourceRelease } from '@matrixai/resources'; import type { VaultId, VaultName, @@ -8,7 +7,7 @@ import type { VaultIdEncoded, } from './types'; import type { Vault } from './Vault'; -import type { FileSystem } from '../types'; +import type { FileSystem, ToString } from '../types'; import type { PolykeyWorkerManagerInterface } from '../workers/types'; import type { NodeId } from '../nodes/types'; import type KeyManager from '../keys/KeyManager'; @@ -18,6 +17,7 @@ import type NotificationsManager from '../notifications/NotificationsManager'; import type ACL from '../acl/ACL'; import type { RemoteInfo } from './VaultInternal'; import type { VaultAction } from './types'; +import type { Lockable } from '@matrixai/async-locks'; import path from 'path'; import { PassThrough } from 'readable-stream'; import { EncryptedFS, errors as encryptedFsErrors } from 'encryptedfs'; @@ -28,7 +28,7 @@ import { } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { IdInternal } from '@matrixai/id'; import { withF, withG } from '@matrixai/resources'; -import { RWLockWriter } from '@matrixai/async-locks'; +import { LockBox, RWLockWriter } from '@matrixai/async-locks'; import VaultInternal from './VaultInternal'; import * as vaultsUtils from '../vaults/utils'; import * as vaultsErrors from '../vaults/errors'; @@ -43,13 +43,7 @@ import * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb'; /** * Object map pattern for each vault */ -type VaultMap = Map< - VaultIdString, - { - vault?: VaultInternal; - lock: RWLockWriter; - } ->; +type VaultMap = Map; type VaultList = Map; type VaultMetadata = { @@ -58,9 +52,12 @@ type VaultMetadata = { remoteInfo?: RemoteInfo; }; -// TODO: -// - Check all `tran` parameters and evaluate if they need to be optional or not -// - check all uses of gestaltGraph and ACL for passing tran +// FIXME, this is a HACK since this type isn't exported +type LockRequest = [ + key: ToString, + lockConstructor: new () => L, + ...lockingParams: Parameters, +]; interface VaultManager extends CreateDestroyStartStop {} @CreateDestroyStartStop( @@ -129,6 +126,7 @@ class VaultManager { protected vaultsNamesLock: RWLockWriter = new RWLockWriter(); // VaultId -> VaultMetadata protected vaultMap: VaultMap = new Map(); + protected vaultLocks: LockBox = new LockBox(); protected vaultKey: Buffer; protected efs: EncryptedFS; @@ -224,14 +222,22 @@ class VaultManager { // Iterate over vaults in memory and destroy them, ensuring that // the working directory commit state is saved - for (const [vaultIdString, vaultAndLock] of this.vaultMap) { + const promises: Array> = []; + for (const vaultIdString of this.vaultMap.keys()) { const vaultId = IdInternal.fromString(vaultIdString); - await withF([this.getWriteLock(vaultId)], async () => { - await vaultAndLock.vault?.stop(); - }); - this.vaultMap.delete(vaultIdString); + promises.push( + withF( + [this.vaultLocks.lock([vaultId.toString(), RWLockWriter, 'write'])], + async () => { + const vault = this.vaultMap.get(vaultIdString); + if (vault == null) return; + await vault.stop(); + this.vaultMap.delete(vaultIdString); + }, + ), + ); } - + await Promise.all(promises); await this.efs.stop(); this.vaultMap = new Map(); this.logger.info(`Stopped ${this.constructor.name}`); @@ -242,7 +248,7 @@ class VaultManager { await this.efs.destroy(); // Clearing all vaults db data await this.db.clear(this.vaultsDbPath); - // Is it necessary to remove the vaults domain? + // Is it necessary to remove the vaults' domain? await this.fs.promises.rm(this.vaultsPath, { force: true, recursive: true, @@ -258,33 +264,10 @@ class VaultManager { this.efs.unsetWorkerManager(); } - public getLock(vaultId: VaultId): RWLockWriter { - // Console.log(new Error(vaultId.toMultibase('base32hex')).stack); - const vaultIdString = vaultId.toString() as VaultIdString; - const vaultAndLock = this.vaultMap.get(vaultIdString); - if (vaultAndLock != null) return vaultAndLock.lock; - const lock = new RWLockWriter(); - this.vaultMap.set(vaultIdString, { lock }); - return lock; - } - - protected getReadLock(vaultId: VaultId): ResourceAcquire { - const lock = this.getLock(vaultId); - return lock.read(); - } - - protected getWriteLock(vaultId: VaultId): ResourceAcquire { - const lock = this.getLock(vaultId); - return lock.write(); - } - /** * Constructs a new vault instance with a given name and * stores it in memory */ - - // this should actually - @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) public async createVault( vaultName: VaultName, @@ -311,31 +294,32 @@ class VaultManager { vaultId.toBuffer(), true, ); - const lock = new RWLockWriter(); const vaultIdString = vaultId.toString() as VaultIdString; - this.vaultMap.set(vaultIdString, { lock }); - return await withF([this.getWriteLock(vaultId)], async () => { - // Creating vault - const vault = await VaultInternal.createVaultInternal({ - vaultId, - vaultName, - keyManager: this.keyManager, - efs: this.efs, - logger: this.logger.getChild(VaultInternal.name), - db: this.db, - vaultsDbPath: this.vaultsDbPath, - fresh: true, - tran, - }); - // Adding vault to object map - this.vaultMap.set(vaultIdString, { lock, vault }); - return vault.vaultId; - }); + return await this.vaultLocks.withF( + [vaultId, RWLockWriter, 'write'], + async () => { + // Creating vault + const vault = await VaultInternal.createVaultInternal({ + vaultId, + vaultName, + keyManager: this.keyManager, + efs: this.efs, + logger: this.logger.getChild(VaultInternal.name), + db: this.db, + vaultsDbPath: this.vaultsDbPath, + fresh: true, + tran, + }); + // Adding vault to object map + this.vaultMap.set(vaultIdString, vault); + return vault.vaultId; + }, + ); }); } /** - * Retreives the vault metadata using the vault Id + * Retrieves the vault metadata using the VaultId * and parses it to return the associated vault name */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) @@ -376,7 +360,7 @@ class VaultManager { /** * Removes the metadata and EFS state of a vault using a - * given vault Id + * given VaultId */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) public async destroyVault( @@ -394,7 +378,7 @@ class VaultManager { const vaultName = vaultMeta.vaultName; this.logger.info(`Destroying Vault ${vaultsUtils.encodeVaultId(vaultId)}`); const vaultIdString = vaultId.toString() as VaultIdString; - await withF([this.getWriteLock(vaultId)], async () => { + await this.vaultLocks.withF([vaultId, RWLockWriter, 'write'], async () => { const vault = await this.getVault(vaultId, tran); // Destroying vault state and metadata await vault.stop(); @@ -427,7 +411,7 @@ class VaultManager { throw new vaultsErrors.ErrorVaultsVaultUndefined(); } const vaultIdString = vaultId.toString() as VaultIdString; - await withF([this.getWriteLock(vaultId)], async () => { + await this.vaultLocks.withF([vaultId, RWLockWriter, 'write'], async () => { const vault = await this.getVault(vaultId, tran); await vault.stop(); this.vaultMap.delete(vaultIdString); @@ -435,7 +419,7 @@ class VaultManager { } /** - * Lists the vault name and associated vault Id of all + * Lists the vault name and associated VaultId of all * the vaults stored */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) @@ -458,7 +442,7 @@ class VaultManager { } /** - * Changes the vault name metadata of a vault Id + * Changes the vault name metadata of a VaultId */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) public async renameVault( @@ -472,7 +456,7 @@ class VaultManager { ); } - await withF([this.getWriteLock(vaultId)], async () => { + await this.vaultLocks.withF([vaultId, RWLockWriter, 'write'], async () => { this.logger.info(`Renaming Vault ${vaultsUtils.encodeVaultId(vaultId)}`); // Checking if new name exists if (await this.getVaultId(newVaultName, tran)) { @@ -503,7 +487,7 @@ class VaultManager { } /** - * Retreives the vault Id associated with a vault name + * Retrieves the VaultId associated with a vault name */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) public async getVaultId( @@ -527,7 +511,7 @@ class VaultManager { } /** - * Retreives the vault name associated with a vault Id + * Retrieves the vault name associated with a VaultId */ @ready(new vaultsErrors.ErrorVaultManagerNotRunning()) public async getVaultName( @@ -584,7 +568,7 @@ class VaultManager { const vaultMeta = await this.getVaultMeta(vaultId, tran); if (vaultMeta == null) throw new vaultsErrors.ErrorVaultsVaultUndefined(); - // Node Id permissions translated to other nodes in + // NodeId permissions translated to other nodes in // a gestalt by other domains await this.gestaltGraph.setGestaltActionByNode(nodeId, 'scan', tran); await this.acl.setVaultAction(vaultId, nodeId, 'pull', tran); @@ -640,65 +624,68 @@ class VaultManager { } const vaultId = await this.generateVaultId(); - const lock = new RWLockWriter(); const vaultIdString = vaultId.toString() as VaultIdString; - this.vaultMap.set(vaultIdString, { lock }); this.logger.info( `Cloning Vault ${vaultsUtils.encodeVaultId(vaultId)} on Node ${nodeId}`, ); - return await withF([this.getWriteLock(vaultId)], async () => { - const vault = await VaultInternal.cloneVaultInternal({ - targetNodeId: nodeId, - targetVaultNameOrId: vaultNameOrId, - vaultId, - db: this.db, - nodeConnectionManager: this.nodeConnectionManager, - vaultsDbPath: this.vaultsDbPath, - keyManager: this.keyManager, - efs: this.efs, - logger: this.logger.getChild(VaultInternal.name), - tran, - }); - this.vaultMap.set(vaultIdString, { lock, vault }); - const vaultMetadata = (await this.getVaultMeta(vaultId, tran))!; - const baseVaultName = vaultMetadata.vaultName; - // Need to check if the name is taken, 10 attempts - let newVaultName = baseVaultName; - let attempts = 1; - while (true) { - const existingVaultId = await tran.get([ - ...this.vaultsNamesDbPath, - newVaultName, - ]); - if (existingVaultId == null) break; - newVaultName = `${baseVaultName}-${attempts}`; - if (attempts >= 50) { - throw new vaultsErrors.ErrorVaultsNameConflict( - `Too many copies of ${baseVaultName}`, - ); + return await this.vaultLocks.withF( + [vaultId, RWLockWriter, 'write'], + async () => { + const vault = await VaultInternal.cloneVaultInternal({ + targetNodeId: nodeId, + targetVaultNameOrId: vaultNameOrId, + vaultId, + db: this.db, + nodeConnectionManager: this.nodeConnectionManager, + vaultsDbPath: this.vaultsDbPath, + keyManager: this.keyManager, + efs: this.efs, + logger: this.logger.getChild(VaultInternal.name), + tran, + }); + this.vaultMap.set(vaultIdString, vault); + const vaultMetadata = (await this.getVaultMeta(vaultId, tran))!; + const baseVaultName = vaultMetadata.vaultName; + // Need to check if the name is taken, 10 attempts + let newVaultName = baseVaultName; + let attempts = 1; + while (true) { + const existingVaultId = await tran.get([ + ...this.vaultsNamesDbPath, + newVaultName, + ]); + if (existingVaultId == null) break; + newVaultName = `${baseVaultName}-${attempts}`; + if (attempts >= 50) { + throw new vaultsErrors.ErrorVaultsNameConflict( + `Too many copies of ${baseVaultName}`, + ); + } + attempts++; } - attempts++; - } - // Set the vaultName -> vaultId mapping - await tran.put( - [...this.vaultsNamesDbPath, newVaultName], - vaultId.toBuffer(), - true, - ); - // Update vault metadata - await tran.put( - [ - ...this.vaultsDbPath, - vaultsUtils.encodeVaultId(vaultId), - VaultInternal.nameKey, - ], - newVaultName, - ); - this.logger.info( - `Cloned Vault ${vaultsUtils.encodeVaultId(vaultId)} on Node ${nodeId}`, - ); - return vault.vaultId; - }); + // Set the vaultName -> vaultId mapping + await tran.put( + [...this.vaultsNamesDbPath, newVaultName], + vaultId.toBuffer(), + true, + ); + // Update vault metadata + await tran.put( + [ + ...this.vaultsDbPath, + vaultsUtils.encodeVaultId(vaultId), + VaultInternal.nameKey, + ], + newVaultName, + ); + this.logger.info( + `Cloned Vault ${vaultsUtils.encodeVaultId( + vaultId, + )} on Node ${nodeId}`, + ); + return vault.vaultId; + }, + ); } /** @@ -723,7 +710,7 @@ class VaultManager { } if ((await this.getVaultName(vaultId, tran)) == null) return; - await withF([this.getWriteLock(vaultId)], async () => { + await this.vaultLocks.withF([vaultId, RWLockWriter, 'write'], async () => { const vault = await this.getVault(vaultId, tran); await vault.pullVault({ nodeConnectionManager: this.nodeConnectionManager, @@ -752,7 +739,10 @@ class VaultManager { const efs = this.efs; const vault = await this.getVault(vaultId, tran); return yield* withG( - [this.getReadLock(vaultId), vault.getLock().read()], + [ + this.vaultLocks.lock([vaultId, RWLockWriter, 'read']), + vault.getLock().read(), + ], async function* (): AsyncGenerator { // Adherence to git protocol yield Buffer.from( @@ -791,7 +781,10 @@ class VaultManager { const vault = await this.getVault(vaultId, tran); return await withF( - [this.getReadLock(vaultId), vault.getLock().read()], + [ + this.vaultLocks.lock([vaultId, RWLockWriter, 'read']), + vault.getLock().read(), + ], async () => { if (body.toString().slice(4, 8) === 'want') { // Parse the request to get the wanted git object @@ -932,79 +925,30 @@ class VaultManager { ); } - let vault: VaultInternal | undefined; - let lock: RWLockWriter; const vaultIdString = vaultId.toString() as VaultIdString; - let vaultAndLock = this.vaultMap.get(vaultIdString); - if (vaultAndLock != null) { - ({ vault, lock } = vaultAndLock); - // Lock and vault exist - if (vault != null) { - return vault; - } - // Only lock exists - let release: ResourceRelease | undefined; - try { - [release] = await lock.write()(); - ({ vault } = vaultAndLock); - if (vault != null) { - return vault; - } - // Only create if the vault state already exists - if ((await this.getVaultMeta(vaultId, tran)) == null) { - throw new vaultsErrors.ErrorVaultsVaultUndefined( - `Vault ${vaultsUtils.encodeVaultId(vaultId)} doesn't exist`, - ); - } - vault = await VaultInternal.createVaultInternal({ - vaultId, - keyManager: this.keyManager, - efs: this.efs, - logger: this.logger.getChild(VaultInternal.name), - db: this.db, - vaultsDbPath: this.vaultsDbPath, - tran, - }); - vaultAndLock.vault = vault; - this.vaultMap.set(vaultIdString, vaultAndLock); - return vault; - } finally { - if (release != null) await release(); - } - } else { - // Neither vault nor lock exists - lock = new RWLockWriter(); - vaultAndLock = { lock }; - this.vaultMap.set(vaultIdString, vaultAndLock); - let release: ResourceRelease | undefined; - try { - [release] = await lock.write()(); - // Only create if the vault state already exists - if ((await this.getVaultMeta(vaultId, tran)) == null) { - throw new vaultsErrors.ErrorVaultsVaultUndefined( - `Vault ${vaultsUtils.encodeVaultId(vaultId)} doesn't exist`, - ); - } - vault = await VaultInternal.createVaultInternal({ - vaultId, - keyManager: this.keyManager, - efs: this.efs, - db: this.db, - vaultsDbPath: this.vaultsDbPath, - logger: this.logger.getChild(VaultInternal.name), - tran, - }); - vaultAndLock.vault = vault; - this.vaultMap.set(vaultIdString, vaultAndLock); - return vault; - } finally { - if (release != null) await release(); - } + // 1. get the vault, if it exists then return that + const vault = this.vaultMap.get(vaultIdString); + if (vault != null) return vault; + // No vault or state exists then we throw error? + if ((await this.getVaultMeta(vaultId, tran)) == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined( + `Vault ${vaultsUtils.encodeVaultId(vaultId)} doesn't exist`, + ); } + // 2. if the state exists then create, add to map and return that + const newVault = await VaultInternal.createVaultInternal({ + vaultId, + keyManager: this.keyManager, + efs: this.efs, + logger: this.logger.getChild(VaultInternal.name), + db: this.db, + vaultsDbPath: this.vaultsDbPath, + tran, + }); + this.vaultMap.set(vaultIdString, newVault); + return newVault; } - // THIS can also be replaced with generic withF and withG - /** * Takes a function and runs it with the listed vaults. locking is handled automatically * @param vaultIds List of vault ID for vaults you wish to use @@ -1023,25 +967,21 @@ class VaultManager { ); } - // Stages: - // 1. Obtain vaults - // 2. Call function with vaults while locking the vaults - // 3. Catch any problems and preform clean up in finally - // 4. return result - - const vaults = await Promise.all( - vaultIds.map(async (vaultId) => { - return await this.getVault(vaultId, tran); - }), - ); - // Obtaining locks - const vaultLocks = vaultIds.map((vaultId) => { - return this.getReadLock(vaultId); - }); + const vaultLocks: Array> = vaultIds.map( + (vaultId) => { + return [vaultId.toString(), RWLockWriter, 'read']; + }, + ); // Running the function with locking - return await withF(vaultLocks, () => { + return await this.vaultLocks.withF(...vaultLocks, async () => { + // Getting the vaults while locked + const vaults = await Promise.all( + vaultIds.map(async (vaultId) => { + return await this.getVault(vaultId, tran); + }), + ); return f(...vaults); }); } diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index 9c7bc4021..783de4ef4 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -15,6 +15,7 @@ import { IdInternal } from '@matrixai/id'; import { DB } from '@matrixai/db'; import { destroyed, running } from '@matrixai/async-init'; import git from 'isomorphic-git'; +import { RWLockWriter } from '@matrixai/async-locks'; import ACL from '@/acl/ACL'; import GestaltGraph from '@/gestalts/GestaltGraph'; import NodeConnectionManager from '@/nodes/NodeConnectionManager'; @@ -869,9 +870,10 @@ describe('VaultManager', () => { remoteVaultId, ); - await expect(() => + await expectRemoteError( vaultManager.pullVault({ vaultId: clonedVaultId }), - ).rejects.toThrow(vaultsErrors.ErrorVaultsPermissionDenied); + vaultsErrors.ErrorVaultsPermissionDenied, + ); } finally { await vaultManager?.stop(); await vaultManager?.destroy(); @@ -962,138 +964,142 @@ describe('VaultManager', () => { await vaultManager?.destroy(); } }); - test('manage pulling from different remotes', async () => { - const vaultManager = await VaultManager.createVaultManager({ - vaultsPath, - keyManager: dummyKeyManager, - gestaltGraph: {} as GestaltGraph, - nodeConnectionManager, - acl: {} as ACL, - notificationsManager: {} as NotificationsManager, - db, - logger: logger.getChild(VaultManager.name), - }); - try { - // Initial history - await remoteKeynode1.vaultManager.withVaults( - [remoteVaultId], - async (remoteVault) => { - await remoteVault.writeF(async (efs) => { - await efs.writeFile(secretNames[0], 'success?'); - await efs.writeFile(secretNames[1], 'success?'); - }); - }, - ); - - // Setting permissions - await remoteKeynode1.gestaltGraph.setNode({ - id: localNodeIdEncoded, - chain: {}, + test( + 'manage pulling from different remotes', + async () => { + const vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + keyManager: dummyKeyManager, + gestaltGraph: {} as GestaltGraph, + nodeConnectionManager, + acl: {} as ACL, + notificationsManager: {} as NotificationsManager, + db, + logger: logger.getChild(VaultManager.name), }); - await remoteKeynode1.gestaltGraph.setGestaltActionByNode( - localNodeId, - 'scan', - ); - await remoteKeynode1.acl.setVaultAction( - remoteVaultId, - localNodeId, - 'clone', - ); - await remoteKeynode1.acl.setVaultAction( - remoteVaultId, - localNodeId, - 'pull', - ); + try { + // Initial history + await remoteKeynode1.vaultManager.withVaults( + [remoteVaultId], + async (remoteVault) => { + await remoteVault.writeF(async (efs) => { + await efs.writeFile(secretNames[0], 'success?'); + await efs.writeFile(secretNames[1], 'success?'); + }); + }, + ); - await remoteKeynode1.gestaltGraph.setNode({ - id: remoteKeynode2IdEncoded, - chain: {}, - }); - await remoteKeynode1.gestaltGraph.setGestaltActionByNode( - remoteKeynode2Id, - 'scan', - ); - await remoteKeynode1.acl.setVaultAction( - remoteVaultId, - remoteKeynode2Id, - 'clone', - ); - await remoteKeynode1.acl.setVaultAction( - remoteVaultId, - remoteKeynode2Id, - 'pull', - ); + // Setting permissions + await remoteKeynode1.gestaltGraph.setNode({ + id: localNodeIdEncoded, + chain: {}, + }); + await remoteKeynode1.gestaltGraph.setGestaltActionByNode( + localNodeId, + 'scan', + ); + await remoteKeynode1.acl.setVaultAction( + remoteVaultId, + localNodeId, + 'clone', + ); + await remoteKeynode1.acl.setVaultAction( + remoteVaultId, + localNodeId, + 'pull', + ); - const clonedVaultRemote2Id = - await remoteKeynode2.vaultManager.cloneVault( - remoteKeynode1Id, + await remoteKeynode1.gestaltGraph.setNode({ + id: remoteKeynode2IdEncoded, + chain: {}, + }); + await remoteKeynode1.gestaltGraph.setGestaltActionByNode( + remoteKeynode2Id, + 'scan', + ); + await remoteKeynode1.acl.setVaultAction( + remoteVaultId, + remoteKeynode2Id, + 'clone', + ); + await remoteKeynode1.acl.setVaultAction( remoteVaultId, + remoteKeynode2Id, + 'pull', ); - await remoteKeynode2.gestaltGraph.setNode({ - id: localNodeIdEncoded, - chain: {}, - }); - await remoteKeynode2.gestaltGraph.setGestaltActionByNode( - localNodeId, - 'scan', - ); - await remoteKeynode2.acl.setVaultAction( - clonedVaultRemote2Id, - localNodeId, - 'clone', - ); - await remoteKeynode2.acl.setVaultAction( - clonedVaultRemote2Id, - localNodeId, - 'pull', - ); - const vaultCloneId = await vaultManager.cloneVault( - remoteKeynode2Id, - clonedVaultRemote2Id, - ); + const clonedVaultRemote2Id = + await remoteKeynode2.vaultManager.cloneVault( + remoteKeynode1Id, + remoteVaultId, + ); - await remoteKeynode1.vaultManager.withVaults( - [remoteVaultId], - async (remoteVault) => { - await remoteVault.writeF(async (efs) => { - await efs.writeFile(secretNames[2], 'success?'); + await remoteKeynode2.gestaltGraph.setNode({ + id: localNodeIdEncoded, + chain: {}, + }); + await remoteKeynode2.gestaltGraph.setGestaltActionByNode( + localNodeId, + 'scan', + ); + await remoteKeynode2.acl.setVaultAction( + clonedVaultRemote2Id, + localNodeId, + 'clone', + ); + await remoteKeynode2.acl.setVaultAction( + clonedVaultRemote2Id, + localNodeId, + 'pull', + ); + const vaultCloneId = await vaultManager.cloneVault( + remoteKeynode2Id, + clonedVaultRemote2Id, + ); + + await remoteKeynode1.vaultManager.withVaults( + [remoteVaultId], + async (remoteVault) => { + await remoteVault.writeF(async (efs) => { + await efs.writeFile(secretNames[2], 'success?'); + }); + }, + ); + await vaultManager.pullVault({ + vaultId: vaultCloneId, + pullNodeId: remoteKeynode1Id, + pullVaultNameOrId: vaultName, + }); + await vaultManager.withVaults([vaultCloneId], async (vaultClone) => { + await vaultClone.readF(async (efs) => { + expect((await efs.readdir('.')).sort()).toStrictEqual( + secretNames.slice(0, 3).sort(), + ); }); - }, - ); - await vaultManager.pullVault({ - vaultId: vaultCloneId, - pullNodeId: remoteKeynode1Id, - pullVaultNameOrId: vaultName, - }); - await vaultManager.withVaults([vaultCloneId], async (vaultClone) => { - await vaultClone.readF(async (efs) => { - expect((await efs.readdir('.')).sort()).toStrictEqual( - secretNames.slice(0, 3).sort(), - ); }); - }); - await remoteKeynode1.vaultManager.withVaults( - [remoteVaultId], - async (remoteVault) => { - await remoteVault.writeF(async (efs) => { - await efs.writeFile(secretNames[3], 'second success?'); + await remoteKeynode1.vaultManager.withVaults( + [remoteVaultId], + async (remoteVault) => { + await remoteVault.writeF(async (efs) => { + await efs.writeFile(secretNames[3], 'second success?'); + }); + }, + ); + await vaultManager.pullVault({ vaultId: vaultCloneId }); + await vaultManager.withVaults([vaultCloneId], async (vaultClone) => { + await vaultClone.readF(async (efs) => { + expect((await efs.readdir('.')).sort()).toStrictEqual( + secretNames.sort(), + ); }); - }, - ); - await vaultManager.pullVault({ vaultId: vaultCloneId }); - await vaultManager.withVaults([vaultCloneId], async (vaultClone) => { - await vaultClone.readF(async (efs) => { - expect((await efs.readdir('.')).sort()).toStrictEqual( - secretNames.sort(), - ); }); - }); - } finally { - await vaultManager?.stop(); - await vaultManager?.destroy(); - } - }); + } finally { + await vaultManager?.stop(); + await vaultManager?.destroy(); + } + }, + global.failedConnectionTimeout, + ); test('able to recover metadata after complex operations', async () => { const vaultManager = await VaultManager.createVaultManager({ vaultsPath, @@ -1309,9 +1315,14 @@ describe('VaultManager', () => { // @ts-ignore: kidnap vaultManager map and grabbing lock const vaultsMap = vaultManager.vaultMap; - const vaultAndLock = vaultsMap.get(vaultId.toString() as VaultIdString); - const lock = vaultAndLock!.lock; - const [releaseWrite] = await lock.write()(); + const vault = vaultsMap.get(vaultId.toString() as VaultIdString); + // @ts-ignore: kidnap vaultManager lockBox + const vaultLocks = vaultManager.vaultLocks; + const [releaseWrite] = await vaultLocks.lock([ + vaultId, + RWLockWriter, + 'write', + ])(); // Pulling vault respects VaultManager write lock const pullP = vaultManager.pullVault({ @@ -1335,9 +1346,8 @@ describe('VaultManager', () => { ); // Respects VaultInternal write lock - const vault = vaultAndLock!.vault!; // @ts-ignore: kidnap vault lock - const vaultLock = vault.lock; + const vaultLock = vault!.lock; const [releaseVaultWrite] = await vaultLock.write()(); // Pulling vault respects VaultManager write lock gitPullMock.mockClear(); @@ -1592,26 +1602,30 @@ describe('VaultManager', () => { try { // @ts-ignore: kidnapping the map const vaultMap = vaultManager.vaultMap; + // @ts-ignore: kidnap vaultManager lockBox + const vaultLocks = vaultManager.vaultLocks; + // Create the vault const vaultId = await vaultManager.createVault('vaultName'); + const vaultIdString = vaultId.toString() as VaultIdString; // Getting and holding the lock - const vaultAndLock = vaultMap.get(vaultId.toString() as VaultIdString)!; - const lock = vaultAndLock.lock; - const vault = vaultAndLock.vault!; - const [release] = await lock.write()(); + const vault = vaultMap.get(vaultIdString)!; + const [releaseWrite] = await vaultLocks.lock([ + vaultId, + RWLockWriter, + 'write', + ])(); // Try to destroy const closeP = vaultManager.closeVault(vaultId); await sleep(1000); // Shouldn't be closed expect(vault[running]).toBe(true); - expect( - vaultMap.get(vaultId.toString() as VaultIdString)!.vault, - ).toBeDefined(); + expect(vaultMap.get(vaultIdString)).toBeDefined(); // Release the lock - await release(); + await releaseWrite(); await closeP; expect(vault[running]).toBe(false); - expect(vaultMap.get(vaultId.toString() as VaultIdString)).toBeUndefined(); + expect(vaultMap.get(vaultIdString)).toBeUndefined(); } finally { await vaultManager?.stop(); await vaultManager?.destroy(); @@ -1631,26 +1645,29 @@ describe('VaultManager', () => { try { // @ts-ignore: kidnapping the map const vaultMap = vaultManager.vaultMap; + // @ts-ignore: kidnap vaultManager lockBox + const vaultLocks = vaultManager.vaultLocks; // Create the vault const vaultId = await vaultManager.createVault('vaultName'); + const vaultIdString = vaultId.toString() as VaultIdString; // Getting and holding the lock - const vaultAndLock = vaultMap.get(vaultId.toString() as VaultIdString)!; - const lock = vaultAndLock.lock; - const vault = vaultAndLock.vault!; - const [release] = await lock.write()(); + const vault = vaultMap.get(vaultIdString)!; + const [releaseWrite] = await vaultLocks.lock([ + vaultId, + RWLockWriter, + 'write', + ])(); // Try to destroy const destroyP = vaultManager.destroyVault(vaultId); await sleep(1000); // Shouldn't be destroyed expect(vault[destroyed]).toBe(false); - expect( - vaultMap.get(vaultId.toString() as VaultIdString)!.vault, - ).toBeDefined(); + expect(vaultMap.get(vaultIdString)).toBeDefined(); // Release the lock - await release(); + await releaseWrite(); await destroyP; expect(vault[destroyed]).toBe(true); - expect(vaultMap.get(vaultId.toString() as VaultIdString)).toBeUndefined(); + expect(vaultMap.get(vaultIdString)).toBeUndefined(); } finally { await vaultManager?.stop(); await vaultManager?.destroy(); @@ -1668,14 +1685,16 @@ describe('VaultManager', () => { logger: logger.getChild(VaultManager.name), }); try { - // @ts-ignore: kidnapping the map - const vaultMap = vaultManager.vaultMap; + // @ts-ignore: kidnap vaultManager lockBox + const vaultLocks = vaultManager.vaultLocks; // Create the vault const vaultId = await vaultManager.createVault('vaultName'); // Getting and holding the lock - const vaultAndLock = vaultMap.get(vaultId.toString() as VaultIdString)!; - const lock = vaultAndLock.lock; - const [release] = await lock.write()(); + const [releaseWrite] = await vaultLocks.lock([ + vaultId, + RWLockWriter, + 'write', + ])(); // Try to use vault let finished = false; const withP = vaultManager.withVaults([vaultId], async () => { @@ -1685,7 +1704,7 @@ describe('VaultManager', () => { // Shouldn't be destroyed expect(finished).toBe(false); // Release the lock - await release(); + await releaseWrite(); await withP; expect(finished).toBe(true); } finally { @@ -1919,7 +1938,7 @@ describe('VaultManager', () => { ); expect(duplicates.length).toBe(0); - const vaultId = await vaultManager.createVault('testvault'); + const vaultId = await vaultManager.createVault('testVault'); // Now only returns duplicates generateVaultIdMock.mockReturnValue(vaultId); const asd = async () => { From 5dda0a4a4f30561ee0e0e9b534d07d301f5adc94 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Mon, 23 May 2022 15:35:18 +1000 Subject: [PATCH 046/137] feat: format json affects error logging Specifying `--format=json` will cause errors to be logged in json format. ErrorPolykeyRemote errors also now contain additional metadata about the origin node of the error. #323 --- package-lock.json | 112 ++++++++++++++++++- package.json | 3 +- src/agent/GRPCClientAgent.ts | 10 ++ src/agent/service/nodesCrossSignClaim.ts | 6 +- src/agent/service/vaultsGitPackGet.ts | 6 +- src/bin/CommandPolykey.ts | 2 + src/bin/agent/CommandStart.ts | 1 + src/bin/polykey-agent.ts | 23 ++-- src/bin/polykey.ts | 12 +-- src/bin/types.ts | 1 + src/bin/utils/ExitHandlers.ts | 27 +++-- src/bin/utils/utils.ts | 77 +++++++++++-- src/client/GRPCClientClient.ts | 64 +++++++++++ src/errors.ts | 53 +++++++-- src/grpc/utils/utils.ts | 79 +++++++------- src/types.ts | 10 ++ tests/bin/agent/lock.test.ts | 2 +- tests/bin/agent/lockall.test.ts | 14 ++- tests/bin/agent/start.test.ts | 40 ++++--- tests/bin/agent/stop.test.ts | 16 ++- tests/bin/bootstrap.test.ts | 85 +++++++-------- tests/bin/sessions.test.ts | 26 ++--- tests/bin/utils.retryAuthentication.test.ts | 2 +- tests/bin/utils.test.ts | 114 +++++++++++++++++++- tests/bin/utils.ts | 24 +++-- 25 files changed, 608 insertions(+), 201 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8fe56b2cf..3a8a23a79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -79,7 +79,8 @@ "ts-node": "^10.4.0", "tsconfig-paths": "^3.9.0", "typedoc": "^0.22.15", - "typescript": "^4.5.2" + "typescript": "^4.5.2", + "typescript-cached-transpile": "0.0.6" } }, "node_modules/@ampproject/remapping": { @@ -10225,6 +10226,64 @@ "node": ">=4.2.0" } }, + "node_modules/typescript-cached-transpile": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typescript-cached-transpile/-/typescript-cached-transpile-0.0.6.tgz", + "integrity": "sha512-bfPc7YUW0PrVkQHU0xN0ANRuxdPgoYYXtZEW6PNkH5a97/AOM+kPPxSTMZbpWA3BG1do22JUkfC60KoCKJ9VZQ==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.7", + "fs-extra": "^8.1.0", + "tslib": "^1.10.0" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/typescript-cached-transpile/node_modules/@types/node": { + "version": "12.20.52", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.52.tgz", + "integrity": "sha512-cfkwWw72849SNYp3Zx0IcIs25vABmFh73xicxhCkTcvtZQeIez15PpwQN8fY3RD7gv1Wrxlc9MEtfMORZDEsGw==", + "dev": true + }, + "node_modules/typescript-cached-transpile/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/typescript-cached-transpile/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/typescript-cached-transpile/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/typescript-cached-transpile/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/uglify-js": { "version": "3.15.5", "dev": true, @@ -17083,6 +17142,57 @@ "version": "4.6.4", "dev": true }, + "typescript-cached-transpile": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typescript-cached-transpile/-/typescript-cached-transpile-0.0.6.tgz", + "integrity": "sha512-bfPc7YUW0PrVkQHU0xN0ANRuxdPgoYYXtZEW6PNkH5a97/AOM+kPPxSTMZbpWA3BG1do22JUkfC60KoCKJ9VZQ==", + "dev": true, + "requires": { + "@types/node": "^12.12.7", + "fs-extra": "^8.1.0", + "tslib": "^1.10.0" + }, + "dependencies": { + "@types/node": { + "version": "12.20.52", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.52.tgz", + "integrity": "sha512-cfkwWw72849SNYp3Zx0IcIs25vABmFh73xicxhCkTcvtZQeIez15PpwQN8fY3RD7gv1Wrxlc9MEtfMORZDEsGw==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "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 + } + } + }, "uglify-js": { "version": "3.15.5", "dev": true, diff --git a/package.json b/package.json index 29bc7b603..9909dbe4d 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "ts-node": "^10.4.0", "tsconfig-paths": "^3.9.0", "typedoc": "^0.22.15", - "typescript": "^4.5.2" + "typescript": "^4.5.2", + "typescript-cached-transpile": "0.0.6" } } diff --git a/src/agent/GRPCClientAgent.ts b/src/agent/GRPCClientAgent.ts index bfc1c4d65..bb4593785 100644 --- a/src/agent/GRPCClientAgent.ts +++ b/src/agent/GRPCClientAgent.ts @@ -83,6 +83,7 @@ class GRPCClientAgent extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.echo.name, }, this.client.echo, )(...args); @@ -101,6 +102,7 @@ class GRPCClientAgent extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsGitInfoGet.name, }, this.client.vaultsGitInfoGet, )(...args); @@ -120,6 +122,7 @@ class GRPCClientAgent extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsGitPackGet.name, }, this.client.vaultsGitPackGet, )(...args); @@ -138,6 +141,7 @@ class GRPCClientAgent extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsScan.name, }, this.client.vaultsScan, )(...args); @@ -151,6 +155,7 @@ class GRPCClientAgent extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.nodesClosestLocalNodesGet.name, }, this.client.nodesClosestLocalNodesGet, )(...args); @@ -164,6 +169,7 @@ class GRPCClientAgent extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.nodesClaimsGet.name, }, this.client.nodesClaimsGet, )(...args); @@ -177,6 +183,7 @@ class GRPCClientAgent extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.nodesChainDataGet.name, }, this.client.nodesChainDataGet, )(...args); @@ -190,6 +197,7 @@ class GRPCClientAgent extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.nodesHolePunchMessageSend.name, }, this.client.nodesHolePunchMessageSend, )(...args); @@ -203,6 +211,7 @@ class GRPCClientAgent extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.notificationsSend.name, }, this.client.notificationsSend, )(...args); @@ -225,6 +234,7 @@ class GRPCClientAgent extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.nodesCrossSignClaim.name, }, this.client.nodesCrossSignClaim, )(...args); diff --git a/src/agent/service/nodesCrossSignClaim.ts b/src/agent/service/nodesCrossSignClaim.ts index f0a3e2a9a..f9fbb1bbb 100644 --- a/src/agent/service/nodesCrossSignClaim.ts +++ b/src/agent/service/nodesCrossSignClaim.ts @@ -32,7 +32,11 @@ function nodesCrossSignClaim({ call: grpc.ServerDuplexStream, ) => { const nodeId = keyManager.getNodeId(); - const genClaims = grpcUtils.generatorDuplex(call, { nodeId }, true); + const genClaims = grpcUtils.generatorDuplex( + call, + { nodeId, command: nodesCrossSignClaim.name }, + true, + ); try { await db.withTransactionF(async (tran) => { const readStatus = await genClaims.read(); diff --git a/src/agent/service/vaultsGitPackGet.ts b/src/agent/service/vaultsGitPackGet.ts index 8d9561512..c7ec95dbd 100644 --- a/src/agent/service/vaultsGitPackGet.ts +++ b/src/agent/service/vaultsGitPackGet.ts @@ -34,7 +34,11 @@ function vaultsGitPackGet({ call: grpc.ServerDuplexStream, ): Promise => { const nodeId = keyManager.getNodeId(); - const genDuplex = grpcUtils.generatorDuplex(call, { nodeId }, true); + const genDuplex = grpcUtils.generatorDuplex( + call, + { nodeId, command: vaultsGitPackGet.name }, + true, + ); try { const clientBodyBuffers: Uint8Array[] = []; const clientRequest = (await genDuplex.read()).value; diff --git a/src/bin/CommandPolykey.ts b/src/bin/CommandPolykey.ts index b9534fee0..436dfdbdd 100644 --- a/src/bin/CommandPolykey.ts +++ b/src/bin/CommandPolykey.ts @@ -61,6 +61,8 @@ class CommandPolykey extends commander.Command { public action(fn: (...args: any[]) => void | Promise): this { return super.action(async (...args: any[]) => { const opts = this.opts(); + // Set the format for error logging for the exit handlers + this.exitHandlers.errFormat = opts.format === 'json' ? 'json' : 'error'; // Set the logger according to the verbosity this.logger.setLevel(binUtils.verboseToLogLevel(opts.verbose)); // Set the global upstream GRPC logger diff --git a/src/bin/agent/CommandStart.ts b/src/bin/agent/CommandStart.ts index e4b863a47..6ccc4e9c0 100644 --- a/src/bin/agent/CommandStart.ts +++ b/src/bin/agent/CommandStart.ts @@ -185,6 +185,7 @@ class CommandStart extends CommandPolykey { }); const messageIn: AgentChildProcessInput = { logLevel: this.logger.getEffectiveLevel(), + format: options.format, workers: options.workers, agentConfig, }; diff --git a/src/bin/polykey-agent.ts b/src/bin/polykey-agent.ts index d56d49220..de65ebc86 100644 --- a/src/bin/polykey-agent.ts +++ b/src/bin/polykey-agent.ts @@ -44,6 +44,8 @@ async function main(_argv = process.argv): Promise { resolveMessageInP(data); }); const messageIn = await messageInP; + const errFormat = messageIn.format === 'json' ? 'json' : 'error'; + exitHandlers.errFormat = errFormat; logger.setLevel(messageIn.logLevel); // Set the global upstream GRPC logger grpcSetLogger(logger.getChild('grpc')); @@ -71,10 +73,8 @@ async function main(_argv = process.argv): Promise { if (e instanceof ErrorPolykey) { process.stderr.write( binUtils.outputFormatter({ - type: 'error', - name: e.name, - description: e.description, - message: e.message, + type: errFormat, + data: e, }), ); process.exitCode = e.exitCode; @@ -82,9 +82,8 @@ async function main(_argv = process.argv): Promise { // Unknown error, this should not happen process.stderr.write( binUtils.outputFormatter({ - type: 'error', - name: e.name, - description: e.message, + type: errFormat, + data: e, }), ); process.exitCode = 255; @@ -107,9 +106,8 @@ async function main(_argv = process.argv): Promise { // There's no point attempting to propagate the error to the parent process.stderr.write( binUtils.outputFormatter({ - type: 'error', - name: e.name, - description: e.message, + type: errFormat, + data: e, }), ); process.exitCode = 255; @@ -137,9 +135,8 @@ async function main(_argv = process.argv): Promise { // There's no point attempting to propagate the error to the parent process.stderr.write( binUtils.outputFormatter({ - type: 'error', - name: e.name, - description: e.message, + type: errFormat, + data: e, }), ); process.exitCode = 255; diff --git a/src/bin/polykey.ts b/src/bin/polykey.ts index ac40d5373..bb4d49f8a 100644 --- a/src/bin/polykey.ts +++ b/src/bin/polykey.ts @@ -55,6 +55,7 @@ async function main(argv = process.argv): Promise { // Successful execution (even if the command was non-terminating) process.exitCode = 0; } catch (e) { + const errFormat = rootCommand.opts().format === 'json' ? 'json' : 'error'; if (e instanceof commander.CommanderError) { // Commander writes help and error messages on stderr automatically if ( @@ -78,10 +79,8 @@ async function main(argv = process.argv): Promise { } else if (e instanceof ErrorPolykey) { process.stderr.write( binUtils.outputFormatter({ - type: 'error', - name: e.name, - description: e.description, - message: e.message, + type: errFormat, + data: e, }), ); process.exitCode = e.exitCode; @@ -89,9 +88,8 @@ async function main(argv = process.argv): Promise { // Unknown error, this should not happen process.stderr.write( binUtils.outputFormatter({ - type: 'error', - name: e.name, - description: e.message, + type: errFormat, + data: e, }), ); process.exitCode = 255; diff --git a/src/bin/types.ts b/src/bin/types.ts index ef2451661..0517f08f1 100644 --- a/src/bin/types.ts +++ b/src/bin/types.ts @@ -17,6 +17,7 @@ type AgentStatusLiveData = Omit & { */ type AgentChildProcessInput = { logLevel: LogLevel; + format: 'human' | 'json'; workers?: number; agentConfig: { password: string; diff --git a/src/bin/utils/ExitHandlers.ts b/src/bin/utils/ExitHandlers.ts index 84b981d80..2fdd74f03 100644 --- a/src/bin/utils/ExitHandlers.ts +++ b/src/bin/utils/ExitHandlers.ts @@ -9,6 +9,7 @@ class ExitHandlers { */ public handlers: Array<(signal?: NodeJS.Signals) => Promise>; protected _exiting: boolean = false; + protected _errFormat: 'json' | 'error'; /** * Handles synchronous and asynchronous exceptions * This prints out appropriate error message on STDERR @@ -23,10 +24,8 @@ class ExitHandlers { if (e instanceof ErrorPolykey) { process.stderr.write( binUtils.outputFormatter({ - type: 'error', - name: e.name, - description: e.description, - message: e.message, + type: this._errFormat, + data: e, }), ); process.exitCode = e.exitCode; @@ -34,9 +33,8 @@ class ExitHandlers { // Unknown error, this should not happen process.stderr.write( binUtils.outputFormatter({ - type: 'error', - name: e.name, - description: e.message, + type: this._errFormat, + data: e, }), ); process.exitCode = 255; @@ -65,19 +63,16 @@ class ExitHandlers { if (e instanceof ErrorPolykey) { process.stderr.write( binUtils.outputFormatter({ - type: 'error', - name: e.name, - description: e.description, - message: e.message, + type: this._errFormat, + data: e, }), ); } else { // Unknown error, this should not happen process.stderr.write( binUtils.outputFormatter({ - type: 'error', - name: e.name, - description: e.message, + type: this._errFormat, + data: e, }), ); } @@ -103,6 +98,10 @@ class ExitHandlers { return this._exiting; } + set errFormat(errFormat: 'json' | 'error') { + this._errFormat = errFormat; + } + public install() { process.on('SIGINT', this.signalHandler); process.on('SIGTERM', this.signalHandler); diff --git a/src/bin/utils/utils.ts b/src/bin/utils/utils.ts index 5477228a9..0e66b8e23 100644 --- a/src/bin/utils/utils.ts +++ b/src/bin/utils/utils.ts @@ -2,11 +2,14 @@ import type { POJO } from '../../types'; import process from 'process'; import { LogLevel } from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; +import { AbstractError } from '@matrixai/errors'; import * as binProcessors from './processors'; import * as binErrors from '../errors'; import * as clientUtils from '../../client/utils'; import * as clientErrors from '../../client/errors'; import * as errors from '../../errors'; +import * as nodesUtils from '../../nodes/utils'; +import * as utils from '../../utils'; /** * Convert verbosity to LogLevel @@ -40,9 +43,7 @@ type OutputObject = } | { type: 'error'; - name: string; - description: string; - message?: string; + data: Error; }; function outputFormatter(msg: OutputObject): string { @@ -92,14 +93,72 @@ function outputFormatter(msg: OutputObject): string { output += `${key}\t${value}\n`; } } else if (msg.type === 'json') { + if (msg.data instanceof Error && !(msg.data instanceof AbstractError)) { + msg.data = { + type: msg.data.name, + data: { message: msg.data.message, stack: msg.data.stack }, + }; + } output = JSON.stringify(msg.data); output += '\n'; } else if (msg.type === 'error') { - output += `${msg.name}: ${msg.description}`; - if (msg.message) { - output += ` - ${msg.message}`; + let currError = msg.data; + let indent = ' '; + while (currError != null) { + if (currError instanceof errors.ErrorPolykeyRemote) { + output += `${currError.name}: ${currError.description}`; + if (currError.message && currError.message !== '') { + output += ` - ${currError.message}`; + } + output += '\n'; + output += `${indent}command\t${currError.metadata.command}\n`; + output += `${indent}nodeId\t${nodesUtils.encodeNodeId( + currError.metadata.nodeId, + )}\n`; + output += `${indent}host\t${currError.metadata.host}\n`; + output += `${indent}port\t${currError.metadata.port}\n`; + output += `${indent}timestamp\t${currError.timestamp}\n`; + output += `${indent}remote error: `; + currError = currError.cause; + } else if (currError instanceof errors.ErrorPolykey) { + output += `${currError.name}: ${currError.description}`; + if (currError.message && currError.message !== '') { + output += ` - ${currError.message}`; + } + output += '\n'; + output += `${indent}exitCode\t${currError.exitCode}\n`; + output += `${indent}timestamp\t${currError.timestamp}\n`; + if (currError.data && !utils.isEmptyObject(currError.data)) { + output += `${indent}data\t${JSON.stringify(currError.data)}\n`; + } + if (currError.cause) { + output += `${indent}cause: `; + if (currError.cause instanceof errors.ErrorPolykey) { + currError = currError.cause; + } else if (currError.cause instanceof Error) { + output += `${currError.cause.name}`; + if (currError.cause.message && currError.cause.message !== '') { + output += `: ${currError.cause.message}`; + } + output += '\n'; + break; + } else { + output += `${JSON.stringify(currError.cause)}\n`; + break; + } + } else { + break; + } + } else { + output += `${currError.name}`; + if (currError.message && currError.message !== '') { + output += `: ${currError.message}`; + } + output += '\n'; + break; + } + indent = indent + ' '; } - output += '\n'; } return output; } @@ -155,8 +214,8 @@ async function retryAuthentication( function remoteErrorCause(e: any): [any, number] { let errorCause = e; let depth = 0; - while (e instanceof errors.ErrorPolykeyRemote) { - errorCause = e.cause; + while (errorCause instanceof errors.ErrorPolykeyRemote) { + errorCause = errorCause.cause; depth++; } return [errorCause, depth]; diff --git a/src/client/GRPCClientClient.ts b/src/client/GRPCClientClient.ts index e866ec475..9492841ed 100644 --- a/src/client/GRPCClientClient.ts +++ b/src/client/GRPCClientClient.ts @@ -95,6 +95,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.agentStatus.name, }, this.client.agentStatus, )(...args); @@ -108,6 +109,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.agentStop.name, }, this.client.agentStop, )(...args); @@ -121,6 +123,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.agentUnlock.name, }, this.client.agentUnlock, )(...args); @@ -134,6 +137,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.agentLockAll.name, }, this.client.agentLockAll, )(...args); @@ -152,6 +156,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsList.name, }, this.client.vaultsList, )(...args); @@ -165,6 +170,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsCreate.name, }, this.client.vaultsCreate, )(...args); @@ -178,6 +184,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsRename.name, }, this.client.vaultsRename, )(...args); @@ -191,6 +198,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsDelete.name, }, this.client.vaultsDelete, )(...args); @@ -204,6 +212,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsClone.name, }, this.client.vaultsClone, )(...args); @@ -217,6 +226,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsPull.name, }, this.client.vaultsPull, )(...args); @@ -235,6 +245,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsScan.name, }, this.client.vaultsScan, )(...args); @@ -248,6 +259,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsPermissionGet.name, }, this.client.vaultsPermissionGet, )(...args); @@ -261,6 +273,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsPermissionSet.name, }, this.client.vaultsPermissionSet, )(...args); @@ -274,6 +287,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsPermissionUnset.name, }, this.client.vaultsPermissionUnset, )(...args); @@ -292,6 +306,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsSecretsList.name, }, this.client.vaultsSecretsList, )(...args); @@ -305,6 +320,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsSecretsMkdir.name, }, this.client.vaultsSecretsMkdir, )(...args); @@ -318,6 +334,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsSecretsDelete.name, }, this.client.vaultsSecretsDelete, )(...args); @@ -331,6 +348,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsSecretsEdit.name, }, this.client.vaultsSecretsEdit, )(...args); @@ -344,6 +362,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsSecretsGet.name, }, this.client.vaultsSecretsGet, )(...args); @@ -357,6 +376,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsSecretsStat.name, }, this.client.vaultsSecretsStat, )(...args); @@ -370,6 +390,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsSecretsRename.name, }, this.client.vaultsSecretsRename, )(...args); @@ -383,6 +404,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsSecretsNew.name, }, this.client.vaultsSecretsNew, )(...args); @@ -396,6 +418,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsSecretsNewDir.name, }, this.client.vaultsSecretsNewDir, )(...args); @@ -409,6 +432,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsVersion.name, }, this.client.vaultsVersion, )(...args); @@ -427,6 +451,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.vaultsLog.name, }, this.client.vaultsLog, )(...args); @@ -440,6 +465,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.keysKeyPairRoot.name, }, this.client.keysKeyPairRoot, )(...args); @@ -453,6 +479,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.keysKeyPairReset.name, }, this.client.keysKeyPairReset, )(...args); @@ -466,6 +493,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.keysKeyPairRenew.name, }, this.client.keysKeyPairRenew, )(...args); @@ -479,6 +507,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.keysEncrypt.name, }, this.client.keysEncrypt, )(...args); @@ -492,6 +521,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.keysDecrypt.name, }, this.client.keysDecrypt, )(...args); @@ -505,6 +535,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.keysSign.name, }, this.client.keysSign, )(...args); @@ -518,6 +549,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.keysVerify.name, }, this.client.keysVerify, )(...args); @@ -531,6 +563,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.keysPasswordChange.name, }, this.client.keysPasswordChange, )(...args); @@ -544,6 +577,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.keysCertsGet.name, }, this.client.keysCertsGet, )(...args); @@ -562,6 +596,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.keysCertsGet.name, }, this.client.keysCertsChainGet, )(...args); @@ -580,6 +615,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsGestaltList.name, }, this.client.gestaltsGestaltList, )(...args); @@ -593,6 +629,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsGestaltGetByIdentity.name, }, this.client.gestaltsGestaltGetByIdentity, )(...args); @@ -606,6 +643,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsGestaltGetByNode.name, }, this.client.gestaltsGestaltGetByNode, )(...args); @@ -619,6 +657,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsDiscoveryByNode.name, }, this.client.gestaltsDiscoveryByNode, )(...args); @@ -632,6 +671,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsDiscoveryByIdentity.name, }, this.client.gestaltsDiscoveryByIdentity, )(...args); @@ -645,6 +685,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsActionsGetByNode.name, }, this.client.gestaltsActionsGetByNode, )(...args); @@ -658,6 +699,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsActionsGetByIdentity.name, }, this.client.gestaltsActionsGetByIdentity, )(...args); @@ -671,6 +713,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsActionsSetByNode.name, }, this.client.gestaltsActionsSetByNode, )(...args); @@ -684,6 +727,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsActionsSetByIdentity.name, }, this.client.gestaltsActionsSetByIdentity, )(...args); @@ -697,6 +741,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsActionsUnsetByNode.name, }, this.client.gestaltsActionsUnsetByNode, )(...args); @@ -710,6 +755,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsActionsUnsetByIdentity.name, }, this.client.gestaltsActionsUnsetByIdentity, )(...args); @@ -723,6 +769,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsGestaltTrustByNode.name, }, this.client.gestaltsGestaltTrustByNode, )(...args); @@ -736,6 +783,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.gestaltsGestaltTrustByIdentity.name, }, this.client.gestaltsGestaltTrustByIdentity, )(...args); @@ -749,6 +797,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.identitiesTokenPut.name, }, this.client.identitiesTokenPut, )(...args); @@ -762,6 +811,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.identitiesTokenGet.name, }, this.client.identitiesTokenGet, )(...args); @@ -775,6 +825,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.identitiesTokenDelete.name, }, this.client.identitiesTokenDelete, )(...args); @@ -788,6 +839,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.identitiesProvidersList.name, }, this.client.identitiesProvidersList, )(...args); @@ -801,6 +853,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.nodesAdd.name, }, this.client.nodesAdd, )(...args); @@ -814,6 +867,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.nodesPing.name, }, this.client.nodesPing, )(...args); @@ -827,6 +881,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.nodesClaim.name, }, this.client.nodesClaim, )(...args); @@ -840,6 +895,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.nodesFind.name, }, this.client.nodesFind, )(...args); @@ -853,6 +909,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.identitiesAuthenticate.name, }, this.client.identitiesAuthenticate, )(...args); @@ -866,6 +923,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.identitiesInfoConnectedGet.name, }, this.client.identitiesInfoConnectedGet, )(...args); @@ -879,6 +937,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.identitiesInfoGet.name, }, this.client.identitiesInfoGet, )(...args); @@ -892,6 +951,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.identitiesClaim.name, }, this.client.identitiesClaim, )(...args); @@ -905,6 +965,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.identitiesAuthenticatedGet.name, }, this.client.identitiesAuthenticatedGet, )(...args); @@ -918,6 +979,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.notificationsSend.name, }, this.client.notificationsSend, )(...args); @@ -931,6 +993,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.notificationsRead.name, }, this.client.notificationsRead, )(...args); @@ -944,6 +1007,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, + command: this.notificationsClear.name, }, this.client.notificationsClear, )(...args); diff --git a/src/errors.ts b/src/errors.ts index 53ec7b8ed..139744171 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,6 +1,52 @@ +import type { Class } from '@matrixai/errors'; +import type { ClientMetadata } from './types'; import ErrorPolykey from './ErrorPolykey'; import sysexits from './utils/sysexits'; +class ErrorPolykeyRemote extends ErrorPolykey { + static description = 'Remote error from RPC call'; + exitCode = sysexits.UNAVAILABLE; + metadata: ClientMetadata; + + constructor(metadata: ClientMetadata, message?: string, options?) { + super(message, options); + this.metadata = metadata; + } + + public static fromJSON>( + this: T, + json: any, + ): InstanceType { + if ( + typeof json !== 'object' || + json.type !== this.name || + typeof json.data !== 'object' || + typeof json.data.message !== 'string' || + isNaN(Date.parse(json.data.timestamp)) || + typeof json.data.metadata !== 'object' || + typeof json.data.data !== 'object' || + typeof json.data.exitCode !== 'number' || + ('stack' in json.data && typeof json.data.stack !== 'string') + ) { + throw new TypeError(`Cannot decode JSON to ${this.name}`); + } + const e = new this(json.data.metadata, json.data.message, { + timestamp: new Date(json.data.timestamp), + data: json.data.data, + cause: json.data.cause, + }); + e.exitCode = json.data.exitCode; + e.stack = json.data.stack; + return e; + } + + public toJSON(): any { + const json = super.toJSON(); + json.data.metadata = this.metadata; + return json; + } +} + class ErrorPolykeyUnimplemented extends ErrorPolykey { static description = 'This is an unimplemented functionality'; exitCode = sysexits.UNAVAILABLE; @@ -8,12 +54,7 @@ class ErrorPolykeyUnimplemented extends ErrorPolykey { class ErrorPolykeyUnknown extends ErrorPolykey { static description = 'Unable to deserialise to known error'; - exitCode = sysexits.UNKNOWN; -} - -class ErrorPolykeyRemote extends ErrorPolykey { - static description = 'Remote error from RPC call'; - exitCode = sysexits.UNAVAILABLE; + exitCode = sysexits.PROTOCOL; } class ErrorPolykeyAgentRunning extends ErrorPolykey { diff --git a/src/grpc/utils/utils.ts b/src/grpc/utils/utils.ts index f99331585..f37442e41 100644 --- a/src/grpc/utils/utils.ts +++ b/src/grpc/utils/utils.ts @@ -28,14 +28,14 @@ import type { AsyncGeneratorDuplexStreamClient, } from '../types'; import type { CertificatePemChain, PrivateKeyPem } from '../../keys/types'; -import type { POJO } from '../../types'; +import type { POJO, ClientMetadata } from '../../types'; +import type { NodeId } from '../../nodes/types'; import { Buffer } from 'buffer'; import { AbstractError } from '@matrixai/errors'; import * as grpc from '@grpc/grpc-js'; import * as grpcErrors from '../errors'; import * as errors from '../../errors'; import * as networkUtils from '../../network/utils'; -import * as nodesUtils from '../../nodes/utils'; import { promisify, promise, never } from '../../utils/utils'; /** @@ -184,9 +184,11 @@ function fromError( * Deserialized GRPC errors into ErrorPolykey * Use this on the receiving side to receive exceptions */ -function toError(e: ServiceError): errors.ErrorPolykey { +function toError( + e: ServiceError, + metadata: ClientMetadata, +): errors.ErrorPolykey { const errorData = e.metadata.get('error')[0].toString(); - const connInfo = e.metadata.get('metadata')[0].toString(); // Grpc.status is an enum // this will iterate the enum values then enum keys // they will all be of string type @@ -197,10 +199,17 @@ function toError(e: ServiceError): errors.ErrorPolykey { if (isNaN(parseInt(key)) && e.code === grpc.status[key]) { if (key === 'UNKNOWN' && errorData != null) { const error: Error = JSON.parse(errorData, reviver); - return new errors.ErrorPolykeyRemote(error.message, { - data: JSON.parse(connInfo), - cause: error, - }); + const remoteError = new errors.ErrorPolykeyRemote( + metadata, + error.message, + { + cause: error, + }, + ); + if (error instanceof errors.ErrorPolykey) { + remoteError.exitCode = error.exitCode; + } + return remoteError; } else { return new grpcErrors.ErrorGRPCClientCall(e.message, { data: { @@ -344,14 +353,6 @@ function reviver(key: string, value: any): any { }, }); return error; - } else if (key === 'timestamp') { - // Encode timestamps - const timestampParsed = Date.parse(value); - if (!isNaN(timestampParsed)) { - return new Date(timestampParsed); - } else { - return undefined; - } } else { return value; } @@ -364,7 +365,7 @@ function reviver(key: string, value: any): any { */ function promisifyUnaryCall( client: Client, - metadata: POJO, + metadata: ClientMetadata, f: (...args: any[]) => ClientUnaryCall, ): (...args: any[]) => PromiseUnaryCall { return (...args) => { @@ -376,11 +377,7 @@ function promisifyUnaryCall( const { p: pMeta, resolveP: resolveMetaP } = promise(); const callback = (error: ServiceError, ...values) => { if (error != null) { - if ('nodeId' in metadata) { - metadata.nodeId = nodesUtils.encodeNodeId(metadata.nodeId); - } - error.metadata.set('metadata', JSON.stringify(metadata)); - rejectP(toError(error)); + rejectP(toError(error, metadata)); return; } resolveP(values.length === 1 ? values[0] : values); @@ -405,15 +402,15 @@ function promisifyUnaryCall( */ function generatorReadable( stream: ClientReadableStream, - metadata: POJO, + metadata: { nodeId: NodeId; command: string } & POJO, ): AsyncGeneratorReadableStream>; function generatorReadable( stream: ServerReadableStream, - metadata: POJO, + metadata: { nodeId: NodeId; command: string } & POJO, ): AsyncGeneratorReadableStream>; function generatorReadable( stream: ClientReadableStream | ServerReadableStream, - metadata: POJO, + metadata: { nodeId: NodeId; command: string } & POJO, ) { const peerAddress = stream .getPeer() @@ -426,9 +423,12 @@ function generatorReadable( if (!('port' in metadata) && peerAddress != null) { metadata.port = networkUtils.parseAddress(peerAddress[0])[1]; } - if ('nodeId' in metadata) { - metadata.nodeId = nodesUtils.encodeNodeId(metadata.nodeId); - } + const clientMetadata: ClientMetadata = { + nodeId: metadata.nodeId, + host: metadata.host, + port: metadata.port, + command: metadata.command, + }; const gf = async function* () { try { let vR = yield; @@ -449,8 +449,7 @@ function generatorReadable( } } catch (e) { stream.destroy(); - e.metadata.set('metadata', JSON.stringify(metadata)); - throw toError(e); + throw toError(e, clientMetadata); } }; const g: any = gf(); @@ -467,7 +466,7 @@ function generatorReadable( */ function promisifyReadableStreamCall( client: grpc.Client, - metadata: POJO, + metadata: ClientMetadata, f: (...args: any[]) => ClientReadableStream, ): ( ...args: any[] @@ -539,7 +538,7 @@ function generatorWritable( */ function promisifyWritableStreamCall( client: grpc.Client, - metadata: POJO, + metadata: ClientMetadata, f: (...args: any[]) => ClientWritableStream, ): ( ...args: any[] @@ -555,11 +554,7 @@ function promisifyWritableStreamCall( }; const callback = (error, ...values) => { if (error != null) { - if ('nodeId' in metadata) { - metadata.nodeId = nodesUtils.encodeNodeId(metadata.nodeId); - } - error.metadata.set('metadata', JSON.stringify(metadata)); - return rejectP(toError(error)); + return rejectP(toError(error, metadata)); } return resolveP(values.length === 1 ? values[0] : values); }; @@ -591,17 +586,17 @@ function promisifyWritableStreamCall( */ function generatorDuplex( stream: ClientDuplexStream, - metadata: POJO, + metadata: { nodeId: NodeId; command: string } & POJO, sensitive: boolean, ): AsyncGeneratorDuplexStream>; function generatorDuplex( stream: ServerDuplexStream, - metadata: POJO, + metadata: { nodeId: NodeId; command: string } & POJO, sensitive: boolean, ): AsyncGeneratorDuplexStream>; function generatorDuplex( stream: ClientDuplexStream | ServerDuplexStream, - metadata: POJO, + metadata: { nodeId: NodeId; command: string } & POJO, sensitive: boolean = false, ) { const gR = generatorReadable(stream as any, metadata); @@ -654,7 +649,7 @@ function generatorDuplex( */ function promisifyDuplexStreamCall( client: grpc.Client, - metadata: POJO, + metadata: ClientMetadata, f: (...args: any[]) => ClientDuplexStream, ): ( ...args: any[] @@ -699,4 +694,6 @@ export { promisifyDuplexStreamCall, toError, fromError, + replacer, + reviver, }; diff --git a/src/types.ts b/src/types.ts index 8fba1fc08..0e41f366f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,7 @@ // eslint-disable-next-line no-restricted-imports -- Interim types for FileSystem import type fs from 'fs'; +import type { Host, Port } from './network/types'; +import type { NodeId } from './nodes/types'; /** * Plain data dictionary @@ -77,6 +79,13 @@ interface FileSystem { type FileHandle = fs.promises.FileHandle; +type ClientMetadata = { + nodeId: NodeId; + host: Host; + port: Port; + command: string; +} & POJO; + export type { POJO, Opaque, @@ -89,4 +98,5 @@ export type { Timer, FileSystem, FileHandle, + ClientMetadata, }; diff --git a/tests/bin/agent/lock.test.ts b/tests/bin/agent/lock.test.ts index 012bbcaf1..a35719991 100644 --- a/tests/bin/agent/lock.test.ts +++ b/tests/bin/agent/lock.test.ts @@ -1,7 +1,7 @@ import path from 'path'; import fs from 'fs'; import prompts from 'prompts'; -import { mocked } from 'ts-jest/utils'; +import { mocked } from 'jest-mock'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import Session from '@/sessions/Session'; import config from '@/config'; diff --git a/tests/bin/agent/lockall.test.ts b/tests/bin/agent/lockall.test.ts index c0096ff14..1f39d4b9e 100644 --- a/tests/bin/agent/lockall.test.ts +++ b/tests/bin/agent/lockall.test.ts @@ -1,11 +1,11 @@ import path from 'path'; import fs from 'fs'; import prompts from 'prompts'; -import { mocked } from 'ts-jest/utils'; +import { mocked } from 'jest-mock'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import Session from '@/sessions/Session'; import config from '@/config'; -import * as clientErrors from '@/client/errors'; +import * as errors from '@/errors'; import * as testBinUtils from '../utils'; import * as testUtils from '../../utils'; @@ -113,17 +113,15 @@ describe('lockall', () => { ); // Old token is invalid const { exitCode, stderr } = await testBinUtils.pkStdio( - ['agent', 'status'], + ['agent', 'status', '--format', 'json'], { PK_NODE_PATH: globalAgentDir, PK_TOKEN: token, }, globalAgentDir, ); - testBinUtils.expectProcessError( - exitCode, - stderr, - new clientErrors.ErrorClientAuthDenied(), - ); + testBinUtils.expectProcessError(exitCode, stderr, [ + new errors.ErrorClientAuthDenied(), + ]); }); }); diff --git a/tests/bin/agent/start.test.ts b/tests/bin/agent/start.test.ts index 06a83f544..6b419fde0 100644 --- a/tests/bin/agent/start.test.ts +++ b/tests/bin/agent/start.test.ts @@ -218,6 +218,8 @@ describe('start', () => { '--workers', '0', '--verbose', + '--format', + 'json', ], { PK_NODE_PATH: path.join(dataDir, 'polykey'), @@ -239,6 +241,8 @@ describe('start', () => { '--workers', '0', '--verbose', + '--format', + 'json', ], { PK_NODE_PATH: path.join(dataDir, 'polykey'), @@ -274,21 +278,17 @@ describe('start', () => { const errorStatusLocked = new statusErrors.ErrorStatusLocked(); // It's either the first or second process if (index === 0) { - testBinUtils.expectProcessError( - exitCode!, - stdErrLine1, + testBinUtils.expectProcessError(exitCode!, stdErrLine1, [ errorStatusLocked, - ); + ]); agentProcess2.kill('SIGQUIT'); [exitCode, signal] = await testBinUtils.processExit(agentProcess2); expect(exitCode).toBe(null); expect(signal).toBe('SIGQUIT'); } else if (index === 1) { - testBinUtils.expectProcessError( - exitCode!, - stdErrLine2, + testBinUtils.expectProcessError(exitCode!, stdErrLine2, [ errorStatusLocked, - ); + ]); agentProcess1.kill('SIGQUIT'); [exitCode, signal] = await testBinUtils.processExit(agentProcess1); expect(exitCode).toBe(null); @@ -316,6 +316,8 @@ describe('start', () => { '--workers', '0', '--verbose', + '--format', + 'json', ], { PK_NODE_PATH: path.join(dataDir, 'polykey'), @@ -325,7 +327,15 @@ describe('start', () => { logger.getChild('agentProcess'), ), testBinUtils.pkSpawn( - ['bootstrap', '--fresh', '--root-key-pair-bits', '1024', '--verbose'], + [ + 'bootstrap', + '--fresh', + '--root-key-pair-bits', + '1024', + '--verbose', + '--format', + 'json', + ], { PK_NODE_PATH: path.join(dataDir, 'polykey'), PK_PASSWORD: password, @@ -360,21 +370,17 @@ describe('start', () => { const errorStatusLocked = new statusErrors.ErrorStatusLocked(); // It's either the first or second process if (index === 0) { - testBinUtils.expectProcessError( - exitCode!, - stdErrLine1, + testBinUtils.expectProcessError(exitCode!, stdErrLine1, [ errorStatusLocked, - ); + ]); bootstrapProcess.kill('SIGTERM'); [exitCode, signal] = await testBinUtils.processExit(bootstrapProcess); expect(exitCode).toBe(null); expect(signal).toBe('SIGTERM'); } else if (index === 1) { - testBinUtils.expectProcessError( - exitCode!, - stdErrLine2, + testBinUtils.expectProcessError(exitCode!, stdErrLine2, [ errorStatusLocked, - ); + ]); agentProcess.kill('SIGTERM'); [exitCode, signal] = await testBinUtils.processExit(agentProcess); expect(exitCode).toBe(null); diff --git a/tests/bin/agent/stop.test.ts b/tests/bin/agent/stop.test.ts index c22843e45..b56f9b42c 100644 --- a/tests/bin/agent/stop.test.ts +++ b/tests/bin/agent/stop.test.ts @@ -197,17 +197,15 @@ describe('stop', () => { ); await status.waitFor('STARTING'); const { exitCode, stderr } = await testBinUtils.pkStdio( - ['agent', 'stop'], + ['agent', 'stop', '--format', 'json'], { PK_NODE_PATH: path.join(dataDir, 'polykey'), }, dataDir, ); - testBinUtils.expectProcessError( - exitCode, - stderr, + testBinUtils.expectProcessError(exitCode, stderr, [ new binErrors.ErrorCLIPolykeyAgentStatus('agent is starting'), - ); + ]); await status.waitFor('LIVE'); await testBinUtils.pkStdio( ['agent', 'stop'], @@ -256,18 +254,16 @@ describe('stop', () => { logger, }); const { exitCode, stderr } = await testBinUtils.pkStdio( - ['agent', 'stop'], + ['agent', 'stop', '--format', 'json'], { PK_NODE_PATH: path.join(dataDir, 'polykey'), PK_PASSWORD: 'wrong password', }, dataDir, ); - testBinUtils.expectProcessError( - exitCode, - stderr, + testBinUtils.expectProcessError(exitCode, stderr, [ new clientErrors.ErrorClientAuthDenied(), - ); + ]); // Should still be LIVE await sleep(500); const statusInfo = await status.readStatus(); diff --git a/tests/bin/bootstrap.test.ts b/tests/bin/bootstrap.test.ts index c108d0345..409afc4f7 100644 --- a/tests/bin/bootstrap.test.ts +++ b/tests/bin/bootstrap.test.ts @@ -5,7 +5,6 @@ import readline from 'readline'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { errors as statusErrors } from '@/status'; import { errors as bootstrapErrors } from '@/bootstrap'; -import * as binUtils from '@/bin/utils'; import * as testBinUtils from './utils'; describe('bootstrap', () => { @@ -68,6 +67,8 @@ describe('bootstrap', () => { '--root-key-pair-bits', '1024', '--verbose', + '--format', + 'json', ], { PK_PASSWORD: password, @@ -76,17 +77,9 @@ describe('bootstrap', () => { )); const errorBootstrapExistingState = new bootstrapErrors.ErrorBootstrapExistingState(); - expect(exitCode).toBe(errorBootstrapExistingState.exitCode); - const stdErrLine = stderr.trim().split('\n').pop(); - const eOutput = binUtils - .outputFormatter({ - type: 'error', - name: errorBootstrapExistingState.name, - description: errorBootstrapExistingState.description, - message: errorBootstrapExistingState.message, - }) - .trim(); - expect(stdErrLine).toBe(eOutput); + testBinUtils.expectProcessError(exitCode, stderr, [ + errorBootstrapExistingState, + ]); ({ exitCode, stdout, stderr } = await testBinUtils.pkStdio( [ 'bootstrap', @@ -117,7 +110,14 @@ describe('bootstrap', () => { const password = 'password'; const [bootstrapProcess1, bootstrapProcess2] = await Promise.all([ testBinUtils.pkSpawn( - ['bootstrap', '--root-key-pair-bits', '1024', '--verbose'], + [ + 'bootstrap', + '--root-key-pair-bits', + '1024', + '--verbose', + '--format', + 'json', + ], { PK_NODE_PATH: path.join(dataDir, 'polykey'), PK_PASSWORD: password, @@ -126,7 +126,14 @@ describe('bootstrap', () => { logger.getChild('bootstrapProcess1'), ), testBinUtils.pkSpawn( - ['bootstrap', '--root-key-pair-bits', '1024', '--verbose'], + [ + 'bootstrap', + '--root-key-pair-bits', + '1024', + '--verbose', + '--format', + 'json', + ], { PK_NODE_PATH: path.join(dataDir, 'polykey'), PK_PASSWORD: password, @@ -158,27 +165,22 @@ describe('bootstrap', () => { }); }); const errorStatusLocked = new statusErrors.ErrorStatusLocked(); - expect(exitCode).toBe(errorStatusLocked.exitCode); expect(signal).toBe(null); - const eOutput = binUtils - .outputFormatter({ - type: 'error', - name: errorStatusLocked.name, - description: errorStatusLocked.description, - message: errorStatusLocked.message, - }) - .trim(); // It's either the first or second process if (index === 0) { expect(stdErrLine1).toBeDefined(); - expect(stdErrLine1).toBe(eOutput); - const [exitCode] = await testBinUtils.processExit(bootstrapProcess2); - expect(exitCode).toBe(0); + testBinUtils.expectProcessError(exitCode!, stdErrLine1, [ + errorStatusLocked, + ]); + const [exitCode2] = await testBinUtils.processExit(bootstrapProcess2); + expect(exitCode2).toBe(0); } else if (index === 1) { expect(stdErrLine2).toBeDefined(); - expect(stdErrLine2).toBe(eOutput); - const [exitCode] = await testBinUtils.processExit(bootstrapProcess1); - expect(exitCode).toBe(0); + testBinUtils.expectProcessError(exitCode!, stdErrLine2, [ + errorStatusLocked, + ]); + const [exitCode2] = await testBinUtils.processExit(bootstrapProcess1); + expect(exitCode2).toBe(0); } }, global.defaultTimeout * 2, @@ -217,28 +219,27 @@ describe('bootstrap', () => { expect(signal).toBe('SIGINT'); // Attempting to bootstrap should fail with existing state const bootstrapProcess2 = await testBinUtils.pkStdio( - ['bootstrap', '--root-key-pair-bits', '1024', '--verbose'], + [ + 'bootstrap', + '--root-key-pair-bits', + '1024', + '--verbose', + '--format', + 'json', + ], { PK_NODE_PATH: path.join(dataDir, 'polykey'), PK_PASSWORD: password, }, dataDir, ); - const stdErrLine = bootstrapProcess2.stderr.trim().split('\n').pop(); const errorBootstrapExistingState = new bootstrapErrors.ErrorBootstrapExistingState(); - expect(bootstrapProcess2.exitCode).toBe( - errorBootstrapExistingState.exitCode, + testBinUtils.expectProcessError( + bootstrapProcess2.exitCode, + bootstrapProcess2.stderr, + [errorBootstrapExistingState], ); - const eOutput = binUtils - .outputFormatter({ - type: 'error', - name: errorBootstrapExistingState.name, - description: errorBootstrapExistingState.description, - message: errorBootstrapExistingState.message, - }) - .trim(); - expect(stdErrLine).toBe(eOutput); // Attempting to bootstrap with --fresh should succeed const bootstrapProcess3 = await testBinUtils.pkStdio( ['bootstrap', '--root-key-pair-bits', '1024', '--fresh', '--verbose'], diff --git a/tests/bin/sessions.test.ts b/tests/bin/sessions.test.ts index b688eb2ef..0487b9f97 100644 --- a/tests/bin/sessions.test.ts +++ b/tests/bin/sessions.test.ts @@ -6,7 +6,7 @@ import os from 'os'; import path from 'path'; import fs from 'fs'; -import { mocked } from 'ts-jest/utils'; +import { mocked } from 'jest-mock'; import prompts from 'prompts'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { Session } from '@/sessions'; @@ -83,7 +83,7 @@ describe('sessions', () => { let exitCode, stderr; // Password and Token set ({ exitCode, stderr } = await testBinUtils.pkStdio( - ['agent', 'status'], + ['agent', 'status', '--format', 'json'], { PK_NODE_PATH: globalAgentDir, PK_PASSWORD: 'invalid', @@ -91,14 +91,12 @@ describe('sessions', () => { }, globalAgentDir, )); - testBinUtils.expectProcessError( - exitCode, - stderr, + testBinUtils.expectProcessError(exitCode, stderr, [ new clientErrors.ErrorClientAuthDenied(), - ); + ]); // Password set ({ exitCode, stderr } = await testBinUtils.pkStdio( - ['agent', 'status'], + ['agent', 'status', '--format', 'json'], { PK_NODE_PATH: globalAgentDir, PK_PASSWORD: 'invalid', @@ -106,14 +104,12 @@ describe('sessions', () => { }, globalAgentDir, )); - testBinUtils.expectProcessError( - exitCode, - stderr, + testBinUtils.expectProcessError(exitCode, stderr, [ new clientErrors.ErrorClientAuthDenied(), - ); + ]); // Token set ({ exitCode, stderr } = await testBinUtils.pkStdio( - ['agent', 'status'], + ['agent', 'status', '--format', 'json'], { PK_NODE_PATH: globalAgentDir, PK_PASSWORD: undefined, @@ -121,11 +117,9 @@ describe('sessions', () => { }, globalAgentDir, )); - testBinUtils.expectProcessError( - exitCode, - stderr, + testBinUtils.expectProcessError(exitCode, stderr, [ new clientErrors.ErrorClientAuthDenied(), - ); + ]); }); test('prompt for password to authenticate attended commands', async () => { const password = globalAgentPassword; diff --git a/tests/bin/utils.retryAuthentication.test.ts b/tests/bin/utils.retryAuthentication.test.ts index 9a97f050f..32e45eee3 100644 --- a/tests/bin/utils.retryAuthentication.test.ts +++ b/tests/bin/utils.retryAuthentication.test.ts @@ -1,5 +1,5 @@ import prompts from 'prompts'; -import { mocked } from 'ts-jest/utils'; +import { mocked } from 'jest-mock'; import mockedEnv from 'mocked-env'; import { utils as clientUtils, errors as clientErrors } from '@/client'; import * as binUtils from '@/bin/utils'; diff --git a/tests/bin/utils.test.ts b/tests/bin/utils.test.ts index 42661b0af..45e6bd870 100644 --- a/tests/bin/utils.test.ts +++ b/tests/bin/utils.test.ts @@ -1,4 +1,8 @@ -import * as binUtils from '@/bin/utils'; +import type { Host, Port } from '@/network/types'; +import * as binUtils from '@/bin/utils/utils'; +import * as nodesUtils from '@/nodes/utils'; +import * as errors from '@/errors'; +import * as testUtils from '../utils'; describe('bin/utils', () => { test('list in human and json format', () => { @@ -70,4 +74,112 @@ describe('bin/utils', () => { }), ).toBe('{"key1":"value1","key2":"value2"}\n'); }); + test('errors in human and json format', () => { + const timestamp = new Date(); + const data = { string: 'one', number: 1 }; + const host = '127.0.0.1' as Host; + const port = 55555 as Port; + const nodeId = testUtils.generateRandomNodeId(); + const standardError = new TypeError('some error'); + const pkError = new errors.ErrorPolykey('some pk error', { + timestamp, + data, + }); + const remoteError = new errors.ErrorPolykeyRemote( + { + nodeId, + host, + port, + command: 'some command', + }, + 'some remote error', + { timestamp, cause: pkError }, + ); + const twoRemoteErrors = new errors.ErrorPolykeyRemote( + { + nodeId, + host, + port, + command: 'command 2', + }, + 'remote error', + { + timestamp, + cause: new errors.ErrorPolykeyRemote( + { + nodeId, + host, + port, + command: 'command 1', + }, + undefined, + { + timestamp, + cause: new errors.ErrorPolykey('pk error', { + timestamp, + cause: standardError, + }), + }, + ), + }, + ); + // Error + expect( + binUtils.outputFormatter({ type: 'error', data: standardError }), + ).toBe(`${standardError.name}: ${standardError.message}\n`); + expect(binUtils.outputFormatter({ type: 'error', data: pkError })).toBe( + `${pkError.name}: ${pkError.description} - ${pkError.message}\n` + + ` exitCode\t${pkError.exitCode}\n` + + ` timestamp\t${timestamp.toString()}\n` + + ` data\t${JSON.stringify(data)}\n`, + ); + expect(binUtils.outputFormatter({ type: 'error', data: remoteError })).toBe( + `${remoteError.name}: ${remoteError.description} - ${remoteError.message}\n` + + ` command\t${remoteError.metadata.command}\n` + + ` nodeId\t${nodesUtils.encodeNodeId(nodeId)}\n` + + ` host\t${host}\n` + + ` port\t${port}\n` + + ` timestamp\t${timestamp.toString()}\n` + + ` remote error: ${remoteError.cause.name}: ${remoteError.cause.description} - ${remoteError.cause.message}\n` + + ` exitCode\t${pkError.exitCode}\n` + + ` timestamp\t${timestamp.toString()}\n` + + ` data\t${JSON.stringify(data)}\n`, + ); + expect( + binUtils.outputFormatter({ type: 'error', data: twoRemoteErrors }), + ).toBe( + `${twoRemoteErrors.name}: ${twoRemoteErrors.description} - ${twoRemoteErrors.message}\n` + + ` command\t${twoRemoteErrors.metadata.command}\n` + + ` nodeId\t${nodesUtils.encodeNodeId(nodeId)}\n` + + ` host\t${host}\n` + + ` port\t${port}\n` + + ` timestamp\t${timestamp.toString()}\n` + + ` remote error: ${twoRemoteErrors.cause.name}: ${twoRemoteErrors.cause.description}\n` + + ` command\t${twoRemoteErrors.cause.metadata.command}\n` + + ` nodeId\t${nodesUtils.encodeNodeId(nodeId)}\n` + + ` host\t${host}\n` + + ` port\t${port}\n` + + ` timestamp\t${timestamp.toString()}\n` + + ` remote error: ${twoRemoteErrors.cause.cause.name}: ${twoRemoteErrors.cause.cause.description} - ${twoRemoteErrors.cause.cause.message}\n` + + ` exitCode\t${pkError.exitCode}\n` + + ` timestamp\t${timestamp.toString()}\n` + + ` cause: ${standardError.name}: ${standardError.message}\n`, + ); + expect( + binUtils.outputFormatter({ type: 'json', data: standardError }), + ).toBe( + `{"type":"${standardError.name}","data":{"message":"${ + standardError.message + }","stack":"${standardError.stack?.replaceAll('\n', '\\n')}"}}\n`, + ); + expect(binUtils.outputFormatter({ type: 'json', data: pkError })).toBe( + JSON.stringify(pkError.toJSON()) + '\n', + ); + expect(binUtils.outputFormatter({ type: 'json', data: remoteError })).toBe( + JSON.stringify(remoteError.toJSON()) + '\n', + ); + expect( + binUtils.outputFormatter({ type: 'json', data: twoRemoteErrors }), + ).toBe(JSON.stringify(twoRemoteErrors.toJSON()) + '\n'); + }); }); diff --git a/tests/bin/utils.ts b/tests/bin/utils.ts index 3b552cf64..2464b9d82 100644 --- a/tests/bin/utils.ts +++ b/tests/bin/utils.ts @@ -12,6 +12,7 @@ import nexpect from 'nexpect'; import Logger from '@matrixai/logger'; import main from '@/bin/polykey'; import * as binUtils from '@/bin/utils'; +import * as grpcUtils from '@/grpc/utils'; /** * Runs pk command functionally @@ -339,23 +340,24 @@ async function processExit( /** * Checks exit code and stderr against ErrorPolykey + * Errors should contain all of the errors in the expected error chain + * starting with the outermost error (excluding ErrorPolykeyRemote) + * When using this function, the command must be run with --format=json */ function expectProcessError( exitCode: number, stderr: string, - error: ErrorPolykey, + errors: Array>, ) { - expect(exitCode).toBe(error.exitCode); + expect(exitCode).toBe(errors[0].exitCode); const stdErrLine = stderr.trim().split('\n').pop(); - const errorOutput = binUtils - .outputFormatter({ - type: 'error', - name: error.name, - description: error.description, - message: error.message, - }) - .trim(); - expect(stdErrLine).toBe(errorOutput); + const receivedError = JSON.parse(stdErrLine!, grpcUtils.reviver); + let [currentError] = binUtils.remoteErrorCause(receivedError); + for (const error of errors) { + expect(currentError.name).toBe(error.name); + expect(currentError.message).toBe(error.message); + currentError = currentError.cause; + } } export { From 19e9b3e322c1792e9394bc0c3122460c3741f3e9 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 18 May 2022 16:17:37 +1000 Subject: [PATCH 047/137] tests: fixing bin tests Had to fix `expectProcessError` to work with the raw JSON forms of the errors rather than attempting to parse the errors. This is due to the bin CLI errors being separate from the normal errors and the reviver being unable to revive them. I also had to fix how the `ErrorPolykeyRemote` converted the metadata with toJSON/fromJSON. --- src/PolykeyAgent.ts | 2 + src/bin/nodes/CommandFind.ts | 4 +- src/bin/nodes/CommandPing.ts | 2 +- src/client/service/agentLockAll.ts | 1 - .../service/gestaltsActionsGetByIdentity.ts | 6 +- src/errors.ts | 12 +++- tests/agent/GRPCClientAgent.test.ts | 1 + tests/agent/utils.ts | 6 +- tests/bin/agent/lock.test.ts | 2 +- tests/bin/identities/claim.test.ts | 2 +- tests/bin/identities/trustUntrustList.test.ts | 49 ++------------ tests/bin/nodes/find.test.ts | 3 +- tests/bin/nodes/ping.test.ts | 3 +- tests/bin/utils.ts | 16 ++--- tests/client/rpcVaults.test.ts | 1 + ...staltsActionsSetUnsetGetByIdentity.test.ts | 1 + tests/nodes/NodeConnection.test.ts | 66 ++++++++----------- 17 files changed, 74 insertions(+), 103 deletions(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index b172f1fd2..68e3b5571 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -560,6 +560,7 @@ class PolykeyAgent { acl: this.acl, gestaltGraph: this.gestaltGraph, proxy: this.proxy, + logger: this.logger.getChild(createAgentService.name), }); const clientService = createClientService({ pkAgent: this, @@ -580,6 +581,7 @@ class PolykeyAgent { grpcServerAgent: this.grpcServerAgent, proxy: this.proxy, fs: this.fs, + logger: this.logger.getChild(createClientService.name), }); // Starting modules await this.keyManager.start({ diff --git a/src/bin/nodes/CommandFind.ts b/src/bin/nodes/CommandFind.ts index 5788c2c8a..32169a968 100644 --- a/src/bin/nodes/CommandFind.ts +++ b/src/bin/nodes/CommandFind.ts @@ -71,7 +71,9 @@ class CommandFind extends CommandPolykey { result.port as Port, )}`; } catch (err) { - if (!(err instanceof nodesErrors.ErrorNodeGraphNodeIdNotFound)) { + if ( + !(err.cause instanceof nodesErrors.ErrorNodeGraphNodeIdNotFound) + ) { throw err; } // Else failed to find the node. diff --git a/src/bin/nodes/CommandPing.ts b/src/bin/nodes/CommandPing.ts index 3ff6049a1..a15779c55 100644 --- a/src/bin/nodes/CommandPing.ts +++ b/src/bin/nodes/CommandPing.ts @@ -55,7 +55,7 @@ class CommandPing extends CommandPolykey { meta, ); } catch (err) { - if (err instanceof nodesErrors.ErrorNodeGraphNodeIdNotFound) { + if (err.cause instanceof nodesErrors.ErrorNodeGraphNodeIdNotFound) { error = new binErrors.ErrorNodePingFailed( `Failed to resolve node ID ${nodesUtils.encodeNodeId( nodeId, diff --git a/src/client/service/agentLockAll.ts b/src/client/service/agentLockAll.ts index f1d4c4d03..1bc011b08 100644 --- a/src/client/service/agentLockAll.ts +++ b/src/client/service/agentLockAll.ts @@ -3,7 +3,6 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { SessionManager } from '../../sessions'; import type Logger from '@matrixai/logger'; -import { withF } from '@matrixai/resources'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; diff --git a/src/client/service/gestaltsActionsGetByIdentity.ts b/src/client/service/gestaltsActionsGetByIdentity.ts index 14da28205..a1ee40c4a 100644 --- a/src/client/service/gestaltsActionsGetByIdentity.ts +++ b/src/client/service/gestaltsActionsGetByIdentity.ts @@ -47,9 +47,9 @@ function gestaltsActionsGetByIdentity({ identityId: call.request.getIdentityId(), }, ); - const result = await gestaltGraph.getGestaltActionsByIdentity( - providerId, - identityId, + + const result = await db.withTransactionF(async (tran) => + gestaltGraph.getGestaltActionsByIdentity(providerId, identityId, tran), ); if (result == null) { // Node doesn't exist, so no permissions diff --git a/src/errors.ts b/src/errors.ts index 139744171..12af747ab 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -2,6 +2,7 @@ import type { Class } from '@matrixai/errors'; import type { ClientMetadata } from './types'; import ErrorPolykey from './ErrorPolykey'; import sysexits from './utils/sysexits'; +import * as nodesUtils from './nodes/utils'; class ErrorPolykeyRemote extends ErrorPolykey { static description = 'Remote error from RPC call'; @@ -30,7 +31,11 @@ class ErrorPolykeyRemote extends ErrorPolykey { ) { throw new TypeError(`Cannot decode JSON to ${this.name}`); } - const e = new this(json.data.metadata, json.data.message, { + const parsedMetadata: ClientMetadata = { + ...json.data.metadata, + nodeId: nodesUtils.decodeNodeId(json.data.metadata.nodeId), + }; + const e = new this(parsedMetadata, json.data.message, { timestamp: new Date(json.data.timestamp), data: json.data.data, cause: json.data.cause, @@ -42,7 +47,10 @@ class ErrorPolykeyRemote extends ErrorPolykey { public toJSON(): any { const json = super.toJSON(); - json.data.metadata = this.metadata; + json.data.metadata = { + ...this.metadata, + nodeId: nodesUtils.encodeNodeId(this.metadata.nodeId), + }; return json; } } diff --git a/tests/agent/GRPCClientAgent.test.ts b/tests/agent/GRPCClientAgent.test.ts index 2a9392e74..60a84410c 100644 --- a/tests/agent/GRPCClientAgent.test.ts +++ b/tests/agent/GRPCClientAgent.test.ts @@ -157,6 +157,7 @@ describe(GRPCClientAgent.name, () => { gestaltGraph, proxy, db, + logger, }); client = await testAgentUtils.openTestAgentClient(port); await proxy.start({ diff --git a/tests/agent/utils.ts b/tests/agent/utils.ts index 296707684..f2b896024 100644 --- a/tests/agent/utils.ts +++ b/tests/agent/utils.ts @@ -11,6 +11,7 @@ import type { GestaltGraph } from '@/gestalts'; import type { NodeId } from 'nodes/types'; import type Proxy from 'network/Proxy'; import type { DB } from '@matrixai/db'; +import type { Server } from '@grpc/grpc-js'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import { promisify } from '@/utils'; @@ -33,6 +34,7 @@ async function openTestAgentServer({ gestaltGraph, proxy, db, + logger, }: { keyManager: KeyManager; vaultManager: VaultManager; @@ -45,7 +47,8 @@ async function openTestAgentServer({ gestaltGraph: GestaltGraph; proxy: Proxy; db: DB; -}) { + logger: Logger; +}): Promise<[Server, Port]> { const agentService: IAgentServiceServer = createAgentService({ keyManager, vaultManager, @@ -58,6 +61,7 @@ async function openTestAgentServer({ gestaltGraph, proxy, db, + logger, }); const server = new grpc.Server(); diff --git a/tests/bin/agent/lock.test.ts b/tests/bin/agent/lock.test.ts index a35719991..f12a7fc89 100644 --- a/tests/bin/agent/lock.test.ts +++ b/tests/bin/agent/lock.test.ts @@ -48,7 +48,7 @@ describe('lock', () => { expect(await session.readToken()).toBeUndefined(); await session.stop(); }); - test('lock ensures reauthentication is required', async () => { + test('lock ensures re-authentication is required', async () => { const password = globalAgentPassword; mockedPrompts.mockClear(); mockedPrompts.mockImplementation(async (_opts: any) => { diff --git a/tests/bin/identities/claim.test.ts b/tests/bin/identities/claim.test.ts index de1817c30..f2e730b9c 100644 --- a/tests/bin/identities/claim.test.ts +++ b/tests/bin/identities/claim.test.ts @@ -125,7 +125,7 @@ describe('claim', () => { }, dataDir, ); - expect(exitCode).toBe(1); + expect(exitCode).toBe(sysexits.NOPERM); }); test('should fail on invalid inputs', async () => { let exitCode; diff --git a/tests/bin/identities/trustUntrustList.test.ts b/tests/bin/identities/trustUntrustList.test.ts index a11c13260..5fb91633d 100644 --- a/tests/bin/identities/trustUntrustList.test.ts +++ b/tests/bin/identities/trustUntrustList.test.ts @@ -1,14 +1,13 @@ import type { Host, Port } from '@/network/types'; import type { IdentityId, ProviderId } from '@/identities/types'; import type { ClaimLinkIdentity } from '@/claims/types'; -import type { Gestalt } from '@/gestalts/types'; import type { NodeId } from '@/nodes/types'; import os from 'os'; import path from 'path'; import fs from 'fs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import PolykeyAgent from '@/PolykeyAgent'; -import { poll, sysexits } from '@/utils'; +import { sysexits } from '@/utils'; import * as nodesUtils from '@/nodes/utils'; import * as keysUtils from '@/keys/utils'; import * as claimsUtils from '@/claims/utils'; @@ -156,27 +155,7 @@ describe('trust/untrust/list', () => { expect(exitCode).toBe(0); // Since discovery is a background process we need to wait for the // gestalt to be discovered - await poll( - async () => { - const gestalts = await poll>( - async () => { - return await pkAgent.gestaltGraph.getGestalts(); - }, - (_, result) => { - if (result.length === 1) return true; - return false; - }, - 100, - ); - return gestalts[0]; - }, - (_, result) => { - if (result === undefined) return false; - if (Object.keys(result.matrix).length === 2) return true; - return false; - }, - 100, - ); + await pkAgent.discovery.waitForDrained(); // Check that gestalt was discovered and permission was set ({ exitCode, stdout } = await testBinUtils.pkStdio( ['identities', 'list', '--format', 'json'], @@ -290,30 +269,10 @@ describe('trust/untrust/list', () => { }, dataDir, )); - expect(exitCode).toBe(1); + expect(exitCode).toBe(sysexits.NOUSER); // Since discovery is a background process we need to wait for the // gestalt to be discovered - await poll( - async () => { - const gestalts = await poll>( - async () => { - return await pkAgent.gestaltGraph.getGestalts(); - }, - (_, result) => { - if (result.length === 1) return true; - return false; - }, - 100, - ); - return gestalts[0]; - }, - (_, result) => { - if (result === undefined) return false; - if (Object.keys(result.matrix).length === 2) return true; - return false; - }, - 100, - ); + await pkAgent.discovery.waitForDrained(); // This time the command should succeed ({ exitCode } = await testBinUtils.pkStdio( ['identities', 'trust', providerString], diff --git a/tests/bin/nodes/find.test.ts b/tests/bin/nodes/find.test.ts index 6be67177a..56bffd263 100644 --- a/tests/bin/nodes/find.test.ts +++ b/tests/bin/nodes/find.test.ts @@ -7,6 +7,7 @@ import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import PolykeyAgent from '@/PolykeyAgent'; import * as nodesUtils from '@/nodes/utils'; import * as keysUtils from '@/keys/utils'; +import { sysexits } from '@/errors'; import * as testBinUtils from '../utils'; import * as testNodesUtils from '../../nodes/utils'; import * as testUtils from '../../utils'; @@ -175,7 +176,7 @@ describe('find', () => { }, dataDir, ); - expect(exitCode).toBe(1); + expect(exitCode).toBe(sysexits.GENERAL); expect(JSON.parse(stdout)).toEqual({ success: false, message: `Failed to find node ${nodesUtils.encodeNodeId(unknownNodeId!)}`, diff --git a/tests/bin/nodes/ping.test.ts b/tests/bin/nodes/ping.test.ts index 196ec8ce8..f531a04d2 100644 --- a/tests/bin/nodes/ping.test.ts +++ b/tests/bin/nodes/ping.test.ts @@ -7,6 +7,7 @@ import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import PolykeyAgent from '@/PolykeyAgent'; import * as nodesUtils from '@/nodes/utils'; import * as keysUtils from '@/keys/utils'; +import { sysexits } from '@/errors'; import * as testBinUtils from '../utils'; import * as testNodesUtils from '../../nodes/utils'; import * as testUtils from '../../utils'; @@ -119,7 +120,7 @@ describe('ping', () => { }, dataDir, ); - expect(exitCode).toBe(1); // Should fail with no response. for automation purposes. + expect(exitCode).toBe(sysexits.GENERAL); // Should fail with no response. for automation purposes. expect(stderr).toContain('No response received'); expect(JSON.parse(stdout)).toEqual({ success: false, diff --git a/tests/bin/utils.ts b/tests/bin/utils.ts index 2464b9d82..b0acefed2 100644 --- a/tests/bin/utils.ts +++ b/tests/bin/utils.ts @@ -1,18 +1,16 @@ import type { ChildProcess } from 'child_process'; import type ErrorPolykey from '@/ErrorPolykey'; +import child_process from 'child_process'; import os from 'os'; import fs from 'fs'; import path from 'path'; import process from 'process'; -import child_process from 'child_process'; import readline from 'readline'; import * as mockProcess from 'jest-mock-process'; import mockedEnv from 'mocked-env'; import nexpect from 'nexpect'; import Logger from '@matrixai/logger'; import main from '@/bin/polykey'; -import * as binUtils from '@/bin/utils'; -import * as grpcUtils from '@/grpc/utils'; /** * Runs pk command functionally @@ -351,12 +349,14 @@ function expectProcessError( ) { expect(exitCode).toBe(errors[0].exitCode); const stdErrLine = stderr.trim().split('\n').pop(); - const receivedError = JSON.parse(stdErrLine!, grpcUtils.reviver); - let [currentError] = binUtils.remoteErrorCause(receivedError); + let currentError = JSON.parse(stdErrLine!); + while (currentError.type === 'ErrorPolykeyRemote') { + currentError = currentError.data.cause; + } for (const error of errors) { - expect(currentError.name).toBe(error.name); - expect(currentError.message).toBe(error.message); - currentError = currentError.cause; + expect(currentError.type).toBe(error.name); + expect(currentError.data.message).toBe(error.message); + currentError = currentError.data.cause; } } diff --git a/tests/client/rpcVaults.test.ts b/tests/client/rpcVaults.test.ts index 98f4b80af..22b9cb1c9 100644 --- a/tests/client/rpcVaults.test.ts +++ b/tests/client/rpcVaults.test.ts @@ -118,6 +118,7 @@ describe('Vaults client service', () => { test('should get vaults', async () => { const listVaults = grpcUtils.promisifyReadableStreamCall( client, + nodeId, localHost, localPort, client.vaultsList, diff --git a/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts b/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts index f20373610..381ec9b60 100644 --- a/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts +++ b/tests/client/service/gestaltsActionsSetUnsetGetByIdentity.test.ts @@ -79,6 +79,7 @@ describe('gestaltsActionsByIdentity', () => { authenticate, gestaltGraph, logger, + db, }), gestaltsActionsUnsetByIdentity: gestaltsActionsUnsetByIdentity({ authenticate, diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index fcc37d701..7c842724d 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -1,6 +1,7 @@ import type { AddressInfo } from 'net'; import type { ConnectionInfo, Host, Port, TLSConfig } from '@/network/types'; import type { NodeId, NodeInfo } from '@/nodes/types'; +import type { Server } from '@grpc/grpc-js'; import net from 'net'; import os from 'os'; import path from 'path'; @@ -18,9 +19,6 @@ import NodeManager from '@/nodes/NodeManager'; import VaultManager from '@/vaults/VaultManager'; import KeyManager from '@/keys/KeyManager'; import * as keysUtils from '@/keys/utils'; -import GRPCServer from '@/grpc/GRPCServer'; -import { AgentServiceService } from '@/proto/js/polykey/v1/agent_service_grpc_pb'; -import createAgentService from '@/agent/service'; import GRPCClientAgent from '@/agent/GRPCClientAgent'; import ACL from '@/acl/ACL'; import GestaltGraph from '@/gestalts/GestaltGraph'; @@ -37,11 +35,12 @@ import * as agentErrors from '@/agent/errors'; import * as grpcUtils from '@/grpc/utils'; import * as testUtils from '../utils'; import * as grpcTestUtils from '../grpc/utils'; +import * as agentTestUtils from '../agent/utils'; const destroyCallback = async () => {}; // Dummy nodeConnectionManager -// We only need the hole punch function and frankly its not used in testing here +// We only need the hole punch function, and frankly it's not used in testing here // This is really dirty so don't do this outside of testing EVER const dummyNodeConnectionManager = { openConnection: async (_host, _port) => { @@ -97,9 +96,10 @@ describe(`${NodeConnection.name} test`, () => { let sourceNodeId: NodeId; let clientKeyManager: KeyManager; const authToken = 'AUTH'; - let clientproxy: Proxy; + let clientProxy: Proxy; - let agentServer: GRPCServer; + let agentServer: Server; + let serverPort: Port; let tlsConfig: TLSConfig; const localHost = '127.0.0.1' as Host; @@ -266,7 +266,7 @@ describe(`${NodeConnection.name} test`, () => { logger: logger, }); await serverGestaltGraph.setNode(node); - const agentService = createAgentService({ + [agentServer, serverPort] = await agentTestUtils.openTestAgentServer({ db: serverDb, keyManager: serverKeyManager, vaultManager: serverVaultManager, @@ -278,17 +278,11 @@ describe(`${NodeConnection.name} test`, () => { acl: serverACL, gestaltGraph: serverGestaltGraph, proxy: serverProxy, - }); - agentServer = new GRPCServer({ logger: logger, }); - await agentServer.start({ - services: [[AgentServiceService, agentService]], - host: localHost, - }); await serverProxy.start({ serverHost: localHost, - serverPort: agentServer.getPort(), + serverPort: serverPort, proxyHost: localHost, tlsConfig: serverTLSConfig, }); @@ -312,18 +306,18 @@ describe(`${NodeConnection.name} test`, () => { }; sourceNodeId = clientKeyManager.getNodeId(); - clientproxy = new Proxy({ + clientProxy = new Proxy({ authToken: authToken, logger: logger, }); - await clientproxy.start({ + await clientProxy.start({ forwardHost: localHost, tlsConfig: clientTLSConfig, proxyHost: localHost, serverHost: localHost, serverPort: 0 as Port, }); - sourcePort = clientproxy.getProxyPort(); + sourcePort = clientProxy.getProxyPort(); // Other setup const globalKeyPair = await testUtils.setupGlobalKeypair(); @@ -340,7 +334,7 @@ describe(`${NodeConnection.name} test`, () => { }, global.polykeyStartupTimeout * 2); afterEach(async () => { - await clientproxy.stop(); + await clientProxy.stop(); await clientKeyManager.stop(); await clientKeyManager.destroy(); await fs.promises.rm(clientDataDir, { @@ -361,7 +355,7 @@ describe(`${NodeConnection.name} test`, () => { await serverNodeConnectionManager.stop(); await serverNotificationsManager.stop(); await serverNotificationsManager.destroy(); - await agentServer.stop(); + await agentTestUtils.closeTestAgentServer(agentServer); await serverProxy.stop(); await serverKeyManager.stop(); await serverKeyManager.destroy(); @@ -379,7 +373,7 @@ describe(`${NodeConnection.name} test`, () => { targetNodeId: targetNodeId, targetHost: localHost, targetPort: targetPort, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, nodeConnectionManager: dummyNodeConnectionManager, destroyCallback, @@ -395,7 +389,7 @@ describe(`${NodeConnection.name} test`, () => { // Explicitly close the connection such that there's no interference in next test await serverProxy.closeConnectionReverse( localHost, - clientproxy.getProxyPort(), + clientProxy.getProxyPort(), ); }); test('connects to its target (via direct connection)', async () => { @@ -403,7 +397,7 @@ describe(`${NodeConnection.name} test`, () => { targetNodeId: targetNodeId, targetHost: localHost, targetPort: targetPort, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, nodeConnectionManager: dummyNodeConnectionManager, destroyCallback, @@ -419,8 +413,7 @@ describe(`${NodeConnection.name} test`, () => { }, (e) => { if (e instanceof networkErrors.ErrorConnectionNotComposed) return false; - if (e instanceof networkErrors.ErrorConnectionNotRunning) return false; - return true; + return !(e instanceof networkErrors.ErrorConnectionNotRunning); }, ); expect(connInfo).toBeDefined(); @@ -435,7 +428,7 @@ describe(`${NodeConnection.name} test`, () => { await conn.destroy(); }); test('connects to its target but proxies connect first', async () => { - await clientproxy.openConnectionForward( + await clientProxy.openConnectionForward( targetNodeId, localHost, targetPort, @@ -444,7 +437,7 @@ describe(`${NodeConnection.name} test`, () => { targetNodeId: targetNodeId, targetHost: localHost, targetPort: targetPort, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, nodeConnectionManager: dummyNodeConnectionManager, destroyCallback, @@ -460,8 +453,7 @@ describe(`${NodeConnection.name} test`, () => { }, (e) => { if (e instanceof networkErrors.ErrorConnectionNotComposed) return false; - if (e instanceof networkErrors.ErrorConnectionNotRunning) return false; - return true; + return !(e instanceof networkErrors.ErrorConnectionNotRunning); }, ); expect(connInfo).toBeDefined(); @@ -491,7 +483,7 @@ describe(`${NodeConnection.name} test`, () => { const killSelf = jest.fn(); nodeConnection = await NodeConnection.createNodeConnection({ connConnectTime: 500, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, logger: logger, nodeConnectionManager: dummyNodeConnectionManager, @@ -526,7 +518,7 @@ describe(`${NodeConnection.name} test`, () => { targetHost: '128.0.0.1' as Host, targetPort: 12345 as Port, connConnectTime: 300, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, nodeConnectionManager: dummyNodeConnectionManager, destroyCallback, @@ -542,7 +534,7 @@ describe(`${NodeConnection.name} test`, () => { targetNodeId: targetNodeId, targetHost: localHost, targetPort: targetPort, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, nodeConnectionManager: dummyNodeConnectionManager, destroyCallback, @@ -563,7 +555,7 @@ describe(`${NodeConnection.name} test`, () => { targetNodeId: targetNodeId, targetHost: localHost, targetPort: targetPort, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, nodeConnectionManager: dummyNodeConnectionManager, destroyCallback, @@ -601,7 +593,7 @@ describe(`${NodeConnection.name} test`, () => { const killSelf = jest.fn(); const nodeConnectionP = NodeConnection.createNodeConnection({ connConnectTime: 500, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, logger: logger, nodeConnectionManager: dummyNodeConnectionManager, @@ -644,7 +636,7 @@ describe(`${NodeConnection.name} test`, () => { const killSelf = jest.fn(); const nodeConnectionP = NodeConnection.createNodeConnection({ connConnectTime: 500, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, logger: logger, nodeConnectionManager: dummyNodeConnectionManager, @@ -682,7 +674,7 @@ describe(`${NodeConnection.name} test`, () => { const killSelf = jest.fn(); nodeConnection = await NodeConnection.createNodeConnection({ connConnectTime: 500, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, logger: logger, nodeConnectionManager: dummyNodeConnectionManager, @@ -744,7 +736,7 @@ describe(`${NodeConnection.name} test`, () => { const killSelfP = promise(); nodeConnection = await NodeConnection.createNodeConnection({ connConnectTime: 2000, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, logger: logger, nodeConnectionManager: dummyNodeConnectionManager, @@ -813,7 +805,7 @@ describe(`${NodeConnection.name} test`, () => { const killSelfP = promise(); nodeConnection = await NodeConnection.createNodeConnection({ connConnectTime: 2000, - proxy: clientproxy, + proxy: clientProxy, keyManager: clientKeyManager, logger: logger, nodeConnectionManager: dummyNodeConnectionManager, From e528d9fef7ded38d5dcf1456bb8f6a452239af19 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 24 May 2022 13:35:51 +1000 Subject: [PATCH 048/137] fix: added logic check to `NotificationsManager.readNotifications` There was a bug with the DB that is getting fixed. This just throws a clear error when a notification can't be read despite it being in the list of all notifications. --- src/notifications/NotificationsManager.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/notifications/NotificationsManager.ts b/src/notifications/NotificationsManager.ts index b2780000a..dce39dd16 100644 --- a/src/notifications/NotificationsManager.ts +++ b/src/notifications/NotificationsManager.ts @@ -23,6 +23,7 @@ import * as notificationsUtils from './utils'; import * as notificationsErrors from './errors'; import * as notificationsPB from '../proto/js/polykey/v1/notifications/notifications_pb'; import * as nodesUtils from '../nodes/utils'; +import { never } from '../utils/utils'; const MESSAGE_COUNT_KEY = 'numMessages'; @@ -289,7 +290,8 @@ class NotificationsManager { const notifications: Array = []; for (const id of notificationIds) { const notification = await this.readNotificationById(id, tran); - notifications.push(notification!); + if (notification == null) never(); + notifications.push(notification); } return notifications; From 0a6442c9392db5f5dc7840f43599f080b7d2d0fc Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 24 May 2022 13:45:34 +1000 Subject: [PATCH 049/137] tests: split vaults client service tests --- src/grpc/utils/utils.ts | 2 +- tests/client/rpcVaults.test.ts | 372 +----------------- tests/client/service/vaultsClone.test.ts | 99 +++++ .../service/vaultsCreateDeleteList.test.ts | 168 ++++++++ tests/client/service/vaultsLog.test.ts | 188 +++++++++ .../vaultsPermissionSetUnsetGet.test.ts | 226 +++++++++++ tests/client/service/vaultsPull.test.ts | 99 +++++ tests/client/service/vaultsRename.test.ts | 128 ++++++ tests/client/service/vaultsScan.test.ts | 91 +++++ tests/client/service/vaultsVersion.test.ts | 182 +++++++++ 10 files changed, 1184 insertions(+), 371 deletions(-) create mode 100644 tests/client/service/vaultsClone.test.ts create mode 100644 tests/client/service/vaultsCreateDeleteList.test.ts create mode 100644 tests/client/service/vaultsLog.test.ts create mode 100644 tests/client/service/vaultsPermissionSetUnsetGet.test.ts create mode 100644 tests/client/service/vaultsPull.test.ts create mode 100644 tests/client/service/vaultsRename.test.ts create mode 100644 tests/client/service/vaultsScan.test.ts create mode 100644 tests/client/service/vaultsVersion.test.ts diff --git a/src/grpc/utils/utils.ts b/src/grpc/utils/utils.ts index f37442e41..1b98d310f 100644 --- a/src/grpc/utils/utils.ts +++ b/src/grpc/utils/utils.ts @@ -188,7 +188,7 @@ function toError( e: ServiceError, metadata: ClientMetadata, ): errors.ErrorPolykey { - const errorData = e.metadata.get('error')[0].toString(); + const errorData = e.metadata.get('error')[0] as string; // Grpc.status is an enum // this will iterate the enum values then enum keys // they will all be of string type diff --git a/tests/client/rpcVaults.test.ts b/tests/client/rpcVaults.test.ts index 22b9cb1c9..0d0ccc6d7 100644 --- a/tests/client/rpcVaults.test.ts +++ b/tests/client/rpcVaults.test.ts @@ -1,9 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; import type VaultManager from '@/vaults/VaultManager'; -import type { VaultId, VaultName } from '@/vaults/types'; +import type { VaultName } from '@/vaults/types'; import type { ClientServiceClient } from '@/proto/js/polykey/v1/client_service_grpc_pb'; import type { Stat } from 'encryptedfs'; -import type { Host, Port } from '@/network/types'; +import type * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import os from 'os'; import path from 'path'; import fs from 'fs'; @@ -11,16 +11,12 @@ import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import PolykeyAgent from '@/PolykeyAgent'; import KeyManager from '@/keys/KeyManager'; import Proxy from '@/network/Proxy'; -import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; import * as secretsPB from '@/proto/js/polykey/v1/secrets/secrets_pb'; import * as grpcUtils from '@/grpc/utils'; -import * as vaultErrors from '@/vaults/errors'; import * as vaultsUtils from '@/vaults/utils'; import * as vaultOps from '@/vaults/VaultOps'; -import * as nodesUtils from '@/nodes/utils'; import * as clientUtils from './utils'; -import { expectRemoteError } from '../utils'; jest.mock('@/keys/utils', () => ({ ...jest.requireActual('@/keys/utils'), @@ -40,8 +36,6 @@ describe('Vaults client service', () => { 'Vault4' as VaultName, ]; const secretList = ['Secret1', 'Secret2', 'Secret3', 'Secret4']; - const localHost = 'localhost' as Host; - const localPort = 55555 as Port; let client: ClientServiceClient; let server: grpc.Server; @@ -113,368 +107,6 @@ describe('Vaults client service', () => { await vaultManager.destroyVault(vaultId); } }); - - describe('Vaults', () => { - test('should get vaults', async () => { - const listVaults = grpcUtils.promisifyReadableStreamCall( - client, - nodeId, - localHost, - localPort, - client.vaultsList, - ); - for (const vaultName of vaultList) { - await vaultManager.createVault(vaultName); - } - const emptyMessage = new utilsPB.EmptyMessage(); - const vaultStream = listVaults(emptyMessage, callCredentials); - const names: Array = []; - for await (const vault of vaultStream) { - names.push(vault.getVaultName()); - } - expect(names.sort()).toStrictEqual(vaultList.sort()); - }); - test('should create vault', async () => { - const createVault = grpcUtils.promisifyUnaryCall( - client, - client.vaultsCreate, - ); - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultList[0]); - const vaultId = await createVault(vaultMessage, callCredentials); - const vaultNames = await vaultManager.listVaults(); - expect(vaultNames.get(vaultList[0])).toBeTruthy(); - expect( - vaultsUtils.encodeVaultId(vaultNames.get(vaultList[0])!), - ).toStrictEqual(vaultId.getNameOrId()); - }); - test('should delete vaults', async () => { - const deleteVault = grpcUtils.promisifyUnaryCall( - client, - client.vaultsDelete, - ); - for (const vaultName of vaultList) { - await vaultManager.createVault(vaultName); - } - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultList[0]); - await deleteVault(vaultMessage, callCredentials); - const listVaults = await vaultManager.listVaults(); - const modifiedVaultList: string[] = []; - for (const [vaultName] of listVaults) { - modifiedVaultList.push(vaultName); - } - expect(modifiedVaultList.sort()).toStrictEqual(vaultList.slice(1).sort()); - }); - test('should rename vaults', async () => { - const renameVault = grpcUtils.promisifyUnaryCall( - client, - client.vaultsRename, - ); - const vaultId1 = await vaultManager.createVault(vaultList[0]); - - const vaultRenameMessage = new vaultsPB.Rename(); - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId1)); - vaultRenameMessage.setVault(vaultMessage); - vaultRenameMessage.setNewName(vaultList[1]); - - const vaultId2 = await renameVault(vaultRenameMessage, callCredentials); - expect(vaultsUtils.decodeVaultId(vaultId2.getNameOrId())).toStrictEqual( - vaultId1, - ); - - const renamedVaultId = await vaultManager.getVaultId(vaultList[1]); - expect(renamedVaultId).toEqual(vaultId1); - }); - describe('Version', () => { - const secretVer1 = { - name: secretList[0], - content: 'Secret-1-content-ver1', - }; - const secretVer2 = { - name: secretList[0], - content: 'Secret-1-content-ver2', - }; - let vaultId: VaultId; - let vaultsVersion; - - beforeEach(async () => { - vaultId = await vaultManager.createVault(vaultList[0]); - vaultsVersion = grpcUtils.promisifyUnaryCall( - client, - client.vaultsVersion, - ); - }); - - test('should switch a vault to a version', async () => { - // Commit some history - const ver1Oid = await vaultManager.withVaults( - [vaultId], - async (vault) => { - await vault.writeF(async (efs) => { - await efs.writeFile(secretVer1.name, secretVer1.content); - }); - const ver1Oid = (await vault.log())[0].commitId; - await vault.writeF(async (efs) => { - await efs.writeFile(secretVer2.name, secretVer2.content); - }); - return ver1Oid; - }, - ); - - // Revert the version - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultList[0]); - - const vaultVersionMessage = new vaultsPB.Version(); - vaultVersionMessage.setVault(vaultMessage); - vaultVersionMessage.setVersionId(ver1Oid); - - const version = await vaultsVersion( - vaultVersionMessage, - callCredentials, - ); - expect(version.getIsLatestVersion()).toBeFalsy(); - // Read old history - - await vaultManager.withVaults([vaultId], async (vault) => { - await vault.readF(async (efs) => { - expect( - (await efs.readFile(secretVer1.name)).toString(), - ).toStrictEqual(secretVer1.content); - }); - }); - }); - test('should fail to find a non existent version', async () => { - // Revert the version - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); - const vaultVersionMessage = new vaultsPB.Version(); - vaultVersionMessage.setVault(vaultMessage); - vaultVersionMessage.setVersionId('invalidOid'); - const version = vaultsVersion(vaultVersionMessage, callCredentials); - await expectRemoteError( - version, - vaultErrors.ErrorVaultReferenceInvalid, - ); - - vaultVersionMessage.setVersionId( - '7660aa9a2fee90e875c2d19e5deefe882ca1d4d9', - ); - const version2 = vaultsVersion(vaultVersionMessage, callCredentials); - await expectRemoteError( - version2, - vaultErrors.ErrorVaultReferenceMissing, - ); - }); - }); - describe('Vault Log', () => { - let vaultLog; - const secret1 = { name: secretList[0], content: 'Secret-1-content' }; - const secret2 = { name: secretList[1], content: 'Secret-2-content' }; - let vaultId: VaultId; - let commit1Oid: string; - let commit2Oid: string; - let commit3Oid: string; - - beforeEach(async () => { - vaultLog = grpcUtils.promisifyReadableStreamCall( - client, - client.vaultsLog, - ); - vaultId = await vaultManager.createVault(vaultList[0]); - - await vaultManager.withVaults([vaultId], async (vault) => { - await vault.writeF(async (efs) => { - await efs.writeFile(secret1.name, secret1.content); - }); - commit1Oid = (await vault.log(undefined, 0))[0].commitId; - - await vault.writeF(async (efs) => { - await efs.writeFile(secret2.name, secret2.content); - }); - commit2Oid = (await vault.log(undefined, 0))[0].commitId; - - await vault.writeF(async (efs) => { - await efs.unlink(secret2.name); - }); - commit3Oid = (await vault.log(undefined, 0))[0].commitId; - }); - }); - - test('should get the full log', async () => { - const vaultLog = - grpcUtils.promisifyReadableStreamCall( - client, - client.vaultsLog, - ); - const vaultsLogMessage = new vaultsPB.Log(); - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultList[0]); - vaultsLogMessage.setVault(vaultMessage); - const logStream = vaultLog(vaultsLogMessage, callCredentials); - const logMessages: vaultsPB.LogEntry[] = []; - for await (const log of logStream) { - logMessages.push(log); - } - // Checking commits exist in order. - expect(logMessages[2].getOid()).toEqual(commit1Oid); - expect(logMessages[1].getOid()).toEqual(commit2Oid); - expect(logMessages[0].getOid()).toEqual(commit3Oid); - }); - test('should get a part of the log', async () => { - const vaultsLogMessage = new vaultsPB.Log(); - const vaultMessage = new vaultsPB.Vault(); - - vaultMessage.setNameOrId(vaultList[0]); - vaultsLogMessage.setVault(vaultMessage); - vaultsLogMessage.setLogDepth(2); - - const logStream = await vaultLog(vaultsLogMessage, callCredentials); - const logMessages: vaultsPB.LogEntry[] = []; - for await (const log of logStream) { - logMessages.push(log); - } - - // Checking commits exist in order. - expect(logMessages[1].getOid()).toEqual(commit2Oid); - expect(logMessages[0].getOid()).toEqual(commit3Oid); - }); - test('should get a specific commit', async () => { - const vaultsLogMessage = new vaultsPB.Log(); - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultList[0]); - vaultsLogMessage.setVault(vaultMessage); - vaultsLogMessage.setCommitId(commit2Oid); - const logStream = await vaultLog(vaultsLogMessage, callCredentials); - const logMessages: vaultsPB.LogEntry[] = []; - for await (const log of logStream) { - logMessages.push(log); - } - // Checking commits exist in order. - expect(logMessages[0].getOid()).toEqual(commit2Oid); - }); - }); - test('should get vault permissions', async () => { - const vaultsPermissionsGet = - grpcUtils.promisifyReadableStreamCall( - client, - client.vaultsPermissionGet, - ); - - let remoteKeynode1: PolykeyAgent | undefined; - let remoteKeynode2: PolykeyAgent | undefined; - try { - remoteKeynode1 = await PolykeyAgent.createPolykeyAgent({ - password, - logger: logger.getChild('Remote Keynode 1'), - nodePath: path.join(dataDir, 'remoteKeynode1'), - }); - remoteKeynode2 = await PolykeyAgent.createPolykeyAgent({ - password, - logger: logger.getChild('Remote Keynode 2'), - nodePath: path.join(dataDir, 'remoteKeynode2'), - }); - const targetNodeId1 = remoteKeynode1.keyManager.getNodeId(); - const targetNodeId2 = remoteKeynode2.keyManager.getNodeId(); - const pkAgentNodeId = pkAgent.keyManager.getNodeId(); - await pkAgent.gestaltGraph.setNode({ - id: nodesUtils.encodeNodeId(targetNodeId1), - chain: {}, - }); - await pkAgent.gestaltGraph.setNode({ - id: nodesUtils.encodeNodeId(targetNodeId2), - chain: {}, - }); - - await pkAgent.nodeManager.setNode(targetNodeId1, { - host: remoteKeynode1.proxy.getProxyHost(), - port: remoteKeynode1.proxy.getProxyPort(), - }); - await pkAgent.nodeManager.setNode(targetNodeId2, { - host: remoteKeynode2.proxy.getProxyHost(), - port: remoteKeynode2.proxy.getProxyPort(), - }); - - await remoteKeynode1.nodeManager.setNode(pkAgentNodeId, { - host: pkAgent.proxy.getProxyHost(), - port: pkAgent.proxy.getProxyPort(), - }); - await remoteKeynode2.nodeManager.setNode(pkAgentNodeId, { - host: pkAgent.proxy.getProxyHost(), - port: pkAgent.proxy.getProxyPort(), - }); - await remoteKeynode1.acl.setNodePerm(pkAgentNodeId, { - gestalt: { - notify: null, - }, - vaults: {}, - }); - await remoteKeynode2.acl.setNodePerm(pkAgentNodeId, { - gestalt: { - notify: null, - }, - vaults: {}, - }); - - const vaultId1 = await vaultManager.createVault(vaultList[0]); - const vaultId2 = await vaultManager.createVault(vaultList[1]); - - await pkAgent.gestaltGraph.setGestaltActionByNode( - targetNodeId1, - 'scan', - ); - await pkAgent.acl.setVaultAction(vaultId1, targetNodeId1, 'clone'); - await pkAgent.acl.setVaultAction(vaultId1, targetNodeId1, 'pull'); - await pkAgent.gestaltGraph.setGestaltActionByNode( - targetNodeId2, - 'scan', - ); - await pkAgent.acl.setVaultAction(vaultId1, targetNodeId2, 'clone'); - await pkAgent.acl.setVaultAction(vaultId1, targetNodeId2, 'pull'); - await pkAgent.gestaltGraph.setGestaltActionByNode( - targetNodeId1, - 'scan', - ); - await pkAgent.acl.setVaultAction(vaultId2, targetNodeId1, 'clone'); - await pkAgent.acl.setVaultAction(vaultId2, targetNodeId1, 'pull'); - - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId1)); - - const permissionsStream = vaultsPermissionsGet( - vaultMessage, - callCredentials, - ); - const list: Record[] = []; - for await (const permission of permissionsStream) { - const permissionsList = permission.getVaultPermissionsList(); - expect(permissionsList).toContain('pull'); - expect(permissionsList).toContain('clone'); - list.push(permission.toObject()); - } - expect(list).toHaveLength(2); - - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId2)); - const permissionStream2 = vaultsPermissionsGet( - vaultMessage, - callCredentials, - ); - for await (const permission of permissionStream2) { - const permissionsList = permission.getVaultPermissionsList(); - expect(permissionsList).toContain('pull'); - expect(permissionsList).toContain('clone'); - const node = permission.getNode(); - const nodeId = node?.getNodeId(); - expect(nodeId).toEqual(nodesUtils.encodeNodeId(targetNodeId1)); - } - } finally { - await remoteKeynode1?.stop(); - await remoteKeynode2?.stop(); - } - }); - }); describe('Secrets', () => { test('should make a directory in a vault', async () => { const mkdirVault = grpcUtils.promisifyUnaryCall( diff --git a/tests/client/service/vaultsClone.test.ts b/tests/client/service/vaultsClone.test.ts new file mode 100644 index 000000000..b54f629db --- /dev/null +++ b/tests/client/service/vaultsClone.test.ts @@ -0,0 +1,99 @@ +import type { Host, Port } from '@/network/types'; +import type KeyManager from '@/keys/KeyManager'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsClone from '@/client/service/vaultsClone'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as keysUtils from '@/keys/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsClone', () => { + const logger = new Logger('vaultsClone test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + let dataDir: string; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager: {} as KeyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + const clientService = { + vaultsClone: vaultsClone({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test.todo('clones a vault'); +}); diff --git a/tests/client/service/vaultsCreateDeleteList.test.ts b/tests/client/service/vaultsCreateDeleteList.test.ts new file mode 100644 index 000000000..c04644056 --- /dev/null +++ b/tests/client/service/vaultsCreateDeleteList.test.ts @@ -0,0 +1,168 @@ +import type { Host, Port } from '@/network/types'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import KeyManager from '@/keys/KeyManager'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsCreate from '@/client/service/vaultsCreate'; +import vaultsDelete from '@/client/service/vaultsDelete'; +import vaultsList from '@/client/service/vaultsList'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; +import * as clientUtils from '@/client/utils/utils'; +import * as keysUtils from '@/keys/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsCreateDeleteList', () => { + const logger = new Logger('vaultsCreateDeleteList test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + let dataDir: string; + let keyManager: KeyManager; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = path.join(dataDir, 'keys'); + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + const clientService = { + vaultsCreate: vaultsCreate({ + authenticate, + vaultManager, + db, + logger, + }), + vaultsDelete: vaultsDelete({ + authenticate, + vaultManager, + db, + logger, + }), + vaultsList: vaultsList({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('creates, lists, and deletes vaults', async () => { + // Create vault + const createRequest = new vaultsPB.Vault(); + createRequest.setNameOrId('test-vault'); + const createResponse = await grpcClient.vaultsCreate( + createRequest, + clientUtils.encodeAuthFromPassword(password), + ); + expect(createResponse).toBeInstanceOf(vaultsPB.Vault); + const vaultId = createResponse.getNameOrId(); + // List vault + const emptyMessage = new utilsPB.EmptyMessage(); + const listResponse1 = grpcClient.vaultsList( + emptyMessage, + clientUtils.encodeAuthFromPassword(password), + ); + const vaults1: Array<{ name: string; id: string }> = []; + for await (const vault of listResponse1) { + expect(vault).toBeInstanceOf(vaultsPB.List); + vaults1.push({ name: vault.getVaultName(), id: vault.getVaultId() }); + } + expect(vaults1).toHaveLength(1); + expect(vaults1[0].name).toBe('test-vault'); + expect(vaults1[0].id).toBe(vaultId); + // Delete vault + const deleteRequest = createRequest; + const deleteResponse = await grpcClient.vaultsDelete( + deleteRequest, + clientUtils.encodeAuthFromPassword(password), + ); + expect(deleteResponse).toBeInstanceOf(utilsPB.StatusMessage); + expect(deleteResponse.getSuccess()).toBeTruthy(); + // Check vault was deleted + const listResponse2 = grpcClient.vaultsList( + emptyMessage, + clientUtils.encodeAuthFromPassword(password), + ); + const vaults2: Array<{ name: string; id: string }> = []; + for await (const vault of listResponse2) { + expect(vault).toBeInstanceOf(vaultsPB.List); + vaults2.push({ name: vault.getVaultName(), id: vault.getVaultId() }); + } + expect(vaults2).toHaveLength(0); + }); +}); diff --git a/tests/client/service/vaultsLog.test.ts b/tests/client/service/vaultsLog.test.ts new file mode 100644 index 000000000..d2f5ed26d --- /dev/null +++ b/tests/client/service/vaultsLog.test.ts @@ -0,0 +1,188 @@ +import type { Host, Port } from '@/network/types'; +import type { VaultId } from '@/vaults/types'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import KeyManager from '@/keys/KeyManager'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsLog from '@/client/service/vaultsLog'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; +import * as clientUtils from '@/client/utils/utils'; +import * as keysUtils from '@/keys/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsLog', () => { + const logger = new Logger('vaultsLog test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + const vaultName = 'test-vault'; + const secret1 = { name: 'secret1', content: 'Secret-1-content' }; + const secret2 = { name: 'secret2', content: 'Secret-2-content' }; + let dataDir: string; + let vaultId: VaultId; + let commit1Oid: string; + let commit2Oid: string; + let commit3Oid: string; + let keyManager: KeyManager; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = path.join(dataDir, 'keys'); + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + vaultId = await vaultManager.createVault(vaultName); + await vaultManager.withVaults([vaultId], async (vault) => { + await vault.writeF(async (efs) => { + await efs.writeFile(secret1.name, secret1.content); + }); + commit1Oid = (await vault.log(undefined, 0))[0].commitId; + await vault.writeF(async (efs) => { + await efs.writeFile(secret2.name, secret2.content); + }); + commit2Oid = (await vault.log(undefined, 0))[0].commitId; + await vault.writeF(async (efs) => { + await efs.unlink(secret2.name); + }); + commit3Oid = (await vault.log(undefined, 0))[0].commitId; + }); + const clientService = { + vaultsLog: vaultsLog({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('should get the full log', async () => { + const vaultsLogMessage = new vaultsPB.Log(); + const vaultMessage = new vaultsPB.Vault(); + vaultMessage.setNameOrId(vaultName); + vaultsLogMessage.setVault(vaultMessage); + const logStream = grpcClient.vaultsLog( + vaultsLogMessage, + clientUtils.encodeAuthFromPassword(password), + ); + const logMessages: vaultsPB.LogEntry[] = []; + for await (const log of logStream) { + expect(log).toBeInstanceOf(vaultsPB.LogEntry); + logMessages.push(log); + } + // Checking commits exist in order. + expect(logMessages[2].getOid()).toEqual(commit1Oid); + expect(logMessages[1].getOid()).toEqual(commit2Oid); + expect(logMessages[0].getOid()).toEqual(commit3Oid); + }); + test('should get a part of the log', async () => { + const vaultsLogMessage = new vaultsPB.Log(); + const vaultMessage = new vaultsPB.Vault(); + vaultMessage.setNameOrId(vaultName); + vaultsLogMessage.setVault(vaultMessage); + vaultsLogMessage.setLogDepth(2); + const logStream = grpcClient.vaultsLog( + vaultsLogMessage, + clientUtils.encodeAuthFromPassword(password), + ); + const logMessages: vaultsPB.LogEntry[] = []; + for await (const log of logStream) { + expect(log).toBeInstanceOf(vaultsPB.LogEntry); + logMessages.push(log); + } + // Checking commits exist in order. + expect(logMessages[1].getOid()).toEqual(commit2Oid); + expect(logMessages[0].getOid()).toEqual(commit3Oid); + }); + test('should get a specific commit', async () => { + const vaultsLogMessage = new vaultsPB.Log(); + const vaultMessage = new vaultsPB.Vault(); + vaultMessage.setNameOrId(vaultName); + vaultsLogMessage.setVault(vaultMessage); + vaultsLogMessage.setCommitId(commit2Oid); + const logStream = grpcClient.vaultsLog( + vaultsLogMessage, + clientUtils.encodeAuthFromPassword(password), + ); + const logMessages: vaultsPB.LogEntry[] = []; + for await (const log of logStream) { + expect(log).toBeInstanceOf(vaultsPB.LogEntry); + logMessages.push(log); + } + // Checking commits exist in order. + expect(logMessages[0].getOid()).toEqual(commit2Oid); + }); +}); diff --git a/tests/client/service/vaultsPermissionSetUnsetGet.test.ts b/tests/client/service/vaultsPermissionSetUnsetGet.test.ts new file mode 100644 index 000000000..299ab6219 --- /dev/null +++ b/tests/client/service/vaultsPermissionSetUnsetGet.test.ts @@ -0,0 +1,226 @@ +import type { Host, Port } from '@/network/types'; +import type NodeManager from '@/nodes/NodeManager'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import ACL from '@/acl/ACL'; +import GestaltGraph from '@/gestalts/GestaltGraph'; +import KeyManager from '@/keys/KeyManager'; +import NotificationsManager from '@/notifications/NotificationsManager'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsPermissionGet from '@/client/service/vaultsPermissionGet'; +import vaultsPermissionSet from '@/client/service/vaultsPermissionSet'; +import vaultsPermissionUnset from '@/client/service/vaultsPermissionUnset'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; +import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; +import * as clientUtils from '@/client/utils/utils'; +import * as keysUtils from '@/keys/utils'; +import * as nodesUtils from '@/nodes/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsPermissionSetUnsetGet', () => { + const logger = new Logger('vaultsPermissionSetUnsetGet test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + let mockedSendNotification: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + mockedSendNotification = jest + .spyOn(NotificationsManager.prototype, 'sendNotification') + .mockImplementation(); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + mockedSendNotification.mockRestore(); + }); + const nodeId = testUtils.generateRandomNodeId(); + let dataDir: string; + let keyManager: KeyManager; + let db: DB; + let acl: ACL; + let gestaltGraph: GestaltGraph; + let notificationsManager: NotificationsManager; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = path.join(dataDir, 'keys'); + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + acl = await ACL.createACL({ + db, + logger, + }); + gestaltGraph = await GestaltGraph.createGestaltGraph({ + db, + acl, + logger, + }); + await gestaltGraph.setNode({ + id: nodesUtils.encodeNodeId(nodeId), + chain: {}, + }); + notificationsManager = + await NotificationsManager.createNotificationsManager({ + acl, + db, + nodeConnectionManager: {} as NodeConnectionManager, + nodeManager: {} as NodeManager, + keyManager, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl, + keyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph, + notificationsManager: notificationsManager, + logger, + }); + const clientService = { + vaultsPermissionSet: vaultsPermissionSet({ + authenticate, + vaultManager, + gestaltGraph, + acl, + notificationsManager, + db, + logger, + }), + vaultsPermissionUnset: vaultsPermissionUnset({ + authenticate, + vaultManager, + gestaltGraph, + acl, + db, + logger, + }), + vaultsPermissionGet: vaultsPermissionGet({ + authenticate, + vaultManager, + acl, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await notificationsManager.stop(); + await gestaltGraph.stop(); + await acl.stop(); + await db.stop(); + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('sets, gets, and unsets vault permissions', async () => { + const vaultName = 'test-vault'; + await vaultManager.createVault(vaultName); + // Set permissions + const vault = new vaultsPB.Vault(); + vault.setNameOrId(vaultName); + const node = new nodesPB.Node(); + node.setNodeId(nodesUtils.encodeNodeId(nodeId)); + const permissions = new vaultsPB.Permissions(); + permissions.setVault(vault); + permissions.setNode(node); + permissions.setVaultPermissionsList(['clone', 'pull']); + const setResponse = await grpcClient.vaultsPermissionSet( + permissions, + clientUtils.encodeAuthFromPassword(password), + ); + expect(setResponse).toBeInstanceOf(utilsPB.StatusMessage); + expect(setResponse.getSuccess()).toBeTruthy(); + // Get permissions + const getResponse1 = grpcClient.vaultsPermissionGet( + vault, + clientUtils.encodeAuthFromPassword(password), + ); + const list1: Record[] = []; + for await (const permission of getResponse1) { + expect(permission).toBeInstanceOf(vaultsPB.Permissions); + const permissionsList = permission.getVaultPermissionsList(); + expect(permissionsList).toContain('pull'); + expect(permissionsList).toContain('clone'); + const node = permission.getNode(); + const receivedNodeId = node?.getNodeId(); + expect(receivedNodeId).toEqual(nodesUtils.encodeNodeId(nodeId)); + list1.push(permission.toObject()); + } + expect(list1).toHaveLength(1); + // Unset permissions + const deleteResponse = await grpcClient.vaultsPermissionUnset( + permissions, + clientUtils.encodeAuthFromPassword(password), + ); + expect(deleteResponse).toBeInstanceOf(utilsPB.StatusMessage); + expect(deleteResponse.getSuccess()).toBeTruthy(); + // Check permissions were unset + const getResponse2 = grpcClient.vaultsPermissionGet( + vault, + clientUtils.encodeAuthFromPassword(password), + ); + const list2: Record[] = []; + for await (const permission of getResponse2) { + expect(permission).toBeInstanceOf(vaultsPB.Permissions); + const permissionsList = permission.getVaultPermissionsList(); + expect(permissionsList).toEqual([]); + const node = permission.getNode(); + const receivedNodeId = node?.getNodeId(); + expect(receivedNodeId).toEqual(nodesUtils.encodeNodeId(nodeId)); + list2.push(permission.toObject()); + } + expect(list2).toHaveLength(1); + }); +}); diff --git a/tests/client/service/vaultsPull.test.ts b/tests/client/service/vaultsPull.test.ts new file mode 100644 index 000000000..8240e167d --- /dev/null +++ b/tests/client/service/vaultsPull.test.ts @@ -0,0 +1,99 @@ +import type { Host, Port } from '@/network/types'; +import type KeyManager from '@/keys/KeyManager'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsPull from '@/client/service/vaultsPull'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as keysUtils from '@/keys/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsPull', () => { + const logger = new Logger('vaultsPull test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + let dataDir: string; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager: {} as KeyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + const clientService = { + vaultsPull: vaultsPull({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test.todo('pulls from a vault'); +}); diff --git a/tests/client/service/vaultsRename.test.ts b/tests/client/service/vaultsRename.test.ts new file mode 100644 index 000000000..0e7dd856e --- /dev/null +++ b/tests/client/service/vaultsRename.test.ts @@ -0,0 +1,128 @@ +import type { Host, Port } from '@/network/types'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import KeyManager from '@/keys/KeyManager'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsRename from '@/client/service/vaultsRename'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; +import * as clientUtils from '@/client/utils/utils'; +import * as keysUtils from '@/keys/utils'; +import * as vaultsUtils from '@/vaults/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsRename', () => { + const logger = new Logger('vaultsRename test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + let dataDir: string; + let keyManager: KeyManager; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = path.join(dataDir, 'keys'); + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + const clientService = { + vaultsRename: vaultsRename({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('should rename vault', async () => { + const vaultId1 = await vaultManager.createVault('test-vault1'); + const vaultRenameMessage = new vaultsPB.Rename(); + const vaultMessage = new vaultsPB.Vault(); + vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId1)); + vaultRenameMessage.setVault(vaultMessage); + vaultRenameMessage.setNewName('test-vault2'); + const vaultId2 = await grpcClient.vaultsRename( + vaultRenameMessage, + clientUtils.encodeAuthFromPassword(password), + ); + expect(vaultId2).toBeInstanceOf(vaultsPB.Vault); + expect(vaultsUtils.decodeVaultId(vaultId2.getNameOrId())).toStrictEqual( + vaultId1, + ); + const renamedVaultId = await vaultManager.getVaultId('test-vault2'); + expect(renamedVaultId).toEqual(vaultId1); + }); +}); diff --git a/tests/client/service/vaultsScan.test.ts b/tests/client/service/vaultsScan.test.ts new file mode 100644 index 000000000..40abc72eb --- /dev/null +++ b/tests/client/service/vaultsScan.test.ts @@ -0,0 +1,91 @@ +import type { DB } from '@matrixai/db'; +import type { Host, Port } from '@/network/types'; +import type KeyManager from '@/keys/KeyManager'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { Metadata } from '@grpc/grpc-js'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsScan from '@/client/service/vaultsScan'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as keysUtils from '@/keys/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsScan', () => { + const logger = new Logger('vaultsScan test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + let dataDir: string; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db: {} as DB, + acl: {} as ACL, + keyManager: {} as KeyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + const clientService = { + vaultsScan: vaultsScan({ + authenticate, + vaultManager, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test.todo('scans a vault'); +}); diff --git a/tests/client/service/vaultsVersion.test.ts b/tests/client/service/vaultsVersion.test.ts new file mode 100644 index 000000000..09373743a --- /dev/null +++ b/tests/client/service/vaultsVersion.test.ts @@ -0,0 +1,182 @@ +import type { Host, Port } from '@/network/types'; +import type { VaultId } from '@/vaults/types'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import KeyManager from '@/keys/KeyManager'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsVersion from '@/client/service/vaultsVersion'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; +import * as clientUtils from '@/client/utils/utils'; +import * as keysUtils from '@/keys/utils'; +import * as vaultsUtils from '@/vaults/utils'; +import * as vaultsErrors from '@/vaults/errors'; +import * as testUtils from '../../utils'; + +describe('vaultsVersion', () => { + const logger = new Logger('vaultsVersion test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + const secretVer1 = { + name: 'secret1v1', + content: 'Secret-1-content-ver1', + }; + const secretVer2 = { + name: 'secret1v2', + content: 'Secret-1-content-ver2', + }; + const vaultName = 'test-vault'; + let vaultId: VaultId; + let dataDir: string; + let keyManager: KeyManager; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = path.join(dataDir, 'keys'); + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + vaultId = await vaultManager.createVault(vaultName); + const clientService = { + vaultsVersion: vaultsVersion({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('should switch a vault to a version', async () => { + // Commit some history + const ver1Oid = await vaultManager.withVaults([vaultId], async (vault) => { + await vault.writeF(async (efs) => { + await efs.writeFile(secretVer1.name, secretVer1.content); + }); + const ver1Oid = (await vault.log())[0].commitId; + await vault.writeF(async (efs) => { + await efs.writeFile(secretVer2.name, secretVer2.content); + }); + return ver1Oid; + }); + // Revert the version + const vaultMessage = new vaultsPB.Vault(); + vaultMessage.setNameOrId(vaultName); + const vaultVersionMessage = new vaultsPB.Version(); + vaultVersionMessage.setVault(vaultMessage); + vaultVersionMessage.setVersionId(ver1Oid); + const version = await grpcClient.vaultsVersion( + vaultVersionMessage, + clientUtils.encodeAuthFromPassword(password), + ); + expect(version.getIsLatestVersion()).toBeFalsy(); + // Read old history + await vaultManager.withVaults([vaultId], async (vault) => { + await vault.readF(async (efs) => { + expect((await efs.readFile(secretVer1.name)).toString()).toStrictEqual( + secretVer1.content, + ); + }); + }); + }); + test('should fail to find a non existent version', async () => { + // Revert the version + const vaultMessage = new vaultsPB.Vault(); + vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); + const vaultVersionMessage = new vaultsPB.Version(); + vaultVersionMessage.setVault(vaultMessage); + vaultVersionMessage.setVersionId('invalidOid'); + const version = grpcClient.vaultsVersion( + vaultVersionMessage, + clientUtils.encodeAuthFromPassword(password), + ); + await testUtils.expectRemoteError( + version, + vaultsErrors.ErrorVaultReferenceInvalid, + ); + vaultVersionMessage.setVersionId( + '7660aa9a2fee90e875c2d19e5deefe882ca1d4d9', + ); + const version2 = grpcClient.vaultsVersion( + vaultVersionMessage, + clientUtils.encodeAuthFromPassword(password), + ); + await testUtils.expectRemoteError( + version2, + vaultsErrors.ErrorVaultReferenceMissing, + ); + }); +}); From 600aa36c445e95c71a64ee923988f43f729d9c8e Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 25 May 2022 14:39:12 +1000 Subject: [PATCH 050/137] test: fixed broken proxy tests Problem was with the tests themselves so i've fixed the tests. If there are any similar issues crop up later, then we can explore the underlying cause in depth. However, it is low priority for now. --- tests/network/Proxy.test.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/network/Proxy.test.ts b/tests/network/Proxy.test.ts index afd93c3b4..b418d6544 100644 --- a/tests/network/Proxy.test.ts +++ b/tests/network/Proxy.test.ts @@ -1,12 +1,12 @@ -import type { Socket, AddressInfo } from 'net'; +import type { AddressInfo, Socket } from 'net'; import type { KeyPairPem } from '@/keys/types'; import type { Host, Port } from '@/network/types'; -import http from 'http'; import net from 'net'; +import http from 'http'; import tls from 'tls'; import UTP from 'utp-native'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import { promisify, promise, timerStart, timerStop, poll } from '@/utils'; +import { poll, promise, promisify, timerStart, timerStop } from '@/utils'; import Proxy from '@/network/Proxy'; import * as networkUtils from '@/network/utils'; import * as networkErrors from '@/network/errors'; @@ -27,7 +27,7 @@ async function httpConnect( path: string, ): Promise { const tokenEncoded = Buffer.from(token, 'utf-8').toString('base64'); - const socket = await new Promise((resolve, reject) => { + return await new Promise((resolve, reject) => { const req = http.request({ method: 'CONNECT', path: path, @@ -49,7 +49,6 @@ async function httpConnect( reject(e); }); }); - return socket; } /** From f6339aabc68252cf5accfe4c1ee33b9555ca26b8 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 25 May 2022 20:17:36 +1000 Subject: [PATCH 051/137] tests: fixing remaining tests --- tests/client/rpcVaults.test.ts | 10 ++++ tests/grpc/GRPCServer.test.ts | 5 ++ tests/grpc/utils.test.ts | 93 ++++++++++++++++++------------ tests/grpc/utils/GRPCClientTest.ts | 8 +++ tests/grpc/utils/testService.ts | 13 ++++- 5 files changed, 89 insertions(+), 40 deletions(-) diff --git a/tests/client/rpcVaults.test.ts b/tests/client/rpcVaults.test.ts index 0d0ccc6d7..eefd4943f 100644 --- a/tests/client/rpcVaults.test.ts +++ b/tests/client/rpcVaults.test.ts @@ -4,6 +4,7 @@ import type { VaultName } from '@/vaults/types'; import type { ClientServiceClient } from '@/proto/js/polykey/v1/client_service_grpc_pb'; import type { Stat } from 'encryptedfs'; import type * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import type { ClientMetadata } from '@/types'; import os from 'os'; import path from 'path'; import fs from 'fs'; @@ -111,6 +112,7 @@ describe('Vaults client service', () => { test('should make a directory in a vault', async () => { const mkdirVault = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.vaultsSecretsMkdir, ); @@ -133,6 +135,7 @@ describe('Vaults client service', () => { const listSecretsVault = grpcUtils.promisifyReadableStreamCall( client, + {} as ClientMetadata, client.vaultsSecretsList, ); @@ -158,6 +161,7 @@ describe('Vaults client service', () => { const deleteSecretVault = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.vaultsSecretsDelete, ); @@ -187,6 +191,7 @@ describe('Vaults client service', () => { const editSecretVault = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.vaultsSecretsEdit, ); const vaultId = await vaultManager.createVault(vaultList[0]); @@ -214,6 +219,7 @@ describe('Vaults client service', () => { test('should get secrets in a vault', async () => { const getSecretVault = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.vaultsSecretsGet, ); const vaultId = await vaultManager.createVault(vaultList[0]); @@ -235,6 +241,7 @@ describe('Vaults client service', () => { const renameSecretVault = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.vaultsSecretsRename, ); const vaultId = await vaultManager.createVault(vaultList[0]); @@ -265,6 +272,7 @@ describe('Vaults client service', () => { const newSecretVault = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.vaultsSecretsNew, ); @@ -288,6 +296,7 @@ describe('Vaults client service', () => { const newDirSecretVault = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.vaultsSecretsNewDir, ); @@ -315,6 +324,7 @@ describe('Vaults client service', () => { test('should stat a file', async () => { const getSecretStat = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.vaultsSecretsStat, ); const vaultId = await vaultManager.createVault(vaultList[0]); diff --git a/tests/grpc/GRPCServer.test.ts b/tests/grpc/GRPCServer.test.ts index 9b5c54809..6b77673e4 100644 --- a/tests/grpc/GRPCServer.test.ts +++ b/tests/grpc/GRPCServer.test.ts @@ -1,5 +1,6 @@ import type { Authenticate } from '@/client/types'; import type { Host, Port } from '@/network/types'; +import type { ClientMetadata } from '@/types'; import os from 'os'; import path from 'path'; import fs from 'fs'; @@ -160,6 +161,7 @@ describe('GRPCServer', () => { ); const unary = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.unary, ); const m = new utilsPB.EchoMessage(); @@ -213,6 +215,7 @@ describe('GRPCServer', () => { ); const unary1 = grpcUtils.promisifyUnaryCall( client1, + {} as ClientMetadata, client1.unary, ); const m1 = new utilsPB.EchoMessage(); @@ -250,6 +253,7 @@ describe('GRPCServer', () => { ); const unary2 = grpcUtils.promisifyUnaryCall( client2, + {} as ClientMetadata, client2.unary, ); const m3 = new utilsPB.EchoMessage(); @@ -303,6 +307,7 @@ describe('GRPCServer', () => { ); const unary = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.unaryAuthenticated, ); const m = new utilsPB.EchoMessage(); diff --git a/tests/grpc/utils.test.ts b/tests/grpc/utils.test.ts index 496f6553b..82a8e2c21 100644 --- a/tests/grpc/utils.test.ts +++ b/tests/grpc/utils.test.ts @@ -1,4 +1,5 @@ import type { TestServiceClient } from '@/proto/js/polykey/v1/test_service_grpc_pb'; +import type { ClientMetadata } from '@/types'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import { getLogger } from '@grpc/grpc-js/build/src/logging'; @@ -41,6 +42,7 @@ describe('GRPC utils', () => { test('promisified client unary call', async () => { const unary = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.unary, ); const messageTo = new utilsPB.EchoMessage(); @@ -53,6 +55,7 @@ describe('GRPC utils', () => { test('promisified client unary call error', async () => { const unary = grpcUtils.promisifyUnaryCall( client, + {} as ClientMetadata, client.unary, ); const messageTo = new utilsPB.EchoMessage(); @@ -74,6 +77,7 @@ describe('GRPC utils', () => { const serverStream = grpcUtils.promisifyReadableStreamCall( client, + {} as ClientMetadata, client.serverStream, ); const challenge = '4444'; @@ -99,6 +103,7 @@ describe('GRPC utils', () => { const serverStream = grpcUtils.promisifyReadableStreamCall( client, + {} as ClientMetadata, client.serverStream, ); const challenge = 'error'; @@ -123,6 +128,7 @@ describe('GRPC utils', () => { const serverStream = grpcUtils.promisifyReadableStreamCall( client, + {} as ClientMetadata, client.serverStream, ); const challenge = '4444'; @@ -147,6 +153,7 @@ describe('GRPC utils', () => { const serverStream = grpcUtils.promisifyReadableStreamCall( client, + {} as ClientMetadata, client.serverStream, ); const challenge = '4444'; @@ -174,7 +181,7 @@ describe('GRPC utils', () => { const clientStream = grpcUtils.promisifyWritableStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, client.clientStream); + >(client, {} as ClientMetadata, client.clientStream); const [genStream, response] = clientStream(); const m = new utilsPB.EchoMessage(); m.setChallenge('d89f7u983e4d'); @@ -191,7 +198,7 @@ describe('GRPC utils', () => { const clientStream = grpcUtils.promisifyWritableStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, client.clientStream); + >(client, {} as ClientMetadata, client.clientStream); const [genStream, response] = clientStream(); const result1 = await genStream.next(null); // Closed stream expect(result1).toMatchObject({ @@ -212,7 +219,7 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, client.duplexStream); + >(client, {} as ClientMetadata, client.duplexStream); const genDuplex = duplexStream(); const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('d89f7u983e4d'); @@ -230,7 +237,7 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, client.duplexStream); + >(client, {} as ClientMetadata, client.duplexStream); const genDuplex = duplexStream(); await genDuplex.next(null); expect(genDuplex.stream.destroyed).toBe(true); @@ -240,7 +247,7 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, client.duplexStream); + >(client, {} as ClientMetadata, client.duplexStream); const genDuplex = duplexStream(); // When duplex streams are ended, reading will hang await genDuplex.write(null); @@ -253,7 +260,7 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, client.duplexStream); + >(client, {} as ClientMetadata, client.duplexStream); const genDuplex = duplexStream(); await genDuplex.read(null); const messageTo = new utilsPB.EchoMessage(); @@ -273,7 +280,7 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, client.duplexStream); + >(client, {} as ClientMetadata, client.duplexStream); const genDuplex = duplexStream(); const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('error'); @@ -288,7 +295,7 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, client.duplexStream); + >(client, {} as ClientMetadata, client.duplexStream); const genDuplex = duplexStream(); const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('error'); @@ -315,13 +322,16 @@ describe('GRPC utils', () => { type: 'ErrorPolykey', data: expect.any(Object), }); - const deserialisedError = grpcUtils.toError({ - name: '', - message: '', - code: 2, - details: '', - metadata: serialised, - }); + const deserialisedError = grpcUtils.toError( + { + name: '', + message: '', + code: 2, + details: '', + metadata: serialised, + }, + {} as ClientMetadata, + ); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); expect(deserialisedError.cause).toBeInstanceOf(errors.ErrorPolykey); @@ -340,32 +350,38 @@ describe('GRPC utils', () => { type: 'TypeError', data: expect.any(Object), }); - const deserialisedError = grpcUtils.toError({ - name: '', - message: '', - code: 2, - details: '', - metadata: serialised, - }); + const deserialisedError = grpcUtils.toError( + { + name: '', + message: '', + code: 2, + details: '', + metadata: serialised, + }, + {} as ClientMetadata, + ); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); expect(deserialisedError.cause).toBeInstanceOf(TypeError); expect(deserialisedError.cause.message).toBe('test error'); expect(deserialisedError.cause.stack).toBe(error.stack); }); - test('serialising and deserialising non-errors', async () => { + test('serialising and de-serialising non-errors', async () => { const error = 'not an error' as unknown as Error; const serialised = grpcUtils.fromError(error).metadata!; const stringifiedError = serialised.get('error')[0] as string; const parsedError = JSON.parse(stringifiedError); expect(parsedError).toEqual('not an error'); - const deserialisedError = grpcUtils.toError({ - name: '', - message: '', - code: 2, - details: '', - metadata: serialised, - }); + const deserialisedError = grpcUtils.toError( + { + name: '', + message: '', + code: 2, + details: '', + metadata: serialised, + }, + {} as ClientMetadata, + ); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe(''); expect(deserialisedError.cause).toBeInstanceOf(errors.ErrorPolykeyUnknown); @@ -396,13 +412,16 @@ describe('GRPC utils', () => { data: error.data, }, }); - const deserialisedError = grpcUtils.toError({ - name: '', - message: '', - code: 2, - details: '', - metadata: serialised, - }); + const deserialisedError = grpcUtils.toError( + { + name: '', + message: '', + code: 2, + details: '', + metadata: serialised, + }, + {} as ClientMetadata, + ); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); expect(deserialisedError.cause).toBeInstanceOf(errors.ErrorPolykey); diff --git a/tests/grpc/utils/GRPCClientTest.ts b/tests/grpc/utils/GRPCClientTest.ts index 9cb176377..b628eba27 100644 --- a/tests/grpc/utils/GRPCClientTest.ts +++ b/tests/grpc/utils/GRPCClientTest.ts @@ -5,6 +5,7 @@ import type { Host, Port, TLSConfig, ProxyConfig } from '@/network/types'; import type * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import type { ClientReadableStream } from '@grpc/grpc-js/build/src/call'; import type { AsyncGeneratorReadableStreamClient } from '@/grpc/types'; +import type { ClientMetadata } from '@/types'; import Logger from '@matrixai/logger'; import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; import GRPCClient from '@/grpc/GRPCClient'; @@ -75,6 +76,7 @@ class GRPCClientTest extends GRPCClient { public unary(...args) { return grpcUtils.promisifyUnaryCall( this.client, + {} as ClientMetadata, this.client.unary, )(...args); } @@ -83,6 +85,7 @@ class GRPCClientTest extends GRPCClient { public serverStream(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, + {} as ClientMetadata, this.client.serverStream, )(...args); } @@ -94,6 +97,7 @@ class GRPCClientTest extends GRPCClient { utilsPB.EchoMessage >( this.client, + {} as ClientMetadata, this.client.clientStream, )(...args); } @@ -105,6 +109,7 @@ class GRPCClientTest extends GRPCClient { utilsPB.EchoMessage >( this.client, + {} as ClientMetadata, this.client.duplexStream, )(...args); } @@ -113,6 +118,7 @@ class GRPCClientTest extends GRPCClient { public unaryAuthenticated(...args) { return grpcUtils.promisifyUnaryCall( this.client, + {} as ClientMetadata, this.client.unaryAuthenticated, )(...args); } @@ -126,6 +132,7 @@ class GRPCClientTest extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, + {} as ClientMetadata, this.client.serverStreamFail, )(...args); } @@ -134,6 +141,7 @@ class GRPCClientTest extends GRPCClient { public unaryFail(...args) { return grpcUtils.promisifyUnaryCall( this.client, + {} as ClientMetadata, this.client.unaryFail, )(...args); } diff --git a/tests/grpc/utils/testService.ts b/tests/grpc/utils/testService.ts index 38cd50128..2769d103e 100644 --- a/tests/grpc/utils/testService.ts +++ b/tests/grpc/utils/testService.ts @@ -7,6 +7,7 @@ import type { Authenticate } from '@/client/types'; import type { SessionToken } from '@/sessions/types'; import type { ITestServiceServer } from '@/proto/js/polykey/v1/test_service_grpc_pb'; +import type { ClientMetadata } from '@/types'; import Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as grpcUtils from '@/grpc/utils'; @@ -102,8 +103,10 @@ function createTestService({ ); call.sendMetadata(meta); } - const genReadable = - grpcUtils.generatorReadable(call); + const genReadable = grpcUtils.generatorReadable( + call, + {} as ClientMetadata, + ); let data = ''; try { for await (const m of genReadable) { @@ -132,7 +135,11 @@ function createTestService({ ); call.sendMetadata(meta); } - const genDuplex = grpcUtils.generatorDuplex(call, false); + const genDuplex = grpcUtils.generatorDuplex( + call, + {} as ClientMetadata, + false, + ); const readStatus = await genDuplex.read(); // If nothing to read, end and destroy if (readStatus.done) { From 51c26a2de760b55fe9bb3d7a06d24200f88c383b Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Thu, 26 May 2022 12:05:26 +1000 Subject: [PATCH 052/137] tests: grpc tests fixes There were places where ClientMetadata was not being provided to grpc calls (`{} as ClientMetadata`) however this information is required in order to construct ErrorPolykeyRemote. Where metadata is needed in tests it is either now taken from constants used in the tests or mocked. There was also an issue with error descriptions not being serialised/deserialised which is now fixed. Also some brittle test cases for error messages were removed. --- src/ErrorPolykey.ts | 2 + tests/grpc/GRPCServer.test.ts | 29 +++- tests/grpc/utils.test.ts | 205 +++++++++++++++++++++++++---- tests/grpc/utils/GRPCClientTest.ts | 50 +++++-- tests/grpc/utils/testService.ts | 20 ++- 5 files changed, 268 insertions(+), 38 deletions(-) diff --git a/src/ErrorPolykey.ts b/src/ErrorPolykey.ts index b7286859e..b4a1d046f 100644 --- a/src/ErrorPolykey.ts +++ b/src/ErrorPolykey.ts @@ -16,6 +16,7 @@ class ErrorPolykey extends AbstractError { typeof json.data !== 'object' || typeof json.data.message !== 'string' || isNaN(Date.parse(json.data.timestamp)) || + typeof json.data.description !== 'string' || typeof json.data.data !== 'object' || typeof json.data.exitCode !== 'number' || ('stack' in json.data && typeof json.data.stack !== 'string') @@ -34,6 +35,7 @@ class ErrorPolykey extends AbstractError { public toJSON(): any { const json = super.toJSON(); + json.data.description = this.description; json.data.exitCode = this.exitCode; return json; } diff --git a/tests/grpc/GRPCServer.test.ts b/tests/grpc/GRPCServer.test.ts index 6b77673e4..83455859b 100644 --- a/tests/grpc/GRPCServer.test.ts +++ b/tests/grpc/GRPCServer.test.ts @@ -1,6 +1,5 @@ import type { Authenticate } from '@/client/types'; import type { Host, Port } from '@/network/types'; -import type { ClientMetadata } from '@/types'; import os from 'os'; import path from 'path'; import fs from 'fs'; @@ -161,7 +160,12 @@ describe('GRPCServer', () => { ); const unary = grpcUtils.promisifyUnaryCall( client, - {} as ClientMetadata, + { + nodeId: nodeIdServer, + host: server.getHost(), + port: server.getPort(), + command: 'unary', + }, client.unary, ); const m = new utilsPB.EchoMessage(); @@ -215,7 +219,12 @@ describe('GRPCServer', () => { ); const unary1 = grpcUtils.promisifyUnaryCall( client1, - {} as ClientMetadata, + { + nodeId: nodeIdServer1, + host: server.getHost(), + port: server.getPort(), + command: 'unary1', + }, client1.unary, ); const m1 = new utilsPB.EchoMessage(); @@ -253,7 +262,12 @@ describe('GRPCServer', () => { ); const unary2 = grpcUtils.promisifyUnaryCall( client2, - {} as ClientMetadata, + { + nodeId: nodeIdServer2, + host: server.getHost(), + port: server.getPort(), + command: 'unary2', + }, client2.unary, ); const m3 = new utilsPB.EchoMessage(); @@ -307,7 +321,12 @@ describe('GRPCServer', () => { ); const unary = grpcUtils.promisifyUnaryCall( client, - {} as ClientMetadata, + { + nodeId: nodeIdServer, + host: server.getHost(), + port: server.getPort(), + command: 'unary', + }, client.unaryAuthenticated, ); const m = new utilsPB.EchoMessage(); diff --git a/tests/grpc/utils.test.ts b/tests/grpc/utils.test.ts index 82a8e2c21..7364d6bff 100644 --- a/tests/grpc/utils.test.ts +++ b/tests/grpc/utils.test.ts @@ -1,5 +1,5 @@ import type { TestServiceClient } from '@/proto/js/polykey/v1/test_service_grpc_pb'; -import type { ClientMetadata } from '@/types'; +import type { Host, Port } from '@/network/types'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import { getLogger } from '@grpc/grpc-js/build/src/logging'; @@ -8,12 +8,15 @@ import * as grpcErrors from '@/grpc/errors'; import * as errors from '@/errors'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as utils from './utils'; +import * as testUtils from '../utils'; describe('GRPC utils', () => { const logger = new Logger('GRPC utils Test', LogLevel.WARN, [ new StreamHandler(), ]); let client: TestServiceClient, server: grpc.Server, port: number; + const nodeId = testUtils.generateRandomNodeId(); + const host = '127.0.0.1' as Host; beforeAll(async () => { // Mocked authenticate always passes authentication const authenticate = async (metaClient, metaServer = new grpc.Metadata()) => @@ -42,7 +45,12 @@ describe('GRPC utils', () => { test('promisified client unary call', async () => { const unary = grpcUtils.promisifyUnaryCall( client, - {} as ClientMetadata, + { + nodeId, + host, + port: port as Port, + command: 'unary', + }, client.unary, ); const messageTo = new utilsPB.EchoMessage(); @@ -55,7 +63,12 @@ describe('GRPC utils', () => { test('promisified client unary call error', async () => { const unary = grpcUtils.promisifyUnaryCall( client, - {} as ClientMetadata, + { + nodeId, + host, + port: port as Port, + command: 'unary', + }, client.unary, ); const messageTo = new utilsPB.EchoMessage(); @@ -67,6 +80,10 @@ describe('GRPC utils', () => { } catch (e) { // This information comes from the server expect(e.message).toBe('test error'); + expect(e.metadata.nodeId).toBe(nodeId); + expect(e.metadata.host).toBe(host); + expect(e.metadata.port).toBe(port); + expect(e.metadata.command).toBe('unary'); expect(e.cause).toBeInstanceOf(grpcErrors.ErrorGRPC); expect(e.cause.data).toMatchObject({ grpc: true, @@ -77,7 +94,12 @@ describe('GRPC utils', () => { const serverStream = grpcUtils.promisifyReadableStreamCall( client, - {} as ClientMetadata, + { + nodeId, + host, + port: port as Port, + command: 'serverStream', + }, client.serverStream, ); const challenge = '4444'; @@ -103,7 +125,12 @@ describe('GRPC utils', () => { const serverStream = grpcUtils.promisifyReadableStreamCall( client, - {} as ClientMetadata, + { + nodeId, + host, + port: port as Port, + command: 'serverStream', + }, client.serverStream, ); const challenge = 'error'; @@ -128,7 +155,12 @@ describe('GRPC utils', () => { const serverStream = grpcUtils.promisifyReadableStreamCall( client, - {} as ClientMetadata, + { + nodeId, + host, + port: port as Port, + command: 'serverStream', + }, client.serverStream, ); const challenge = '4444'; @@ -153,7 +185,12 @@ describe('GRPC utils', () => { const serverStream = grpcUtils.promisifyReadableStreamCall( client, - {} as ClientMetadata, + { + nodeId, + host, + port: port as Port, + command: 'serverStream', + }, client.serverStream, ); const challenge = '4444'; @@ -181,7 +218,16 @@ describe('GRPC utils', () => { const clientStream = grpcUtils.promisifyWritableStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, {} as ClientMetadata, client.clientStream); + >( + client, + { + nodeId, + host, + port: port as Port, + command: 'clientStream', + }, + client.clientStream, + ); const [genStream, response] = clientStream(); const m = new utilsPB.EchoMessage(); m.setChallenge('d89f7u983e4d'); @@ -198,7 +244,16 @@ describe('GRPC utils', () => { const clientStream = grpcUtils.promisifyWritableStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, {} as ClientMetadata, client.clientStream); + >( + client, + { + nodeId, + host, + port: port as Port, + command: 'clientStream', + }, + client.clientStream, + ); const [genStream, response] = clientStream(); const result1 = await genStream.next(null); // Closed stream expect(result1).toMatchObject({ @@ -219,7 +274,16 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, {} as ClientMetadata, client.duplexStream); + >( + client, + { + nodeId, + host, + port: port as Port, + command: 'duplexStream', + }, + client.duplexStream, + ); const genDuplex = duplexStream(); const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('d89f7u983e4d'); @@ -237,7 +301,16 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, {} as ClientMetadata, client.duplexStream); + >( + client, + { + nodeId, + host, + port: port as Port, + command: 'duplexStream', + }, + client.duplexStream, + ); const genDuplex = duplexStream(); await genDuplex.next(null); expect(genDuplex.stream.destroyed).toBe(true); @@ -247,7 +320,16 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, {} as ClientMetadata, client.duplexStream); + >( + client, + { + nodeId, + host, + port: port as Port, + command: 'duplexStream', + }, + client.duplexStream, + ); const genDuplex = duplexStream(); // When duplex streams are ended, reading will hang await genDuplex.write(null); @@ -260,7 +342,16 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, {} as ClientMetadata, client.duplexStream); + >( + client, + { + nodeId, + host, + port: port as Port, + command: 'duplexStream', + }, + client.duplexStream, + ); const genDuplex = duplexStream(); await genDuplex.read(null); const messageTo = new utilsPB.EchoMessage(); @@ -280,7 +371,16 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, {} as ClientMetadata, client.duplexStream); + >( + client, + { + nodeId, + host, + port: port as Port, + command: 'duplexStream', + }, + client.duplexStream, + ); const genDuplex = duplexStream(); const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('error'); @@ -295,7 +395,16 @@ describe('GRPC utils', () => { const duplexStream = grpcUtils.promisifyDuplexStreamCall< utilsPB.EchoMessage, utilsPB.EchoMessage - >(client, {} as ClientMetadata, client.duplexStream); + >( + client, + { + nodeId, + host, + port: port as Port, + command: 'duplexStream', + }, + client.duplexStream, + ); const genDuplex = duplexStream(); const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('error'); @@ -330,10 +439,23 @@ describe('GRPC utils', () => { details: '', metadata: serialised, }, - {} as ClientMetadata, + { + nodeId, + host, + port: port as Port, + command: 'testCall', + }, ); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); + // @ts-ignore - already checked above that error is ErrorPolykeyRemote + expect(deserialisedError.metadata.nodeId).toBe(nodeId); + // @ts-ignore + expect(deserialisedError.metadata.host).toBe(host); + // @ts-ignore + expect(deserialisedError.metadata.port).toBe(port); + // @ts-ignore + expect(deserialisedError.metadata.command).toBe('testCall'); expect(deserialisedError.cause).toBeInstanceOf(errors.ErrorPolykey); expect(deserialisedError.cause.message).toBe('test error'); expect(deserialisedError.cause.exitCode).toBe(255); @@ -358,10 +480,23 @@ describe('GRPC utils', () => { details: '', metadata: serialised, }, - {} as ClientMetadata, + { + nodeId, + host, + port: port as Port, + command: 'testCall', + }, ); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); + // @ts-ignore - already checked above that error is ErrorPolykeyRemote + expect(deserialisedError.metadata.nodeId).toBe(nodeId); + // @ts-ignore + expect(deserialisedError.metadata.host).toBe(host); + // @ts-ignore + expect(deserialisedError.metadata.port).toBe(port); + // @ts-ignore + expect(deserialisedError.metadata.command).toBe('testCall'); expect(deserialisedError.cause).toBeInstanceOf(TypeError); expect(deserialisedError.cause.message).toBe('test error'); expect(deserialisedError.cause.stack).toBe(error.stack); @@ -380,13 +515,26 @@ describe('GRPC utils', () => { details: '', metadata: serialised, }, - {} as ClientMetadata, + { + nodeId, + host, + port: port as Port, + command: 'testCall', + }, ); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); - expect(deserialisedError.message).toBe(''); + // @ts-ignore - already checked above that error is ErrorPolykeyRemote + expect(deserialisedError.metadata.nodeId).toBe(nodeId); + // @ts-ignore + expect(deserialisedError.metadata.host).toBe(host); + // @ts-ignore + expect(deserialisedError.metadata.port).toBe(port); + // @ts-ignore + expect(deserialisedError.metadata.command).toBe('testCall'); expect(deserialisedError.cause).toBeInstanceOf(errors.ErrorPolykeyUnknown); - expect(deserialisedError.cause.message).toBe(''); - expect(deserialisedError.cause.data).toEqual('not an error'); + // This is slightly brittle because it's based on what we choose to do + // with unknown data in our grpc reviver + expect(deserialisedError.cause.data.json).toEqual('not an error'); }); test('serialising and deserialising sensitive errors', async () => { const timestamp = new Date(); @@ -420,10 +568,23 @@ describe('GRPC utils', () => { details: '', metadata: serialised, }, - {} as ClientMetadata, + { + nodeId, + host, + port: port as Port, + command: 'testCall', + }, ); expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); + // @ts-ignore - already checked above that error is ErrorPolykeyRemote + expect(deserialisedError.metadata.nodeId).toBe(nodeId); + // @ts-ignore + expect(deserialisedError.metadata.host).toBe(host); + // @ts-ignore + expect(deserialisedError.metadata.port).toBe(port); + // @ts-ignore + expect(deserialisedError.metadata.command).toBe('testCall'); expect(deserialisedError.cause).toBeInstanceOf(errors.ErrorPolykey); expect(deserialisedError.cause.message).toBe('test error'); expect(deserialisedError.cause.exitCode).toBe(255); diff --git a/tests/grpc/utils/GRPCClientTest.ts b/tests/grpc/utils/GRPCClientTest.ts index b628eba27..e3c5f9489 100644 --- a/tests/grpc/utils/GRPCClientTest.ts +++ b/tests/grpc/utils/GRPCClientTest.ts @@ -5,7 +5,6 @@ import type { Host, Port, TLSConfig, ProxyConfig } from '@/network/types'; import type * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import type { ClientReadableStream } from '@grpc/grpc-js/build/src/call'; import type { AsyncGeneratorReadableStreamClient } from '@/grpc/types'; -import type { ClientMetadata } from '@/types'; import Logger from '@matrixai/logger'; import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; import GRPCClient from '@/grpc/GRPCClient'; @@ -76,7 +75,12 @@ class GRPCClientTest extends GRPCClient { public unary(...args) { return grpcUtils.promisifyUnaryCall( this.client, - {} as ClientMetadata, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + command: this.unary.name, + }, this.client.unary, )(...args); } @@ -85,7 +89,12 @@ class GRPCClientTest extends GRPCClient { public serverStream(...args) { return grpcUtils.promisifyReadableStreamCall( this.client, - {} as ClientMetadata, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + command: this.serverStream.name, + }, this.client.serverStream, )(...args); } @@ -97,7 +106,12 @@ class GRPCClientTest extends GRPCClient { utilsPB.EchoMessage >( this.client, - {} as ClientMetadata, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + command: this.clientStream.name, + }, this.client.clientStream, )(...args); } @@ -109,7 +123,12 @@ class GRPCClientTest extends GRPCClient { utilsPB.EchoMessage >( this.client, - {} as ClientMetadata, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + command: this.duplexStream.name, + }, this.client.duplexStream, )(...args); } @@ -118,7 +137,12 @@ class GRPCClientTest extends GRPCClient { public unaryAuthenticated(...args) { return grpcUtils.promisifyUnaryCall( this.client, - {} as ClientMetadata, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + command: this.unaryAuthenticated.name, + }, this.client.unaryAuthenticated, )(...args); } @@ -132,7 +156,12 @@ class GRPCClientTest extends GRPCClient { > { return grpcUtils.promisifyReadableStreamCall( this.client, - {} as ClientMetadata, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + command: this.serverStreamFail.name, + }, this.client.serverStreamFail, )(...args); } @@ -141,7 +170,12 @@ class GRPCClientTest extends GRPCClient { public unaryFail(...args) { return grpcUtils.promisifyUnaryCall( this.client, - {} as ClientMetadata, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + command: this.unaryFail.name, + }, this.client.unaryFail, )(...args); } diff --git a/tests/grpc/utils/testService.ts b/tests/grpc/utils/testService.ts index 2769d103e..bec280ffc 100644 --- a/tests/grpc/utils/testService.ts +++ b/tests/grpc/utils/testService.ts @@ -7,7 +7,7 @@ import type { Authenticate } from '@/client/types'; import type { SessionToken } from '@/sessions/types'; import type { ITestServiceServer } from '@/proto/js/polykey/v1/test_service_grpc_pb'; -import type { ClientMetadata } from '@/types'; +import type { Host, Port } from '@/network/types'; import Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import * as grpcUtils from '@/grpc/utils'; @@ -15,6 +15,7 @@ import * as grpcErrors from '@/grpc/errors'; import * as clientUtils from '@/client/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import { sleep } from '@/utils'; +import * as testUtils from '../../utils'; function createTestService({ authenticate, @@ -23,6 +24,9 @@ function createTestService({ authenticate: Authenticate; logger?: Logger; }) { + const nodeId = testUtils.generateRandomNodeId(); + const host = '127.0.0.1' as Host; + const port = 0 as Port; const testService: ITestServiceServer = { unary: async ( call: grpc.ServerUnaryCall, @@ -105,7 +109,12 @@ function createTestService({ } const genReadable = grpcUtils.generatorReadable( call, - {} as ClientMetadata, + { + nodeId, + host, + port, + command: 'genReadable', + }, ); let data = ''; try { @@ -137,7 +146,12 @@ function createTestService({ } const genDuplex = grpcUtils.generatorDuplex( call, - {} as ClientMetadata, + { + nodeId, + host, + port, + command: 'genDuplex', + }, false, ); const readStatus = await genDuplex.read(); From d0f82dda41ae967be4d796aebaf98ef042d72c1f Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Thu, 26 May 2022 14:19:31 +1000 Subject: [PATCH 053/137] tests: split vaults secrets client service tests --- src/client/GRPCClientClient.ts | 2 +- src/client/service/vaultsSecretsMkdir.ts | 2 +- tests/client/rpcVaults.test.ts | 349 ------------------ tests/client/service/vaultsLog.test.ts | 2 +- .../client/service/vaultsSecretsEdit.test.ts | 141 +++++++ .../client/service/vaultsSecretsMkdir.test.ts | 133 +++++++ .../service/vaultsSecretsNewDeleteGet.test.ts | 169 +++++++++ .../service/vaultsSecretsNewDirList.test.ts | 157 ++++++++ .../service/vaultsSecretsRename.test.ts | 143 +++++++ .../client/service/vaultsSecretsStat.test.ts | 137 +++++++ 10 files changed, 883 insertions(+), 352 deletions(-) delete mode 100644 tests/client/rpcVaults.test.ts create mode 100644 tests/client/service/vaultsSecretsEdit.test.ts create mode 100644 tests/client/service/vaultsSecretsMkdir.test.ts create mode 100644 tests/client/service/vaultsSecretsNewDeleteGet.test.ts create mode 100644 tests/client/service/vaultsSecretsNewDirList.test.ts create mode 100644 tests/client/service/vaultsSecretsRename.test.ts create mode 100644 tests/client/service/vaultsSecretsStat.test.ts diff --git a/src/client/GRPCClientClient.ts b/src/client/GRPCClientClient.ts index 9492841ed..c69d58d89 100644 --- a/src/client/GRPCClientClient.ts +++ b/src/client/GRPCClientClient.ts @@ -314,7 +314,7 @@ class GRPCClientClient extends GRPCClient { @ready(new clientErrors.ErrorClientClientDestroyed()) public vaultsSecretsMkdir(...args) { - return grpcUtils.promisifyUnaryCall( + return grpcUtils.promisifyUnaryCall( this.client, { nodeId: this.nodeId, diff --git a/src/client/service/vaultsSecretsMkdir.ts b/src/client/service/vaultsSecretsMkdir.ts index 6d5649fb5..f441207cc 100644 --- a/src/client/service/vaultsSecretsMkdir.ts +++ b/src/client/service/vaultsSecretsMkdir.ts @@ -22,7 +22,7 @@ function vaultsSecretsMkdir({ logger: Logger; }) { return async ( - call: grpc.ServerUnaryCall, + call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData, ): Promise => { try { diff --git a/tests/client/rpcVaults.test.ts b/tests/client/rpcVaults.test.ts deleted file mode 100644 index eefd4943f..000000000 --- a/tests/client/rpcVaults.test.ts +++ /dev/null @@ -1,349 +0,0 @@ -import type * as grpc from '@grpc/grpc-js'; -import type VaultManager from '@/vaults/VaultManager'; -import type { VaultName } from '@/vaults/types'; -import type { ClientServiceClient } from '@/proto/js/polykey/v1/client_service_grpc_pb'; -import type { Stat } from 'encryptedfs'; -import type * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; -import type { ClientMetadata } from '@/types'; -import os from 'os'; -import path from 'path'; -import fs from 'fs'; -import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import PolykeyAgent from '@/PolykeyAgent'; -import KeyManager from '@/keys/KeyManager'; -import Proxy from '@/network/Proxy'; -import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; -import * as secretsPB from '@/proto/js/polykey/v1/secrets/secrets_pb'; -import * as grpcUtils from '@/grpc/utils'; -import * as vaultsUtils from '@/vaults/utils'; -import * as vaultOps from '@/vaults/VaultOps'; -import * as clientUtils from './utils'; - -jest.mock('@/keys/utils', () => ({ - ...jest.requireActual('@/keys/utils'), - generateDeterministicKeyPair: - jest.requireActual('@/keys/utils').generateKeyPair, -})); - -describe('Vaults client service', () => { - const password = 'password'; - const logger = new Logger('VaultsClientServerTest', LogLevel.WARN, [ - new StreamHandler(), - ]); - const vaultList = [ - 'Vault1' as VaultName, - 'Vault2' as VaultName, - 'Vault3' as VaultName, - 'Vault4' as VaultName, - ]; - const secretList = ['Secret1', 'Secret2', 'Secret3', 'Secret4']; - - let client: ClientServiceClient; - let server: grpc.Server; - let port: number; - let dataDir: string; - let pkAgent: PolykeyAgent; - let keyManager: KeyManager; - let vaultManager: VaultManager; - let passwordFile: string; - let callCredentials: grpc.Metadata; - - beforeAll(async () => { - dataDir = await fs.promises.mkdtemp( - path.join(os.tmpdir(), 'polykey-test-'), - ); - - passwordFile = path.join(dataDir, 'password'); - await fs.promises.writeFile(passwordFile, 'password'); - const keysPath = path.join(dataDir, 'keys'); - - keyManager = await KeyManager.createKeyManager({ - keysPath, - password, - logger, - }); - - const proxy = new Proxy({ - authToken: 'abc', - logger: logger, - }); - - pkAgent = await PolykeyAgent.createPolykeyAgent({ - password, - nodePath: dataDir, - logger, - proxy, - keyManager, - }); - - vaultManager = pkAgent.vaultManager; - - [server, port] = await clientUtils.openTestClientServer({ - pkAgent, - secure: false, - }); - - client = await clientUtils.openSimpleClientClient(port); - }, global.polykeyStartupTimeout); - afterAll(async () => { - await clientUtils.closeTestClientServer(server); - clientUtils.closeSimpleClientClient(client); - - await pkAgent.stop(); - await pkAgent.destroy(); - - await fs.promises.rm(dataDir, { - force: true, - recursive: true, - }); - await fs.promises.rm(passwordFile); - }); - beforeEach(async () => { - const sessionToken = await pkAgent.sessionManager.createToken(); - callCredentials = clientUtils.createCallCredentials(sessionToken); - }); - afterEach(async () => { - const aliveVaults = await vaultManager.listVaults(); - for (const vaultId of aliveVaults.values()) { - await vaultManager.destroyVault(vaultId); - } - }); - describe('Secrets', () => { - test('should make a directory in a vault', async () => { - const mkdirVault = grpcUtils.promisifyUnaryCall( - client, - {} as ClientMetadata, - client.vaultsSecretsMkdir, - ); - - const vaultId = await vaultManager.createVault(vaultList[0]); - const dirPath = 'dir/dir1/dir2'; - const vaultMkdirMessage = new vaultsPB.Mkdir(); - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); - vaultMkdirMessage.setVault(vaultMessage); - vaultMkdirMessage.setDirName(dirPath); - vaultMkdirMessage.setRecursive(true); - await mkdirVault(vaultMkdirMessage, callCredentials); - await vaultManager.withVaults([vaultId], async (vault) => { - await vault.readF(async (efs) => { - expect(await efs.exists(dirPath)).toBeTruthy(); - }); - }); - }); - test('should list secrets in a vault', async () => { - const listSecretsVault = - grpcUtils.promisifyReadableStreamCall( - client, - {} as ClientMetadata, - client.vaultsSecretsList, - ); - - const vaultId = await vaultManager.createVault(vaultList[0]); - await vaultManager.withVaults([vaultId], async (vault) => { - await vault.writeF(async (efs) => { - for (const secretName of secretList) { - await efs.writeFile(secretName, secretName); - } - }); - }); - - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); - const secretsStream = listSecretsVault(vaultMessage, callCredentials); - const names: Array = []; - for await (const secret of secretsStream) { - names.push(secret.getSecretName()); - } - expect(names.sort()).toStrictEqual(secretList.sort()); - }); - test('should delete secrets in a vault', async () => { - const deleteSecretVault = - grpcUtils.promisifyUnaryCall( - client, - {} as ClientMetadata, - client.vaultsSecretsDelete, - ); - - const vaultId = await vaultManager.createVault(vaultList[0]); - await vaultManager.withVaults([vaultId], async (vault) => { - await vault.writeF(async (efs) => { - for (const secretName of secretList) { - await efs.writeFile(secretName, secretName); - } - }); - }); - - const secretMessage = new secretsPB.Secret(); - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); - secretMessage.setVault(vaultMessage); - secretMessage.setSecretName(secretList[0]); - await deleteSecretVault(secretMessage, callCredentials); - await vaultManager.withVaults([vaultId], async (vault) => { - const secrets = await vault.readF(async (efs) => { - return await efs.readdir('.', { encoding: 'utf8' }); - }); - expect(secrets.sort()).toEqual(secretList.slice(1).sort()); - }); - }); - test('should edit secrets in a vault', async () => { - const editSecretVault = - grpcUtils.promisifyUnaryCall( - client, - {} as ClientMetadata, - client.vaultsSecretsEdit, - ); - const vaultId = await vaultManager.createVault(vaultList[0]); - await vaultManager.withVaults([vaultId], async (vault) => { - await vault.writeF(async (efs) => { - await efs.writeFile(secretList[0], secretList[0]); - }); - }); - const secretMessage = new secretsPB.Secret(); - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); - secretMessage.setVault(vaultMessage); - secretMessage.setSecretName(secretList[0]); - secretMessage.setSecretContent(Buffer.from('content-change')); - await editSecretVault(secretMessage, callCredentials); - - await vaultManager.withVaults([vaultId], async (vault) => { - await vault.readF(async (efs) => { - expect((await efs.readFile(secretList[0])).toString()).toStrictEqual( - 'content-change', - ); - }); - }); - }); - test('should get secrets in a vault', async () => { - const getSecretVault = grpcUtils.promisifyUnaryCall( - client, - {} as ClientMetadata, - client.vaultsSecretsGet, - ); - const vaultId = await vaultManager.createVault(vaultList[0]); - await vaultManager.withVaults([vaultId], async (vault) => { - await vault.writeF(async (efs) => { - await efs.writeFile(secretList[0], secretList[0]); - }); - }); - const secretMessage = new secretsPB.Secret(); - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); - secretMessage.setVault(vaultMessage); - secretMessage.setSecretName(secretList[0]); - const secret = await getSecretVault(secretMessage, callCredentials); - const secretContent = Buffer.from(secret.getSecretContent()).toString(); - expect(secretContent).toStrictEqual(secretList[0]); - }); - test('should rename secrets in a vault', async () => { - const renameSecretVault = - grpcUtils.promisifyUnaryCall( - client, - {} as ClientMetadata, - client.vaultsSecretsRename, - ); - const vaultId = await vaultManager.createVault(vaultList[0]); - await vaultManager.withVaults([vaultId], async (vault) => { - await vault.writeF(async (efs) => { - await efs.writeFile(secretList[0], secretList[0]); - }); - }); - const secretRenameMessage = new secretsPB.Rename(); - const vaultMessage = new vaultsPB.Vault(); - const secretMessage = new secretsPB.Secret(); - - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); - secretMessage.setSecretName(secretList[0]); - secretMessage.setVault(vaultMessage); - secretRenameMessage.setNewName(secretList[1]); - secretRenameMessage.setOldSecret(secretMessage); - await renameSecretVault(secretRenameMessage, callCredentials); - - await vaultManager.withVaults([vaultId], async (vault) => { - const secrets = await vault.readF(async (efs) => { - return await efs.readdir('.'); - }); - expect(secrets.sort()).toEqual(secretList.splice(1, 1).sort()); - }); - }); - test('should add secrets in a vault', async () => { - const newSecretVault = - grpcUtils.promisifyUnaryCall( - client, - {} as ClientMetadata, - client.vaultsSecretsNew, - ); - - const vaultId = await vaultManager.createVault(vaultList[0]); - const secretMessage = new secretsPB.Secret(); - const vaultMessage = new vaultsPB.Vault(); - - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); - secretMessage.setVault(vaultMessage); - secretMessage.setSecretName(secretList[0]); - secretMessage.setSecretContent(Buffer.from(secretList[0])); - await newSecretVault(secretMessage, callCredentials); - await vaultManager.withVaults([vaultId], async (vault) => { - const secret = await vault.readF(async (efs) => { - return await efs.readFile(secretList[0], { encoding: 'utf8' }); - }); - expect(secret).toBe(secretList[0]); - }); - }); - test('should add a directory of secrets in a vault', async () => { - const newDirSecretVault = - grpcUtils.promisifyUnaryCall( - client, - {} as ClientMetadata, - client.vaultsSecretsNewDir, - ); - - const secretDir = path.join(dataDir, 'secretDir'); - await fs.promises.mkdir(secretDir); - for (const secret of secretList) { - const secretFile = path.join(secretDir, secret); - // Write secret to file - await fs.promises.writeFile(secretFile, secret); - } - const vaultId = await vaultManager.createVault(vaultList[0]); - const secretDirectoryMessage = new secretsPB.Directory(); - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); - secretDirectoryMessage.setVault(vaultMessage); - secretDirectoryMessage.setSecretDirectory(secretDir); - await newDirSecretVault(secretDirectoryMessage, callCredentials); - await vaultManager.withVaults([vaultId], async (vault) => { - const secrets = await vaultOps.listSecrets(vault); - expect(secrets.sort()).toEqual( - secretList.map((secret) => path.join('secretDir', secret)).sort(), - ); - }); - }); - test('should stat a file', async () => { - const getSecretStat = grpcUtils.promisifyUnaryCall( - client, - {} as ClientMetadata, - client.vaultsSecretsStat, - ); - const vaultId = await vaultManager.createVault(vaultList[0]); - await vaultManager.withVaults([vaultId], async (vault) => { - await vault.writeF(async (efs) => { - await efs.writeFile(secretList[0], secretList[0]); - }); - }); - const secretMessage = new secretsPB.Secret(); - const vaultMessage = new vaultsPB.Vault(); - vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); - secretMessage.setVault(vaultMessage); - secretMessage.setSecretName(secretList[0]); - const result = await getSecretStat(secretMessage, callCredentials); - const stat: Stat = JSON.parse(result.getJson()); - expect(stat.size).toBe(7); - expect(stat.blksize).toBe(4096); - expect(stat.blocks).toBe(1); - expect(stat.nlink).toBe(1); - }); - }); -}); diff --git a/tests/client/service/vaultsLog.test.ts b/tests/client/service/vaultsLog.test.ts index d2f5ed26d..9a3e9f6c9 100644 --- a/tests/client/service/vaultsLog.test.ts +++ b/tests/client/service/vaultsLog.test.ts @@ -117,7 +117,7 @@ describe('vaultsLog', () => { port: grpcServer.getPort(), logger, }); - }); + }, global.defaultTimeout * 2); afterEach(async () => { await grpcClient.destroy(); await grpcServer.stop(); diff --git a/tests/client/service/vaultsSecretsEdit.test.ts b/tests/client/service/vaultsSecretsEdit.test.ts new file mode 100644 index 000000000..0956bac33 --- /dev/null +++ b/tests/client/service/vaultsSecretsEdit.test.ts @@ -0,0 +1,141 @@ +import type { Host, Port } from '@/network/types'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import KeyManager from '@/keys/KeyManager'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsSecretsEdit from '@/client/service/vaultsSecretsEdit'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; +import * as secretsPB from '@/proto/js/polykey/v1/secrets/secrets_pb'; +import * as clientUtils from '@/client/utils/utils'; +import * as vaultsUtils from '@/vaults/utils'; +import * as keysUtils from '@/keys/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsSecretsEdit', () => { + const logger = new Logger('vaultsSecretsEdit test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + let dataDir: string; + let keyManager: KeyManager; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = path.join(dataDir, 'keys'); + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + const clientService = { + vaultsSecretsEdit: vaultsSecretsEdit({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('edits secrets', async () => { + const vaultName = 'test-vault'; + const secretName = 'test-secret'; + const vaultId = await vaultManager.createVault(vaultName); + await vaultManager.withVaults([vaultId], async (vault) => { + await vault.writeF(async (efs) => { + await efs.writeFile(secretName, secretName); + }); + }); + const secretMessage = new secretsPB.Secret(); + const vaultMessage = new vaultsPB.Vault(); + vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); + secretMessage.setVault(vaultMessage); + secretMessage.setSecretName(secretName); + secretMessage.setSecretContent(Buffer.from('content-change')); + const response = await grpcClient.vaultsSecretsEdit( + secretMessage, + clientUtils.encodeAuthFromPassword(password), + ); + expect(response).toBeInstanceOf(utilsPB.StatusMessage); + expect(response.getSuccess()).toBeTruthy(); + await vaultManager.withVaults([vaultId], async (vault) => { + await vault.readF(async (efs) => { + expect((await efs.readFile(secretName)).toString()).toStrictEqual( + 'content-change', + ); + }); + }); + }); +}); diff --git a/tests/client/service/vaultsSecretsMkdir.test.ts b/tests/client/service/vaultsSecretsMkdir.test.ts new file mode 100644 index 000000000..1e4c1b971 --- /dev/null +++ b/tests/client/service/vaultsSecretsMkdir.test.ts @@ -0,0 +1,133 @@ +import type { Host, Port } from '@/network/types'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import KeyManager from '@/keys/KeyManager'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsSecretsMkdir from '@/client/service/vaultsSecretsMkdir'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; +import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '@/client/utils/utils'; +import * as vaultsUtils from '@/vaults/utils'; +import * as keysUtils from '@/keys/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsSecretsMkdir', () => { + const logger = new Logger('vaultsSecretsMkdir test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + let dataDir: string; + let keyManager: KeyManager; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = path.join(dataDir, 'keys'); + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + const clientService = { + vaultsSecretsMkdir: vaultsSecretsMkdir({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('makes a directory', async () => { + const vaultName = 'test-vault'; + const vaultId = await vaultManager.createVault(vaultName); + const dirPath = 'dir/dir1/dir2'; + const vaultMkdirMessage = new vaultsPB.Mkdir(); + const vaultMessage = new vaultsPB.Vault(); + vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); + vaultMkdirMessage.setVault(vaultMessage); + vaultMkdirMessage.setDirName(dirPath); + vaultMkdirMessage.setRecursive(true); + const response = await grpcClient.vaultsSecretsMkdir( + vaultMkdirMessage, + clientUtils.encodeAuthFromPassword(password), + ); + expect(response).toBeInstanceOf(utilsPB.StatusMessage); + expect(response.getSuccess()).toBeTruthy(); + await vaultManager.withVaults([vaultId], async (vault) => { + await vault.readF(async (efs) => { + expect(await efs.exists(dirPath)).toBeTruthy(); + }); + }); + }); +}); diff --git a/tests/client/service/vaultsSecretsNewDeleteGet.test.ts b/tests/client/service/vaultsSecretsNewDeleteGet.test.ts new file mode 100644 index 000000000..f743f6ff0 --- /dev/null +++ b/tests/client/service/vaultsSecretsNewDeleteGet.test.ts @@ -0,0 +1,169 @@ +import type { Host, Port } from '@/network/types'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import KeyManager from '@/keys/KeyManager'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsSecretsNew from '@/client/service/vaultsSecretsNew'; +import vaultsSecretsDelete from '@/client/service/vaultsSecretsDelete'; +import vaultsSecretsGet from '@/client/service/vaultsSecretsGet'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; +import * as secretsPB from '@/proto/js/polykey/v1/secrets/secrets_pb'; +import * as clientUtils from '@/client/utils/utils'; +import * as vaultsUtils from '@/vaults/utils'; +import * as keysUtils from '@/keys/utils'; +import * as vaultsErrors from '@/vaults/errors'; +import * as testUtils from '../../utils'; + +describe('vaultsSecretsNewDeleteGet', () => { + const logger = new Logger('vaultsSecretsNewDeleteGet test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + let dataDir: string; + let keyManager: KeyManager; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = path.join(dataDir, 'keys'); + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + const clientService = { + vaultsSecretsNew: vaultsSecretsNew({ + authenticate, + vaultManager, + db, + logger, + }), + vaultsSecretsDelete: vaultsSecretsDelete({ + authenticate, + vaultManager, + db, + logger, + }), + vaultsSecretsGet: vaultsSecretsGet({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('creates, gets, and deletes secrets', async () => { + // Create secret + const secret = 'test-secret'; + const vaultId = await vaultManager.createVault('test-vault'); + const secretMessage = new secretsPB.Secret(); + const vaultMessage = new vaultsPB.Vault(); + vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); + secretMessage.setVault(vaultMessage); + secretMessage.setSecretName(secret); + secretMessage.setSecretContent(Buffer.from(secret)); + const createResponse = await grpcClient.vaultsSecretsNew( + secretMessage, + clientUtils.encodeAuthFromPassword(password), + ); + expect(createResponse).toBeInstanceOf(utilsPB.StatusMessage); + expect(createResponse.getSuccess()).toBeTruthy(); + // Get secret + const getResponse1 = await grpcClient.vaultsSecretsGet( + secretMessage, + clientUtils.encodeAuthFromPassword(password), + ); + expect(getResponse1).toBeInstanceOf(secretsPB.Secret); + const secretContent = Buffer.from( + getResponse1.getSecretContent(), + ).toString(); + expect(secretContent).toStrictEqual(secret); + // Delete secret + const deleteResponse = await grpcClient.vaultsSecretsDelete( + secretMessage, + clientUtils.encodeAuthFromPassword(password), + ); + expect(deleteResponse).toBeInstanceOf(utilsPB.StatusMessage); + expect(deleteResponse.getSuccess()).toBeTruthy(); + // Check secret was deleted + await testUtils.expectRemoteError( + grpcClient.vaultsSecretsGet( + secretMessage, + clientUtils.encodeAuthFromPassword(password), + ), + vaultsErrors.ErrorSecretsSecretUndefined, + ); + }); +}); diff --git a/tests/client/service/vaultsSecretsNewDirList.test.ts b/tests/client/service/vaultsSecretsNewDirList.test.ts new file mode 100644 index 000000000..7e8911dbd --- /dev/null +++ b/tests/client/service/vaultsSecretsNewDirList.test.ts @@ -0,0 +1,157 @@ +import type { Host, Port } from '@/network/types'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import KeyManager from '@/keys/KeyManager'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsSecretsNewDir from '@/client/service/vaultsSecretsNewDir'; +import vaultsSecretsList from '@/client/service/vaultsSecretsList'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; +import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as secretsPB from '@/proto/js/polykey/v1/secrets/secrets_pb'; +import * as clientUtils from '@/client/utils/utils'; +import * as vaultsUtils from '@/vaults/utils'; +import * as keysUtils from '@/keys/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsSecretsNewDirList', () => { + const logger = new Logger('vaultsSecretsNewDirList test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + let dataDir: string; + let keyManager: KeyManager; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = path.join(dataDir, 'keys'); + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + const clientService = { + vaultsSecretsNewDir: vaultsSecretsNewDir({ + authenticate, + vaultManager, + fs, + db, + logger, + }), + vaultsSecretsList: vaultsSecretsList({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('adds and lists a directory of secrets', async () => { + // Add directory of secrets + const vaultName = 'test-vault'; + const secretList = ['test-secret1', 'test-secret2', 'test-secret3']; + const secretDir = path.join(dataDir, 'secretDir'); + await fs.promises.mkdir(secretDir); + for (const secret of secretList) { + const secretFile = path.join(secretDir, secret); + // Write secret to file + await fs.promises.writeFile(secretFile, secret); + } + const vaultId = await vaultManager.createVault(vaultName); + const secretDirectoryMessage = new secretsPB.Directory(); + const vaultMessage = new vaultsPB.Vault(); + vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); + secretDirectoryMessage.setVault(vaultMessage); + secretDirectoryMessage.setSecretDirectory(secretDir); + const addResponse = await grpcClient.vaultsSecretsNewDir( + secretDirectoryMessage, + clientUtils.encodeAuthFromPassword(password), + ); + expect(addResponse).toBeInstanceOf(utilsPB.StatusMessage); + expect(addResponse.getSuccess()).toBeTruthy(); + // List secrets + const listResponse = grpcClient.vaultsSecretsList( + vaultMessage, + clientUtils.encodeAuthFromPassword(password), + ); + const secrets: Array = []; + for await (const secret of listResponse) { + expect(secret).toBeInstanceOf(secretsPB.Secret); + secrets.push(secret.getSecretName()); + } + expect(secrets.sort()).toStrictEqual( + secretList.map((secret) => path.join('secretDir', secret)).sort(), + ); + }); +}); diff --git a/tests/client/service/vaultsSecretsRename.test.ts b/tests/client/service/vaultsSecretsRename.test.ts new file mode 100644 index 000000000..1d6027aa3 --- /dev/null +++ b/tests/client/service/vaultsSecretsRename.test.ts @@ -0,0 +1,143 @@ +import type { Host, Port } from '@/network/types'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import KeyManager from '@/keys/KeyManager'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsSecretsRename from '@/client/service/vaultsSecretsRename'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; +import * as secretsPB from '@/proto/js/polykey/v1/secrets/secrets_pb'; +import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '@/client/utils/utils'; +import * as vaultsUtils from '@/vaults/utils'; +import * as keysUtils from '@/keys/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsSecretsRename', () => { + const logger = new Logger('vaultsSecretsRename test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + let dataDir: string; + let keyManager: KeyManager; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = path.join(dataDir, 'keys'); + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + const clientService = { + vaultsSecretsRename: vaultsSecretsRename({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('renames a secret', async () => { + const vaultName = 'test-vault'; + const secretName = 'test-secret'; + const vaultId = await vaultManager.createVault(vaultName); + await vaultManager.withVaults([vaultId], async (vault) => { + await vault.writeF(async (efs) => { + await efs.writeFile(secretName, secretName); + }); + }); + const secretRenameMessage = new secretsPB.Rename(); + const vaultMessage = new vaultsPB.Vault(); + const secretMessage = new secretsPB.Secret(); + vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); + secretMessage.setSecretName(secretName); + secretMessage.setVault(vaultMessage); + secretRenameMessage.setNewName('name-change'); + secretRenameMessage.setOldSecret(secretMessage); + const response = await grpcClient.vaultsSecretsRename( + secretRenameMessage, + clientUtils.encodeAuthFromPassword(password), + ); + expect(response).toBeInstanceOf(utilsPB.StatusMessage); + expect(response.getSuccess()).toBeTruthy(); + await vaultManager.withVaults([vaultId], async (vault) => { + await vault.readF(async (efs) => { + expect((await efs.readFile('name-change')).toString()).toStrictEqual( + secretName, + ); + }); + }); + }); +}); diff --git a/tests/client/service/vaultsSecretsStat.test.ts b/tests/client/service/vaultsSecretsStat.test.ts new file mode 100644 index 000000000..909ee82b8 --- /dev/null +++ b/tests/client/service/vaultsSecretsStat.test.ts @@ -0,0 +1,137 @@ +import type { Stat } from 'encryptedfs'; +import type { Host, Port } from '@/network/types'; +import type NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import type ACL from '@/acl/ACL'; +import type GestaltGraph from '@/gestalts/GestaltGraph'; +import type NotificationsManager from '@/notifications/NotificationsManager'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { Metadata } from '@grpc/grpc-js'; +import KeyManager from '@/keys/KeyManager'; +import VaultManager from '@/vaults/VaultManager'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import vaultsSecretsStat from '@/client/service/vaultsSecretsStat'; +import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_pb'; +import * as vaultsPB from '@/proto/js/polykey/v1/vaults/vaults_pb'; +import * as secretsPB from '@/proto/js/polykey/v1/secrets/secrets_pb'; +import * as clientUtils from '@/client/utils/utils'; +import * as vaultsUtils from '@/vaults/utils'; +import * as keysUtils from '@/keys/utils'; +import * as testUtils from '../../utils'; + +describe('vaultsSecretsStat', () => { + const logger = new Logger('vaultsSecretsStat test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + const authenticate = async (metaClient, metaServer = new Metadata()) => + metaServer; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); + }); + afterAll(async () => { + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + let dataDir: string; + let keyManager: KeyManager; + let db: DB; + let vaultManager: VaultManager; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientClient; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = path.join(dataDir, 'keys'); + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + const dbPath = path.join(dataDir, 'db'); + db = await DB.createDB({ + dbPath, + logger, + }); + const vaultsPath = path.join(dataDir, 'vaults'); + vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + db, + acl: {} as ACL, + keyManager, + nodeConnectionManager: {} as NodeConnectionManager, + gestaltGraph: {} as GestaltGraph, + notificationsManager: {} as NotificationsManager, + logger, + }); + const clientService = { + vaultsSecretsStat: vaultsSecretsStat({ + authenticate, + vaultManager, + db, + logger, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[ClientServiceService, clientService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: testUtils.generateRandomNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }); + afterEach(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await vaultManager.stop(); + await db.stop(); + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('stats a file', async () => { + const vaultName = 'test-vault'; + const secretName = 'test-secret'; + const vaultId = await vaultManager.createVault(vaultName); + await vaultManager.withVaults([vaultId], async (vault) => { + await vault.writeF(async (efs) => { + await efs.writeFile(secretName, secretName); + }); + }); + const secretMessage = new secretsPB.Secret(); + const vaultMessage = new vaultsPB.Vault(); + vaultMessage.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); + secretMessage.setVault(vaultMessage); + secretMessage.setSecretName(secretName); + const response = await grpcClient.vaultsSecretsStat( + secretMessage, + clientUtils.encodeAuthFromPassword(password), + ); + expect(response).toBeInstanceOf(secretsPB.Stat); + const stat: Stat = JSON.parse(response.getJson()); + expect(stat.size).toBe(secretName.length); + expect(stat.blksize).toBe(4096); + expect(stat.blocks).toBe(1); + expect(stat.nlink).toBe(1); + }); +}); From 16ff93768e605e7ff398e724d9460abe911151fc Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Thu, 26 May 2022 14:54:02 +1000 Subject: [PATCH 054/137] tests: fix for nodesClaim test TypeError --- tests/client/service/nodesClaim.test.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/client/service/nodesClaim.test.ts b/tests/client/service/nodesClaim.test.ts index bee8c8ad3..bc04e2ae6 100644 --- a/tests/client/service/nodesClaim.test.ts +++ b/tests/client/service/nodesClaim.test.ts @@ -15,7 +15,6 @@ import NodeGraph from '@/nodes/NodeGraph'; import NodeManager from '@/nodes/NodeManager'; import Sigchain from '@/sigchain/Sigchain'; import Proxy from '@/network/Proxy'; - import GRPCServer from '@/grpc/GRPCServer'; import GRPCClientClient from '@/client/GRPCClientClient'; import nodesClaim from '@/client/service/nodesClaim'; @@ -26,7 +25,6 @@ import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; import * as testUtils from '../../utils'; -import { expectRemoteError } from '../../utils'; describe('nodesClaim', () => { const logger = new Logger('nodesClaim test', LogLevel.WARN, [ @@ -63,7 +61,7 @@ describe('nodesClaim', () => { mockedSendNotification = jest .spyOn(NotificationsManager.prototype, 'sendNotification') .mockResolvedValue(undefined); - mockedSendNotification = jest + mockedClaimNode = jest .spyOn(NodeManager.prototype, 'claimNode') .mockResolvedValue(undefined); }); @@ -83,7 +81,6 @@ describe('nodesClaim', () => { let acl: ACL; let sigchain: Sigchain; let proxy: Proxy; - let db: DB; let keyManager: KeyManager; let grpcServer: GRPCServer; @@ -231,7 +228,7 @@ describe('nodesClaim', () => { test('cannot claim an invalid node', async () => { const request = new nodesPB.Claim(); request.setNodeId('nodeId'); - await expectRemoteError( + await testUtils.expectRemoteError( grpcClient.nodesClaim( request, clientUtils.encodeAuthFromPassword(password), From bd95bc8860261ae403cf96d22d719ade7ef9f4c8 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 26 May 2022 18:02:11 +1000 Subject: [PATCH 055/137] tests: fixing timeouts for tests failing in CI/CD --- tests/bin/identities/trustUntrustList.test.ts | 472 +++++++++--------- tests/nodes/NodeConnection.test.ts | 4 +- tests/vaults/VaultManager.test.ts | 220 ++++---- 3 files changed, 355 insertions(+), 341 deletions(-) diff --git a/tests/bin/identities/trustUntrustList.test.ts b/tests/bin/identities/trustUntrustList.test.ts index 5fb91633d..4f0816cbe 100644 --- a/tests/bin/identities/trustUntrustList.test.ts +++ b/tests/bin/identities/trustUntrustList.test.ts @@ -106,248 +106,256 @@ describe('trust/untrust/list', () => { mockedGenerateKeyPair.mockRestore(); mockedGenerateDeterministicKeyPair.mockRestore(); }); - test('trusts and untrusts a gestalt by node, adds it to the gestalt graph, and lists the gestalt with notify permission', async () => { - let exitCode, stdout; - // Add the node to our node graph and authenticate an identity on the - // provider - // This allows us to contact the members of the gestalt we want to trust - await testBinUtils.pkStdio( - [ - 'nodes', - 'add', - nodesUtils.encodeNodeId(nodeId), - nodeHost, - `${nodePort}`, - ], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - const mockedBrowser = jest - .spyOn(identitiesUtils, 'browser') - .mockImplementation(() => {}); - await testBinUtils.pkStdio( - [ - 'identities', - 'authenticate', - testToken.providerId, - testToken.identityId, - ], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - mockedBrowser.mockRestore(); - // Trust node - this should trigger discovery on the gestalt the node - // belongs to and add it to our gestalt graph - ({ exitCode } = await testBinUtils.pkStdio( - ['identities', 'trust', nodesUtils.encodeNodeId(nodeId)], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - // Since discovery is a background process we need to wait for the - // gestalt to be discovered - await pkAgent.discovery.waitForDrained(); - // Check that gestalt was discovered and permission was set - ({ exitCode, stdout } = await testBinUtils.pkStdio( - ['identities', 'list', '--format', 'json'], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toHaveLength(1); - expect(JSON.parse(stdout)[0]).toEqual({ - permissions: ['notify'], - nodes: [{ id: nodesUtils.encodeNodeId(nodeId) }], - identities: [ + test( + 'trusts and untrusts a gestalt by node, adds it to the gestalt graph, and lists the gestalt with notify permission', + async () => { + let exitCode, stdout; + // Add the node to our node graph and authenticate an identity on the + // provider + // This allows us to contact the members of the gestalt we want to trust + await testBinUtils.pkStdio( + [ + 'nodes', + 'add', + nodesUtils.encodeNodeId(nodeId), + nodeHost, + `${nodePort}`, + ], { - providerId: provider.id, - identityId: identity, + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, }, - ], - }); - // Untrust the gestalt by node - // This should remove the permission, but not the gestalt (from the gestalt - // graph) - ({ exitCode } = await testBinUtils.pkStdio( - ['identities', 'untrust', nodesUtils.encodeNodeId(nodeId)], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - // Check that gestalt still exists but has no permissions - ({ exitCode, stdout } = await testBinUtils.pkStdio( - ['identities', 'list', '--format', 'json'], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toHaveLength(1); - expect(JSON.parse(stdout)[0]).toEqual({ - permissions: null, - nodes: [{ id: nodesUtils.encodeNodeId(nodeId) }], - identities: [ + dataDir, + ); + const mockedBrowser = jest + .spyOn(identitiesUtils, 'browser') + .mockImplementation(() => {}); + await testBinUtils.pkStdio( + [ + 'identities', + 'authenticate', + testToken.providerId, + testToken.identityId, + ], { - providerId: provider.id, - identityId: identity, + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, }, - ], - }); - // Revert side-effects - await pkAgent.gestaltGraph.unsetNode(nodeId); - await pkAgent.gestaltGraph.unsetIdentity(provider.id, identity); - await pkAgent.nodeGraph.unsetNode(nodeId); - await pkAgent.identitiesManager.delToken( - testToken.providerId, - testToken.identityId, - ); - // @ts-ignore - get protected property - pkAgent.discovery.visitedVertices.clear(); - }); - test('trusts and untrusts a gestalt by identity, adds it to the gestalt graph, and lists the gestalt with notify permission', async () => { - let exitCode, stdout; - // Add the node to our node graph and authenticate an identity on the - // provider - // This allows us to contact the members of the gestalt we want to trust - await testBinUtils.pkStdio( - [ - 'nodes', - 'add', - nodesUtils.encodeNodeId(nodeId), - nodeHost, - `${nodePort}`, - ], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - const mockedBrowser = jest - .spyOn(identitiesUtils, 'browser') - .mockImplementation(() => {}); - await testBinUtils.pkStdio( - [ - 'identities', - 'authenticate', + dataDir, + ); + mockedBrowser.mockRestore(); + // Trust node - this should trigger discovery on the gestalt the node + // belongs to and add it to our gestalt graph + ({ exitCode } = await testBinUtils.pkStdio( + ['identities', 'trust', nodesUtils.encodeNodeId(nodeId)], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + // Since discovery is a background process we need to wait for the + // gestalt to be discovered + await pkAgent.discovery.waitForDrained(); + // Check that gestalt was discovered and permission was set + ({ exitCode, stdout } = await testBinUtils.pkStdio( + ['identities', 'list', '--format', 'json'], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toHaveLength(1); + expect(JSON.parse(stdout)[0]).toEqual({ + permissions: ['notify'], + nodes: [{ id: nodesUtils.encodeNodeId(nodeId) }], + identities: [ + { + providerId: provider.id, + identityId: identity, + }, + ], + }); + // Untrust the gestalt by node + // This should remove the permission, but not the gestalt (from the gestalt + // graph) + ({ exitCode } = await testBinUtils.pkStdio( + ['identities', 'untrust', nodesUtils.encodeNodeId(nodeId)], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + // Check that gestalt still exists but has no permissions + ({ exitCode, stdout } = await testBinUtils.pkStdio( + ['identities', 'list', '--format', 'json'], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toHaveLength(1); + expect(JSON.parse(stdout)[0]).toEqual({ + permissions: null, + nodes: [{ id: nodesUtils.encodeNodeId(nodeId) }], + identities: [ + { + providerId: provider.id, + identityId: identity, + }, + ], + }); + // Revert side-effects + await pkAgent.gestaltGraph.unsetNode(nodeId); + await pkAgent.gestaltGraph.unsetIdentity(provider.id, identity); + await pkAgent.nodeGraph.unsetNode(nodeId); + await pkAgent.identitiesManager.delToken( testToken.providerId, testToken.identityId, - ], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - mockedBrowser.mockRestore(); - // Trust identity - this should trigger discovery on the gestalt the node - // belongs to and add it to our gestalt graph - // This command should fail first time as we need to allow time for the - // identity to be linked to a node in the node graph - ({ exitCode } = await testBinUtils.pkStdio( - ['identities', 'trust', providerString], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(sysexits.NOUSER); - // Since discovery is a background process we need to wait for the - // gestalt to be discovered - await pkAgent.discovery.waitForDrained(); - // This time the command should succeed - ({ exitCode } = await testBinUtils.pkStdio( - ['identities', 'trust', providerString], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - // Check that gestalt was discovered and permission was set - ({ exitCode, stdout } = await testBinUtils.pkStdio( - ['identities', 'list', '--format', 'json'], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toHaveLength(1); - expect(JSON.parse(stdout)[0]).toEqual({ - permissions: ['notify'], - nodes: [{ id: nodesUtils.encodeNodeId(nodeId) }], - identities: [ + ); + // @ts-ignore - get protected property + pkAgent.discovery.visitedVertices.clear(); + }, + global.defaultTimeout * 2, + ); + test( + 'trusts and untrusts a gestalt by identity, adds it to the gestalt graph, and lists the gestalt with notify permission', + async () => { + let exitCode, stdout; + // Add the node to our node graph and authenticate an identity on the + // provider + // This allows us to contact the members of the gestalt we want to trust + await testBinUtils.pkStdio( + [ + 'nodes', + 'add', + nodesUtils.encodeNodeId(nodeId), + nodeHost, + `${nodePort}`, + ], { - providerId: provider.id, - identityId: identity, + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, }, - ], - }); - // Untrust the gestalt by node - // This should remove the permission, but not the gestalt (from the gestalt - // graph) - ({ exitCode } = await testBinUtils.pkStdio( - ['identities', 'untrust', providerString], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - // Check that gestalt still exists but has no permissions - ({ exitCode, stdout } = await testBinUtils.pkStdio( - ['identities', 'list', '--format', 'json'], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toHaveLength(1); - expect(JSON.parse(stdout)[0]).toEqual({ - permissions: null, - nodes: [{ id: nodesUtils.encodeNodeId(nodeId) }], - identities: [ + dataDir, + ); + const mockedBrowser = jest + .spyOn(identitiesUtils, 'browser') + .mockImplementation(() => {}); + await testBinUtils.pkStdio( + [ + 'identities', + 'authenticate', + testToken.providerId, + testToken.identityId, + ], { - providerId: provider.id, - identityId: identity, + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, }, - ], - }); - // Revert side-effects - await pkAgent.gestaltGraph.unsetNode(nodeId); - await pkAgent.gestaltGraph.unsetIdentity(provider.id, identity); - await pkAgent.nodeGraph.unsetNode(nodeId); - await pkAgent.identitiesManager.delToken( - testToken.providerId, - testToken.identityId, - ); - // @ts-ignore - get protected property - pkAgent.discovery.visitedVertices.clear(); - }); + dataDir, + ); + mockedBrowser.mockRestore(); + // Trust identity - this should trigger discovery on the gestalt the node + // belongs to and add it to our gestalt graph + // This command should fail first time as we need to allow time for the + // identity to be linked to a node in the node graph + ({ exitCode } = await testBinUtils.pkStdio( + ['identities', 'trust', providerString], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(sysexits.NOUSER); + // Since discovery is a background process we need to wait for the + // gestalt to be discovered + await pkAgent.discovery.waitForDrained(); + // This time the command should succeed + ({ exitCode } = await testBinUtils.pkStdio( + ['identities', 'trust', providerString], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + // Check that gestalt was discovered and permission was set + ({ exitCode, stdout } = await testBinUtils.pkStdio( + ['identities', 'list', '--format', 'json'], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toHaveLength(1); + expect(JSON.parse(stdout)[0]).toEqual({ + permissions: ['notify'], + nodes: [{ id: nodesUtils.encodeNodeId(nodeId) }], + identities: [ + { + providerId: provider.id, + identityId: identity, + }, + ], + }); + // Untrust the gestalt by node + // This should remove the permission, but not the gestalt (from the gestalt + // graph) + ({ exitCode } = await testBinUtils.pkStdio( + ['identities', 'untrust', providerString], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + // Check that gestalt still exists but has no permissions + ({ exitCode, stdout } = await testBinUtils.pkStdio( + ['identities', 'list', '--format', 'json'], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toHaveLength(1); + expect(JSON.parse(stdout)[0]).toEqual({ + permissions: null, + nodes: [{ id: nodesUtils.encodeNodeId(nodeId) }], + identities: [ + { + providerId: provider.id, + identityId: identity, + }, + ], + }); + // Revert side-effects + await pkAgent.gestaltGraph.unsetNode(nodeId); + await pkAgent.gestaltGraph.unsetIdentity(provider.id, identity); + await pkAgent.nodeGraph.unsetNode(nodeId); + await pkAgent.identitiesManager.delToken( + testToken.providerId, + testToken.identityId, + ); + // @ts-ignore - get protected property + pkAgent.discovery.visitedVertices.clear(); + }, + global.defaultTimeout * 2, + ); test('should fail on invalid inputs', async () => { let exitCode; // Trust diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index 7c842724d..ed80ab06a 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -60,7 +60,7 @@ const mockedGenerateDeterministicKeyPair = jest.spyOn( 'generateDeterministicKeyPair', ); -describe(`${NodeConnection.name} test`, () => { +describe('${NodeConnection.name} test', () => { const logger = new Logger(`${NodeConnection.name} test`, LogLevel.WARN, [ new StreamHandler(), ]); @@ -767,6 +767,7 @@ describe(`${NodeConnection.name} test`, () => { await nodeConnection?.destroy(); } }, + global.defaultTimeout * 2, ); test.each(options)( "should call `killSelf and throw if the server %s's during testStreamFail", @@ -839,5 +840,6 @@ describe(`${NodeConnection.name} test`, () => { await nodeConnection?.destroy(); } }, + global.defaultTimeout * 2, ); }); diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index 783de4ef4..e4ed618aa 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -1252,120 +1252,124 @@ describe('VaultManager', () => { await vaultManager?.destroy(); } }); - test('pullVault respects locking', async () => { - // This should respect the VaultManager read lock - // and the VaultInternal write lock - const vaultManager = await VaultManager.createVaultManager({ - vaultsPath, - keyManager: dummyKeyManager, - gestaltGraph: {} as GestaltGraph, - nodeConnectionManager, - acl: {} as ACL, - notificationsManager: {} as NotificationsManager, - db, - logger: logger.getChild(VaultManager.name), - }); - const pullVaultMock = jest.spyOn(VaultInternal.prototype, 'pullVault'); - const gitPullMock = jest.spyOn(git, 'pull'); - try { - // Creating some state at the remote - await remoteKeynode1.vaultManager.withVaults( - [remoteVaultId], - async (vault) => { - await vault.writeF(async (efs) => { - await efs.writeFile('secret-1', 'secret1'); - await efs.writeFile('secret-2', 'secret2'); - }); - }, - ); - - // Setting permissions - await remoteKeynode1.gestaltGraph.setNode({ - id: localNodeIdEncoded, - chain: {}, + test( + 'pullVault respects locking', + async () => { + // This should respect the VaultManager read lock + // and the VaultInternal write lock + const vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + keyManager: dummyKeyManager, + gestaltGraph: {} as GestaltGraph, + nodeConnectionManager, + acl: {} as ACL, + notificationsManager: {} as NotificationsManager, + db, + logger: logger.getChild(VaultManager.name), }); - await remoteKeynode1.gestaltGraph.setGestaltActionByNode( - localNodeId, - 'scan', - ); - await remoteKeynode1.acl.setVaultAction( - remoteVaultId, - localNodeId, - 'clone', - ); - await remoteKeynode1.acl.setVaultAction( - remoteVaultId, - localNodeId, - 'pull', - ); + const pullVaultMock = jest.spyOn(VaultInternal.prototype, 'pullVault'); + const gitPullMock = jest.spyOn(git, 'pull'); + try { + // Creating some state at the remote + await remoteKeynode1.vaultManager.withVaults( + [remoteVaultId], + async (vault) => { + await vault.writeF(async (efs) => { + await efs.writeFile('secret-1', 'secret1'); + await efs.writeFile('secret-2', 'secret2'); + }); + }, + ); - await vaultManager.cloneVault(remoteKeynode1Id, vaultName); - const vaultId = await vaultManager.getVaultId(vaultName); - if (vaultId === undefined) fail('VaultId is not found.'); + // Setting permissions + await remoteKeynode1.gestaltGraph.setNode({ + id: localNodeIdEncoded, + chain: {}, + }); + await remoteKeynode1.gestaltGraph.setGestaltActionByNode( + localNodeId, + 'scan', + ); + await remoteKeynode1.acl.setVaultAction( + remoteVaultId, + localNodeId, + 'clone', + ); + await remoteKeynode1.acl.setVaultAction( + remoteVaultId, + localNodeId, + 'pull', + ); - // Creating new history - await remoteKeynode1.vaultManager.withVaults( - [remoteVaultId], - async (vault) => { - await vault.writeF(async (efs) => { - await efs.writeFile('secret-2', 'secret2'); - }); - }, - ); + await vaultManager.cloneVault(remoteKeynode1Id, vaultName); + const vaultId = await vaultManager.getVaultId(vaultName); + if (vaultId === undefined) fail('VaultId is not found.'); - // @ts-ignore: kidnap vaultManager map and grabbing lock - const vaultsMap = vaultManager.vaultMap; - const vault = vaultsMap.get(vaultId.toString() as VaultIdString); - // @ts-ignore: kidnap vaultManager lockBox - const vaultLocks = vaultManager.vaultLocks; - const [releaseWrite] = await vaultLocks.lock([ - vaultId, - RWLockWriter, - 'write', - ])(); - - // Pulling vault respects VaultManager write lock - const pullP = vaultManager.pullVault({ - vaultId: vaultId, - }); - await sleep(200); - expect(pullVaultMock).not.toHaveBeenCalled(); - await releaseWrite(); - await pullP; - expect(pullVaultMock).toHaveBeenCalled(); - pullVaultMock.mockClear(); + // Creating new history + await remoteKeynode1.vaultManager.withVaults( + [remoteVaultId], + async (vault) => { + await vault.writeF(async (efs) => { + await efs.writeFile('secret-2', 'secret2'); + }); + }, + ); - // Creating new history - await remoteKeynode1.vaultManager.withVaults( - [remoteVaultId], - async (vault) => { - await vault.writeF(async (efs) => { - await efs.writeFile('secret-3', 'secret3'); - }); - }, - ); + // @ts-ignore: kidnap vaultManager map and grabbing lock + const vaultsMap = vaultManager.vaultMap; + const vault = vaultsMap.get(vaultId.toString() as VaultIdString); + // @ts-ignore: kidnap vaultManager lockBox + const vaultLocks = vaultManager.vaultLocks; + const [releaseWrite] = await vaultLocks.lock([ + vaultId, + RWLockWriter, + 'write', + ])(); + + // Pulling vault respects VaultManager write lock + const pullP = vaultManager.pullVault({ + vaultId: vaultId, + }); + await sleep(200); + expect(pullVaultMock).not.toHaveBeenCalled(); + await releaseWrite(); + await pullP; + expect(pullVaultMock).toHaveBeenCalled(); + pullVaultMock.mockClear(); + + // Creating new history + await remoteKeynode1.vaultManager.withVaults( + [remoteVaultId], + async (vault) => { + await vault.writeF(async (efs) => { + await efs.writeFile('secret-3', 'secret3'); + }); + }, + ); - // Respects VaultInternal write lock - // @ts-ignore: kidnap vault lock - const vaultLock = vault!.lock; - const [releaseVaultWrite] = await vaultLock.write()(); - // Pulling vault respects VaultManager write lock - gitPullMock.mockClear(); - const pullP2 = vaultManager.pullVault({ - vaultId: vaultId, - }); - await sleep(200); - expect(gitPullMock).not.toHaveBeenCalled(); - await releaseVaultWrite(); - await pullP2; - expect(gitPullMock).toHaveBeenCalled(); - } finally { - pullVaultMock.mockRestore(); - gitPullMock.mockRestore(); - await vaultManager?.stop(); - await vaultManager?.destroy(); - } - }); + // Respects VaultInternal write lock + // @ts-ignore: kidnap vault lock + const vaultLock = vault!.lock; + const [releaseVaultWrite] = await vaultLock.write()(); + // Pulling vault respects VaultManager write lock + gitPullMock.mockClear(); + const pullP2 = vaultManager.pullVault({ + vaultId: vaultId, + }); + await sleep(200); + expect(gitPullMock).not.toHaveBeenCalled(); + await releaseVaultWrite(); + await pullP2; + expect(gitPullMock).toHaveBeenCalled(); + } finally { + pullVaultMock.mockRestore(); + gitPullMock.mockRestore(); + await vaultManager?.stop(); + await vaultManager?.destroy(); + } + }, + global.failedConnectionTimeout, + ); }); test('handleScanVaults should list all vaults with permissions', async () => { // 1. we need to set up state From 52755eca270a857ecbe0d6d162dc8322d13e3ea1 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 27 May 2022 15:09:36 +1000 Subject: [PATCH 056/137] feat: updating `@matrixai/db` to `^4.0.1` Had to fix the usage in 5 domains. --- package-lock.json | 60 ++++++----------------- package.json | 2 +- src/acl/ACL.ts | 14 +++--- src/discovery/Discovery.ts | 17 ++++--- src/nodes/NodeGraph.ts | 13 ++--- src/notifications/NotificationsManager.ts | 8 +-- src/sigchain/Sigchain.ts | 30 +++++++----- 7 files changed, 61 insertions(+), 83 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3a8a23a79..fdd71bd6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@grpc/grpc-js": "1.6.7", "@matrixai/async-init": "^1.7.3", "@matrixai/async-locks": "^2.2.4", - "@matrixai/db": "^3.3.3", + "@matrixai/db": "^4.0.1", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", "@matrixai/logger": "^2.1.1", @@ -2357,9 +2357,9 @@ } }, "node_modules/@matrixai/db": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.3.4.tgz", - "integrity": "sha512-iRuwT+jbCZ4om5tbiUvaoYTRBfA6soULYmyqV0n2Av7gayiRhP7e0tEcxI3VFue4xuO1KPCsZjSTwcFXesHP0g==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-4.0.5.tgz", + "integrity": "sha512-X3gBcyPxC+bTEfi1J1Y49n1bglvg7HjM8MKNH5s+OUEswqKSZgeg1uWfXqvUqq72yjBtgRi4Ghmy4MdrIB1oMw==", "dependencies": { "@matrixai/async-init": "^1.7.3", "@matrixai/errors": "^1.1.1", @@ -4216,21 +4216,6 @@ "util-callbackify": "^1.0.0" } }, - "node_modules/encryptedfs/node_modules/@matrixai/db": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-4.0.5.tgz", - "integrity": "sha512-X3gBcyPxC+bTEfi1J1Y49n1bglvg7HjM8MKNH5s+OUEswqKSZgeg1uWfXqvUqq72yjBtgRi4Ghmy4MdrIB1oMw==", - "dependencies": { - "@matrixai/async-init": "^1.7.3", - "@matrixai/errors": "^1.1.1", - "@matrixai/logger": "^2.1.1", - "@matrixai/resources": "^1.1.3", - "@matrixai/workers": "^1.3.3", - "@types/abstract-leveldown": "^7.2.0", - "level": "7.0.1", - "threads": "^1.6.5" - } - }, "node_modules/encryptedfs/node_modules/node-forge": { "version": "1.3.1", "license": "(BSD-3-Clause OR GPL-2.0)", @@ -10241,9 +10226,9 @@ } }, "node_modules/typescript-cached-transpile/node_modules/@types/node": { - "version": "12.20.52", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.52.tgz", - "integrity": "sha512-cfkwWw72849SNYp3Zx0IcIs25vABmFh73xicxhCkTcvtZQeIez15PpwQN8fY3RD7gv1Wrxlc9MEtfMORZDEsGw==", + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", "dev": true }, "node_modules/typescript-cached-transpile/node_modules/fs-extra": { @@ -10263,7 +10248,7 @@ "node_modules/typescript-cached-transpile/node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "optionalDependencies": { "graceful-fs": "^4.1.6" @@ -12155,9 +12140,9 @@ } }, "@matrixai/db": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-3.3.4.tgz", - "integrity": "sha512-iRuwT+jbCZ4om5tbiUvaoYTRBfA6soULYmyqV0n2Av7gayiRhP7e0tEcxI3VFue4xuO1KPCsZjSTwcFXesHP0g==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-4.0.5.tgz", + "integrity": "sha512-X3gBcyPxC+bTEfi1J1Y49n1bglvg7HjM8MKNH5s+OUEswqKSZgeg1uWfXqvUqq72yjBtgRi4Ghmy4MdrIB1oMw==", "requires": { "@matrixai/async-init": "^1.7.3", "@matrixai/errors": "^1.1.1", @@ -13376,21 +13361,6 @@ "util-callbackify": "^1.0.0" }, "dependencies": { - "@matrixai/db": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@matrixai/db/-/db-4.0.5.tgz", - "integrity": "sha512-X3gBcyPxC+bTEfi1J1Y49n1bglvg7HjM8MKNH5s+OUEswqKSZgeg1uWfXqvUqq72yjBtgRi4Ghmy4MdrIB1oMw==", - "requires": { - "@matrixai/async-init": "^1.7.3", - "@matrixai/errors": "^1.1.1", - "@matrixai/logger": "^2.1.1", - "@matrixai/resources": "^1.1.3", - "@matrixai/workers": "^1.3.3", - "@types/abstract-leveldown": "^7.2.0", - "level": "7.0.1", - "threads": "^1.6.5" - } - }, "node-forge": { "version": "1.3.1" } @@ -17154,9 +17124,9 @@ }, "dependencies": { "@types/node": { - "version": "12.20.52", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.52.tgz", - "integrity": "sha512-cfkwWw72849SNYp3Zx0IcIs25vABmFh73xicxhCkTcvtZQeIez15PpwQN8fY3RD7gv1Wrxlc9MEtfMORZDEsGw==", + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", "dev": true }, "fs-extra": { @@ -17173,7 +17143,7 @@ "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "requires": { "graceful-fs": "^4.1.6" diff --git a/package.json b/package.json index 9909dbe4d..bed43797e 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "@grpc/grpc-js": "1.6.7", "@matrixai/async-init": "^1.7.3", "@matrixai/async-locks": "^2.2.4", - "@matrixai/db": "^3.3.3", + "@matrixai/db": "^4.0.1", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", "@matrixai/logger": "^2.1.1", diff --git a/src/acl/ACL.ts b/src/acl/ACL.ts index e97dc6c30..caa308f13 100644 --- a/src/acl/ACL.ts +++ b/src/acl/ACL.ts @@ -135,11 +135,12 @@ class ACL { return this.withTransactionF(async (tran) => this.getNodePerms(tran)); } const permIds: Record> = {}; - for await (const [k, v] of tran.iterator(undefined, [ + for await (const [keyPath, value] of tran.iterator(undefined, [ ...this.aclNodesDbPath, ])) { - const nodeId = IdInternal.fromBuffer(k); - const permId = IdInternal.fromBuffer(v); + const key = keyPath[0] as Buffer; + const nodeId = IdInternal.fromBuffer(key); + const permId = IdInternal.fromBuffer(value); let nodePerm: Record; if (permId in permIds) { nodePerm = permIds[permId]; @@ -175,11 +176,12 @@ class ACL { return this.withTransactionF(async (tran) => this.getVaultPerms(tran)); } const vaultPerms: Record> = {}; - for await (const [k, v] of tran.iterator(undefined, [ + for await (const [keyPath, value] of tran.iterator(undefined, [ ...this.aclVaultsDbPath, ])) { - const vaultId = IdInternal.fromBuffer(k); - const nodeIds = dbUtils.deserialize>(v); + const key = keyPath[0] as Buffer; + const vaultId = IdInternal.fromBuffer(key); + const nodeIds = dbUtils.deserialize>(value); const nodePerm: Record = {}; const nodeIdsGc: Set = new Set(); for (const nodeIdString in nodeIds) { diff --git a/src/discovery/Discovery.ts b/src/discovery/Discovery.ts index 53026b098..576ecf29f 100644 --- a/src/discovery/Discovery.ts +++ b/src/discovery/Discovery.ts @@ -26,7 +26,7 @@ import { import { IdInternal } from '@matrixai/id'; import { Lock } from '@matrixai/async-locks'; import * as idUtils from '@matrixai/id/dist/utils'; -import { utils as DBUtils } from '@matrixai/db'; +import { utils as dbUtils } from '@matrixai/db'; import * as resources from '@matrixai/resources'; import * as discoveryUtils from './utils'; import * as discoveryErrors from './errors'; @@ -134,7 +134,8 @@ class Discovery { { limit: 1, reverse: true, values: false }, this.discoveryQueueDbPath, ); - for await (const [key] of keyIterator) { + for await (const [keyPath] of keyIterator) { + const key = keyPath[0] as Buffer; latestId = IdInternal.fromBuffer(key); } this.discoveryQueueIdGenerator = @@ -202,12 +203,13 @@ class Discovery { // Processing queue this.logger.debug('DiscoveryQueue is processing'); - for await (const [key, value] of this.db.iterator( + for await (const [keyPath, value] of this.db.iterator( {}, this.discoveryQueueDbPath, )) { - const vertexId = IdInternal.fromBuffer(key) as DiscoveryQueueId; - const vertex = DBUtils.deserialize(value); + const key = keyPath[0] as Buffer; + const vertexId = IdInternal.fromBuffer(key); + const vertex = dbUtils.deserialize(value); this.logger.debug(`Processing vertex: ${vertex}`); const vertexGId = gestaltsUtils.ungestaltKey(vertex); switch (vertexGId.type) { @@ -424,10 +426,11 @@ class Discovery { return await this.lock.withF(async () => { let nextDiscoveryQueueId: DiscoveryQueueId | undefined; const keyIterator = this.db.iterator( - { limit: 1 }, + { limit: 1, values: false }, this.discoveryQueueDbPath, ); - for await (const [key] of keyIterator) { + for await (const [keyPath] of keyIterator) { + const key = keyPath[0] as Buffer; nextDiscoveryQueueId = IdInternal.fromBuffer(key); } return nextDiscoveryQueueId == null; diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index ddf2ff7b3..31cc5d130 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -1,7 +1,8 @@ import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; -import type { NodeId, NodeAddress, NodeBucket } from './types'; +import type { NodeAddress, NodeBucket, NodeId } from './types'; import type KeyManager from '../keys/KeyManager'; import type { Host, Hostname, Port } from '../network/types'; +import { utils as dbUtils } from '@matrixai/db'; import lexi from 'lexicographic-integer'; import Logger from '@matrixai/logger'; import { @@ -9,7 +10,6 @@ import { ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { IdInternal } from '@matrixai/id'; -import { utils as dbUtils } from '@matrixai/db'; import { withF } from '@matrixai/resources'; import * as nodesUtils from './utils'; import * as nodesErrors from './errors'; @@ -335,14 +335,11 @@ class NodeGraph { // Wrap as a batch operation. We want to rollback if we encounter any // errors (such that we don't clear the DB without re-adding the nodes) // 1. Delete every bucket - for await (const [k] of tran.iterator({ value: false }, [ + for await (const [keyPath] of tran.iterator({ values: false }, [ ...this.nodeGraphBucketsDbPath, ])) { - const hexBucketIndex = k.toString(); - const hexBucketPath = [ - ...this.nodeGraphBucketsDbPath, - hexBucketIndex, - ] as unknown as KeyPath; + const key = keyPath[0].toString(); + const hexBucketPath = [...this.nodeGraphBucketsDbPath, key]; await tran.del(hexBucketPath); } const tempBuckets: Record = {}; diff --git a/src/notifications/NotificationsManager.ts b/src/notifications/NotificationsManager.ts index dce39dd16..58b6fc42c 100644 --- a/src/notifications/NotificationsManager.ts +++ b/src/notifications/NotificationsManager.ts @@ -140,10 +140,11 @@ class NotificationsManager { // Getting latest ID and creating ID generator let latestId: NotificationId | undefined; const keyIterator = tran.iterator( - { limit: 1, reverse: true }, + { limit: 1, reverse: true, values: false }, this.notificationsMessagesDbPath, ); - for await (const [key] of keyIterator) { + for await (const [keyPath] of keyIterator) { + const key = keyPath[0] as Buffer; latestId = IdInternal.fromBuffer(key); } this.notificationIdGenerator = @@ -367,7 +368,8 @@ class NotificationsManager { ): Promise> { const notificationIds: Array = []; const messageIterator = tran.iterator({}, this.notificationsMessagesDbPath); - for await (const [key, value] of messageIterator) { + for await (const [keyPath, value] of messageIterator) { + const key = keyPath[0] as Buffer; const notificationId = IdInternal.fromBuffer(key); const notification = JSON.parse(value.toString()) as Notification; if (type === 'all') { diff --git a/src/sigchain/Sigchain.ts b/src/sigchain/Sigchain.ts index 25614e490..a2a1f0af4 100644 --- a/src/sigchain/Sigchain.ts +++ b/src/sigchain/Sigchain.ts @@ -10,13 +10,13 @@ import type { } from '../claims/types'; import type KeyManager from '../keys/KeyManager'; import type { NodeIdEncoded } from '../nodes/types'; +import { utils as dbUtils } from '@matrixai/db'; import Logger from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; -import { utils as dbUtils } from '@matrixai/db'; import { Lock, LockBox } from '@matrixai/async-locks'; import { withF } from '@matrixai/resources'; import * as sigchainErrors from './errors'; @@ -269,11 +269,10 @@ class Sigchain { seq: (await this.getSequenceNumber(tran)) + 1, data: claimData, }); - const intermediaryClaim: ClaimIntermediary = { + return { payload: claim.payload, signature: claim.signatures[0], }; - return intermediaryClaim; } /** @@ -289,10 +288,11 @@ class Sigchain { } const chainData: ChainDataEncoded = {}; const readIterator = tran.iterator({}, [...this.sigchainClaimsDbPath]); - for await (const [key, value] of readIterator) { + for await (const [keyPath, value] of readIterator) { + const key = keyPath[0] as Buffer; const claimId = IdInternal.fromBuffer(key); - const claim = dbUtils.deserialize(value); - chainData[claimsUtils.encodeClaimId(claimId)] = claim; + chainData[claimsUtils.encodeClaimId(claimId)] = + dbUtils.deserialize(value); } return chainData; } @@ -399,9 +399,12 @@ class Sigchain { return this.withTransactionF(async (tran) => this.getSeqMap(tran)); } const map: Record = {}; - const claimStream = tran.iterator({}, [...this.sigchainClaimsDbPath]); + const claimStream = tran.iterator({ values: false }, [ + ...this.sigchainClaimsDbPath, + ]); let seq = 1; - for await (const [key] of claimStream) { + for await (const [keyPath] of claimStream) { + const key = keyPath[0] as Buffer; map[seq] = IdInternal.fromBuffer(key); seq++; } @@ -412,11 +415,12 @@ class Sigchain { tran: DBTransaction, ): Promise { let latestId: ClaimId | undefined; - const keyStream = tran.iterator({ limit: 1, reverse: true }, [ - ...this.sigchainClaimsDbPath, - ]); - for await (const [key] of keyStream) { - latestId = IdInternal.fromBuffer(key); + const keyStream = tran.iterator( + { limit: 1, reverse: true, values: false }, + [...this.sigchainClaimsDbPath], + ); + for await (const [keyPath] of keyStream) { + latestId = IdInternal.fromBuffer(keyPath[0] as Buffer); } return latestId; } From d88278c13dedf91fef077783ad720a226667c786 Mon Sep 17 00:00:00 2001 From: Roger Qiu Date: Wed, 25 May 2022 16:51:02 +1000 Subject: [PATCH 057/137] tests: general clean up for proxy tests --- tests/network/Proxy.test.ts | 311 +++++++++++++++--------------------- tests/network/utils.test.ts | 4 +- 2 files changed, 134 insertions(+), 181 deletions(-) diff --git a/tests/network/Proxy.test.ts b/tests/network/Proxy.test.ts index b418d6544..b9a7d6e50 100644 --- a/tests/network/Proxy.test.ts +++ b/tests/network/Proxy.test.ts @@ -6,12 +6,12 @@ import http from 'http'; import tls from 'tls'; import UTP from 'utp-native'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import { poll, promise, promisify, timerStart, timerStop } from '@/utils'; import Proxy from '@/network/Proxy'; import * as networkUtils from '@/network/utils'; import * as networkErrors from '@/network/errors'; import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; +import { promisify, promise, timerStart, timerStop, poll } from '@/utils'; import * as testUtils from '../utils'; /** @@ -107,7 +107,7 @@ function tcpServer(end: boolean = false) { describe(Proxy.name, () => { const localHost = '127.0.0.1' as Host; const port = 0 as Port; - const logger = new Logger(`${Proxy.name} test`, LogLevel.DEBUG, [ + const logger = new Logger(`${Proxy.name} test`, LogLevel.WARN, [ new StreamHandler(), ]); const nodeIdABC = testUtils.generateRandomNodeId(); @@ -249,7 +249,7 @@ describe(Proxy.name, () => { }); // Cannot open connection to port 0 await expect(() => - proxy.openConnectionForward(nodeIdABC, '127.0.0.1' as Host, 0 as Port), + proxy.openConnectionForward(nodeIdABC, localHost, 0 as Port), ).rejects.toThrow(networkErrors.ErrorConnectionStart); await expect(() => httpConnect( @@ -282,35 +282,35 @@ describe(Proxy.name, () => { serverPort: port, }); // This UTP server will just hang and not respond - let recievedCount = 0; + let receivedCount = 0; const utpSocketHang = UTP.createServer(() => { - recievedCount++; + receivedCount++; }); const utpSocketHangListen = promisify(utpSocketHang.listen).bind( utpSocketHang, ); - await utpSocketHangListen(0, '127.0.0.1'); + await utpSocketHangListen(0, localHost); const utpSocketHangPort = utpSocketHang.address().port; await expect(() => proxy.openConnectionForward( nodeIdABC, - '127.0.0.1' as Host, + localHost, utpSocketHangPort as Port, ), ).rejects.toThrow(networkErrors.ErrorConnectionStartTimeout); - expect(recievedCount).toBe(1); + expect(receivedCount).toBe(1); // Can override the timer const timer = timerStart(2000); await expect(() => proxy.openConnectionForward( nodeIdABC, - '127.0.0.1' as Host, + localHost, utpSocketHangPort as Port, timer, ), ).rejects.toThrow(networkErrors.ErrorConnectionStartTimeout); timerStop(timer); - expect(recievedCount).toBe(2); + expect(receivedCount).toBe(2); await expect(() => httpConnect( proxy.getForwardHost(), @@ -321,7 +321,7 @@ describe(Proxy.name, () => { )}`, ), ).rejects.toThrow('504'); - expect(recievedCount).toBe(3); + expect(receivedCount).toBe(3); utpSocketHang.close(); utpSocketHang.unref(); await proxy.stop(); @@ -341,34 +341,34 @@ describe(Proxy.name, () => { }); // This UTP Server will immediately end and destroy // the connection upon receiving a connection - let recievedCount = 0; + let receivedCount = 0; const utpSocketEnd = UTP.createServer((utpConn) => { - recievedCount++; + receivedCount++; utpConn.end(); utpConn.destroy(); }); const utpSocketEndListen = promisify(utpSocketEnd.listen).bind( utpSocketEnd, ); - await utpSocketEndListen(0, '127.0.0.1'); + await utpSocketEndListen(0, localHost); const utpSocketEndPort = utpSocketEnd.address().port; await expect(() => proxy.openConnectionForward( nodeIdABC, - '127.0.0.1' as Host, + localHost, utpSocketEndPort as Port, ), ).rejects.toThrow(networkErrors.ErrorConnectionStart); - expect(recievedCount).toBe(1); + expect(receivedCount).toBe(1); // The actual error is UTP_ECONNRESET to be precise await expect(() => proxy.openConnectionForward( nodeIdABC, - '127.0.0.1' as Host, + localHost, utpSocketEndPort as Port, ), ).rejects.toThrow(/UTP_ECONNRESET/); - expect(recievedCount).toBe(2); + expect(receivedCount).toBe(2); // 502 Bad Gateway on HTTP Connect await expect(() => httpConnect( @@ -380,7 +380,7 @@ describe(Proxy.name, () => { )}`, ), ).rejects.toThrow('502'); - expect(recievedCount).toBe(3); + expect(receivedCount).toBe(3); utpSocketEnd.close(); utpSocketEnd.unref(); await proxy.stop(); @@ -460,7 +460,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -473,19 +473,19 @@ describe(Proxy.name, () => { ), ).rejects.toThrow(networkErrors.ErrorConnectionStart); await expect(remoteClosedP).resolves.toBeUndefined(); - expect(utpConnError.mock.calls.length).toBe(0); + expect(utpConnError).toHaveBeenCalledTimes(0); // The TLS socket throw an error because there's no suitable signature algorithm - expect(tlsSocketError.mock.calls.length).toBe(1); + expect(tlsSocketError).toHaveBeenCalledTimes(1); // Expect(tlsSocketError.mock.calls[0][0]).toBeInstanceOf(Error); expect(tlsSocketError.mock.calls[0][0]).toHaveProperty( 'code', 'ERR_SSL_NO_SUITABLE_SIGNATURE_ALGORITHM', ); // The TLS socket end event never was emitted - expect(tlsSocketEnd.mock.calls.length).toBe(0); + expect(tlsSocketEnd).toHaveBeenCalledTimes(0); // The TLS socket close event is emitted with error - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(true); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(true); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -566,7 +566,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -582,19 +582,19 @@ describe(Proxy.name, () => { ), ).rejects.toThrow('502'); await expect(remoteClosedP).resolves.toBeUndefined(); - expect(utpConnError.mock.calls.length).toBe(0); + expect(utpConnError).toHaveBeenCalledTimes(0); // The TLS socket throw an error because there's no suitable signature algorithm - expect(tlsSocketError.mock.calls.length).toBe(1); + expect(tlsSocketError).toHaveBeenCalledTimes(1); // Expect(tlsSocketError.mock.calls[0][0]).toBeInstanceOf(Error); expect(tlsSocketError.mock.calls[0][0]).toHaveProperty( 'code', 'ERR_SSL_NO_SUITABLE_SIGNATURE_ALGORITHM', ); // The TLS socket end event never was emitted - expect(tlsSocketEnd.mock.calls.length).toBe(0); + expect(tlsSocketEnd).toHaveBeenCalledTimes(0); // The TLS socket close event is emitted with error - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(true); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(true); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -687,7 +687,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -702,15 +702,15 @@ describe(Proxy.name, () => { expect(secured).toBe(true); expect(proxy.getConnectionForwardCount()).toBe(0); await expect(remoteClosedP).resolves.toBeUndefined(); - expect(utpConnError.mock.calls.length).toBe(0); + expect(utpConnError).toHaveBeenCalledTimes(0); // No TLS socket errors this time - // The client side figured that the node id is incorect - expect(tlsSocketError.mock.calls.length).toBe(0); + // The client side figured that the node id is incorrect + expect(tlsSocketError).toHaveBeenCalledTimes(0); // This time the tls socket is ended from the client side - expect(tlsSocketEnd.mock.calls.length).toBe(1); + expect(tlsSocketEnd).toHaveBeenCalledTimes(1); // The TLS socket close event is emitted without error - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(false); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(false); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -803,7 +803,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -821,15 +821,15 @@ describe(Proxy.name, () => { expect(secured).toBe(true); expect(proxy.getConnectionForwardCount()).toBe(0); await expect(remoteClosedP).resolves.toBeUndefined(); - expect(utpConnError.mock.calls.length).toBe(0); + expect(utpConnError).toHaveBeenCalledTimes(0); // No TLS socket errors this time - // The client side figured taht the node id is incorect - expect(tlsSocketError.mock.calls.length).toBe(0); + // The client side figured that the node id is incorrect + expect(tlsSocketError).toHaveBeenCalledTimes(0); // This time the tls socket is ended from the client side - expect(tlsSocketEnd.mock.calls.length).toBe(1); + expect(tlsSocketEnd).toHaveBeenCalledTimes(1); // The TLS socket close event is emitted without error - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(false); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(false); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -927,7 +927,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -951,11 +951,11 @@ describe(Proxy.name, () => { ); expect(proxy.getConnectionForwardCount()).toBe(0); await expect(remoteClosedP).resolves.toBeUndefined(); - expect(utpConnError.mock.calls.length).toBe(0); - expect(tlsSocketError.mock.calls.length).toBe(0); - expect(tlsSocketEnd.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(false); + expect(utpConnError).toHaveBeenCalledTimes(0); + expect(tlsSocketError).toHaveBeenCalledTimes(0); + expect(tlsSocketEnd).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(false); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -1057,7 +1057,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -1082,7 +1082,7 @@ describe(Proxy.name, () => { tlsSocket_!.once('end', resolveEndP); tlsSocket_!.end(); await endP; - // Force destroy the socket due to buggy tlsSocket and utpConn + // Force destroys the socket due to buggy tlsSocket and utpConn tlsSocket_!.destroy(); logger.debug('Reverse: finishes tlsSocket ending'); await expect(remoteClosedP).resolves.toBeUndefined(); @@ -1093,19 +1093,18 @@ describe(Proxy.name, () => { return proxy.getConnectionForwardCount(); }, (_, result) => { - if (result === 0) return true; - return false; + return result === 0; }, 100, ), ).resolves.toBe(0); - expect(utpConnError.mock.calls.length).toBe(0); - expect(tlsSocketError.mock.calls.length).toBe(0); + expect(utpConnError).toHaveBeenCalledTimes(0); + expect(tlsSocketError).toHaveBeenCalledTimes(0); // This time the reverse side initiates the end // Therefore, this handler is removed - expect(tlsSocketEnd.mock.calls.length).toBe(0); - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(false); + expect(tlsSocketEnd).toHaveBeenCalledTimes(0); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(false); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -1204,7 +1203,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -1247,14 +1246,14 @@ describe(Proxy.name, () => { utpSocketPort as Port, ); expect(proxy.getConnectionForwardCount()).toBe(0); - expect(clientSocketEnd.mock.calls.length).toBe(1); + expect(clientSocketEnd).toHaveBeenCalledTimes(1); await expect(localClosedP).resolves.toBeUndefined(); await expect(remoteClosedP).resolves.toBeUndefined(); - expect(utpConnError.mock.calls.length).toBe(0); - expect(tlsSocketError.mock.calls.length).toBe(0); - expect(tlsSocketEnd.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(false); + expect(utpConnError).toHaveBeenCalledTimes(0); + expect(tlsSocketError).toHaveBeenCalledTimes(0); + expect(tlsSocketEnd).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(false); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -1356,7 +1355,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -1401,11 +1400,11 @@ describe(Proxy.name, () => { tlsSocket_!.once('end', resolveEndP); tlsSocket_!.end(); await endP; - // Force destroy the socket due to buggy tlsSocket and utpConn + // Force destroys the socket due to buggy tlsSocket and utpConn tlsSocket_!.destroy(); logger.debug('Reverse: finishes tlsSocket ending'); await expect(localClosedP).resolves.toBeUndefined(); - expect(clientSocketEnd.mock.calls.length).toBe(1); + expect(clientSocketEnd).toHaveBeenCalledTimes(1); await expect(remoteClosedP).resolves.toBeUndefined(); // Connection count should reach 0 eventually await expect( @@ -1414,19 +1413,18 @@ describe(Proxy.name, () => { return proxy.getConnectionForwardCount(); }, (_, result) => { - if (result === 0) return true; - return false; + return result === 0; }, 100, ), ).resolves.toBe(0); - expect(utpConnError.mock.calls.length).toBe(0); - expect(tlsSocketError.mock.calls.length).toBe(0); + expect(utpConnError).toHaveBeenCalledTimes(0); + expect(tlsSocketError).toHaveBeenCalledTimes(0); // This time the reverse side initiates the end // Therefore, this handler is removed - expect(tlsSocketEnd.mock.calls.length).toBe(0); - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(false); + expect(tlsSocketEnd).toHaveBeenCalledTimes(0); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(false); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -1525,7 +1523,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -1554,7 +1552,7 @@ describe(Proxy.name, () => { ); expect(proxy.getConnectionForwardCount()).toBe(1); const { p: endP, resolveP: resolveEndP } = promise(); - // By default net sockets have `allowHalfOpen: false` + // By default, net sockets have `allowHalfOpen: false` // Here we override the behaviour by removing the end listener // And replacing it with our own, and remember to also force destroy clientSocket.removeAllListeners('end'); @@ -1575,17 +1573,16 @@ describe(Proxy.name, () => { return proxy.getConnectionForwardCount(); }, (_, result) => { - if (result === 0) return true; - return false; + return result === 0; }, 100, ), ).resolves.toBe(0); - expect(utpConnError.mock.calls.length).toBe(0); - expect(tlsSocketError.mock.calls.length).toBe(0); - expect(tlsSocketEnd.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(false); + expect(utpConnError).toHaveBeenCalledTimes(0); + expect(tlsSocketError).toHaveBeenCalledTimes(0); + expect(tlsSocketEnd).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(false); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -1681,7 +1678,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; await proxy.openConnectionForward( @@ -1712,11 +1709,11 @@ describe(Proxy.name, () => { ); await expect(localClosedP).resolves.toBeUndefined(); await expect(remoteClosedP).resolves.toBeUndefined(); - expect(utpConnError.mock.calls.length).toBe(0); - expect(tlsSocketError.mock.calls.length).toBe(0); - expect(tlsSocketEnd.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(false); + expect(utpConnError).toHaveBeenCalledTimes(0); + expect(tlsSocketError).toHaveBeenCalledTimes(0); + expect(tlsSocketEnd).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(false); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -1814,7 +1811,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -1829,11 +1826,11 @@ describe(Proxy.name, () => { // When ErrorConnectionTimeout is triggered // This results in the destruction of the socket await expect(remoteClosedP).resolves.toBeUndefined(); - expect(utpConnError.mock.calls.length).toBe(0); - expect(tlsSocketError.mock.calls.length).toBe(0); - expect(tlsSocketEnd.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(false); + expect(utpConnError).toHaveBeenCalledTimes(0); + expect(tlsSocketError).toHaveBeenCalledTimes(0); + expect(tlsSocketEnd).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(false); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -1932,7 +1929,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -1965,17 +1962,16 @@ describe(Proxy.name, () => { return proxy.getConnectionForwardCount(); }, (_, result) => { - if (result === 0) return true; - return false; + return result === 0; }, 100, ), ).resolves.toBe(0); - expect(utpConnError.mock.calls.length).toBe(0); - expect(tlsSocketError.mock.calls.length).toBe(0); - expect(tlsSocketEnd.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls.length).toBe(1); - expect(tlsSocketClose.mock.calls[0][0]).toBe(false); + expect(utpConnError).toHaveBeenCalledTimes(0); + expect(tlsSocketError).toHaveBeenCalledTimes(0); + expect(tlsSocketEnd).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledTimes(1); + expect(tlsSocketClose).toHaveBeenCalledWith(false); utpSocket.off('message', handleMessage); utpSocket.close(); utpSocket.unref(); @@ -2057,7 +2053,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen = promisify(utpSocket.listen).bind(utpSocket); - await utpSocketListen(0, '127.0.0.1'); + await utpSocketListen(0, localHost); const utpSocketHost = utpSocket.address().address; const utpSocketPort = utpSocket.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -2163,7 +2159,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen1 = promisify(utpSocket1.listen).bind(utpSocket1); - await utpSocketListen1(0, '127.0.0.1'); + await utpSocketListen1(0, localHost); const utpSocketHost1 = utpSocket1.address().address; const utpSocketPort1 = utpSocket1.address().port; const utpSocket2 = UTP.createServer(async (utpConn) => { @@ -2206,7 +2202,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketListen2 = promisify(utpSocket2.listen).bind(utpSocket2); - await utpSocketListen2(0, '127.0.0.1'); + await utpSocketListen2(0, localHost); const utpSocketHost2 = utpSocket2.address().address; const utpSocketPort2 = utpSocket2.address().port; expect(proxy.getConnectionForwardCount()).toBe(0); @@ -2242,7 +2238,6 @@ describe(Proxy.name, () => { utpSocket2.unref(); await proxy.stop(); }); - test('open connection to port 0 fails', async () => { const proxy = new Proxy({ logger: logger.getChild('Proxy port 0'), @@ -2267,7 +2262,7 @@ describe(Proxy.name, () => { }, }); await expect( - proxy.openConnectionReverse('127.0.0.1' as Host, 0 as Port), + proxy.openConnectionReverse(localHost, 0 as Port), ).rejects.toThrow(networkErrors.ErrorConnectionStart); await expect(serverConnP).resolves.toBeUndefined(); await expect(serverConnClosedP).resolves.toBeUndefined(); @@ -2300,15 +2295,11 @@ describe(Proxy.name, () => { // This UTP client will just hang and not respond const utpSocket = UTP(); const utpSocketBind = promisify(utpSocket.bind).bind(utpSocket); - await utpSocketBind(0, '127.0.0.1'); + await utpSocketBind(0, localHost); const utpSocketPort = utpSocket.address().port; const timer = timerStart(3000); await expect( - proxy.openConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort as Port, - timer, - ), + proxy.openConnectionReverse(localHost, utpSocketPort as Port, timer), ).rejects.toThrow(networkErrors.ErrorConnectionStartTimeout); timerStop(timer); await expect(serverConnP).resolves.toBeUndefined(); @@ -2356,17 +2347,11 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketBind = promisify(utpSocket.bind).bind(utpSocket); - await utpSocketBind(0, '127.0.0.1'); + await utpSocketBind(0, localHost); const utpSocketPort = utpSocket.address().port; - await proxy.openConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort as Port, - ); + await proxy.openConnectionReverse(localHost, utpSocketPort as Port); expect(proxy.getConnectionReverseCount()).toBe(1); - await proxy.closeConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort as Port, - ); + await proxy.closeConnectionReverse(localHost, utpSocketPort as Port); await expect(serverConnP).resolves.toBeUndefined(); await expect(serverConnClosedP).resolves.toBeUndefined(); utpSocket.off('message', handleMessage); @@ -2414,7 +2399,7 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketBind1 = promisify(utpSocket1.bind).bind(utpSocket1); - await utpSocketBind1(0, '127.0.0.1'); + await utpSocketBind1(0, localHost); const utpSocketPort1 = utpSocket1.address().port; // Second client const utpSocket2 = UTP(); @@ -2430,25 +2415,13 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketBind2 = promisify(utpSocket2.bind).bind(utpSocket2); - await utpSocketBind2(0, '127.0.0.1'); + await utpSocketBind2(0, localHost); const utpSocketPort2 = utpSocket2.address().port; - await proxy.openConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort1 as Port, - ); - await proxy.openConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort2 as Port, - ); + await proxy.openConnectionReverse(localHost, utpSocketPort1 as Port); + await proxy.openConnectionReverse(localHost, utpSocketPort2 as Port); expect(proxy.getConnectionReverseCount()).toBe(2); - await proxy.closeConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort1 as Port, - ); - await proxy.closeConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort2 as Port, - ); + await proxy.closeConnectionReverse(localHost, utpSocketPort1 as Port); + await proxy.closeConnectionReverse(localHost, utpSocketPort2 as Port); expect(proxy.getConnectionReverseCount()).toBe(0); await expect(serverConnP).resolves.toBeUndefined(); await expect(serverConnClosedP).resolves.toBeUndefined(); @@ -2501,12 +2474,9 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketBind = promisify(utpSocket.bind).bind(utpSocket); - await utpSocketBind(0, '127.0.0.1'); + await utpSocketBind(0, localHost); const utpSocketPort = utpSocket.address().port; - await proxy.openConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort as Port, - ); + await proxy.openConnectionReverse(localHost, utpSocketPort as Port); expect(proxy.getConnectionReverseCount()).toBe(1); await expect(serverConnP).resolves.toBeUndefined(); // The server receives the end confirmation for graceful exit @@ -2569,12 +2539,9 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; const utpSocketBind = promisify(utpSocket.bind).bind(utpSocket); - await utpSocketBind(0, '127.0.0.1'); + await utpSocketBind(0, localHost); const utpSocketPort = utpSocket.address().port; - await proxy.openConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort as Port, - ); + await proxy.openConnectionReverse(localHost, utpSocketPort as Port); expect(proxy.getConnectionReverseCount()).toBe(1); // This retries multiple times // This will eventually fail and trigger a ErrorConnectionComposeTimeout @@ -2605,8 +2572,7 @@ describe(Proxy.name, () => { return proxy.getConnectionReverseCount(); }, (_, result) => { - if (result === 0) return true; - return false; + return result === 0; }, 100, ), @@ -2661,12 +2627,9 @@ describe(Proxy.name, () => { await utpSocketSend(data, 0, data.byteLength, externalPort, externalHost); }; const utpSocketBind = promisify(utpSocket.bind).bind(utpSocket); - await utpSocketBind(0, '127.0.0.1'); + await utpSocketBind(0, localHost); const utpSocketPort = utpSocket.address().port; - await proxy.openConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort as Port, - ); + await proxy.openConnectionReverse(localHost, utpSocketPort as Port); expect(proxy.getConnectionReverseCount()).toBe(1); const { p: tlsSocketClosedP, resolveP: resolveTlsSocketClosedP } = promise(); @@ -2715,8 +2678,7 @@ describe(Proxy.name, () => { return proxy.getConnectionReverseCount(); }, (_, result) => { - if (result === 0) return true; - return false; + return result === 0; }, 100, ), @@ -2746,7 +2708,7 @@ describe(Proxy.name, () => { serverHost, serverPort, } = tcpServer(); - await serverListen(0, '127.0.0.1'); + await serverListen(0, localHost); const proxy = new Proxy({ logger: logger, authToken: '', @@ -2780,12 +2742,9 @@ describe(Proxy.name, () => { const utpSocketSend = promisify(utpSocket.send).bind(utpSocket); await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; - await utpSocketBind(0, '127.0.0.1'); + await utpSocketBind(0, localHost); const utpSocketPort = utpSocket.address().port; - await proxy.openConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort as Port, - ); + await proxy.openConnectionReverse(localHost, utpSocketPort as Port); const utpConn = utpSocket.connect(proxyPort, proxyHost); const tlsSocket = tls.connect( { @@ -2816,10 +2775,7 @@ describe(Proxy.name, () => { await clientReadyP; await clientSecureConnectP; await serverConnP; - await proxy.closeConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort as Port, - ); + await proxy.closeConnectionReverse(localHost, utpSocketPort as Port); expect(proxy.getConnectionReverseCount()).toBe(0); await clientCloseP; await serverConnEndP; @@ -2850,7 +2806,7 @@ describe(Proxy.name, () => { serverHost, serverPort, } = tcpServer(); - await serverListen(0, '127.0.0.1'); + await serverListen(0, localHost); const proxy = new Proxy({ logger: logger, authToken: '', @@ -2884,12 +2840,9 @@ describe(Proxy.name, () => { const utpSocketSend = promisify(utpSocket.send).bind(utpSocket); await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); }; - await utpSocketBind(0, '127.0.0.1'); + await utpSocketBind(0, localHost); const utpSocketPort = utpSocket.address().port; - await proxy.openConnectionReverse( - '127.0.0.1' as Host, - utpSocketPort as Port, - ); + await proxy.openConnectionReverse(localHost, utpSocketPort as Port); const utpConn = utpSocket.connect(proxyPort, proxyHost); const tlsSocket = tls.connect( { diff --git a/tests/network/utils.test.ts b/tests/network/utils.test.ts index 4ef705fd8..d1a26f6aa 100644 --- a/tests/network/utils.test.ts +++ b/tests/network/utils.test.ts @@ -1,6 +1,6 @@ import type { Host, Port } from '@/network/types'; - -import { utils as networkUtils, errors as networkErrors } from '@/network'; +import * as networkUtils from '@/network/utils'; +import * as networkErrors from '@/network/errors'; describe('utils', () => { test('building addresses', async () => { From 2127b0d63525aef5dbfa9012422b80b613ebea30 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 26 May 2022 15:00:44 +1000 Subject: [PATCH 058/137] tests: fixed write after end error in proxy tests --- tests/network/Proxy.test.ts | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/network/Proxy.test.ts b/tests/network/Proxy.test.ts index b9a7d6e50..6d2c685eb 100644 --- a/tests/network/Proxy.test.ts +++ b/tests/network/Proxy.test.ts @@ -635,8 +635,17 @@ describe(Proxy.name, () => { let secured = false; const utpSocket = UTP.createServer(async (utpConn) => { utpConn.on('error', (e) => { + logger.warn('utpConn threw: ' + e.message); + // UTP implementation is buggy, + // we sometimes expect to see write after end error + if (e.message === 'Cannot call write after a stream was destroyed') { + return; + } utpConnError(e); }); + utpConn.on('end', async () => { + utpConn.destroy(); + }) const tlsSocket = new tls.TLSSocket(utpConn, { key: Buffer.from(serverKeyPairPem.privateKey, 'ascii'), cert: Buffer.from(serverCertPem, 'ascii'), @@ -751,8 +760,17 @@ describe(Proxy.name, () => { let secured = false; const utpSocket = UTP.createServer(async (utpConn) => { utpConn.on('error', (e) => { + logger.warn('utpConn threw: ' + e.message); + // UTP implementation is buggy, + // we sometimes expect to see write after end error + if (e.message === 'Cannot call write after a stream was destroyed') { + return; + } utpConnError(e); }); + utpConn.on('end', async () => { + utpConn.destroy(); + }) const tlsSocket = new tls.TLSSocket(utpConn, { key: Buffer.from(serverKeyPairPem.privateKey, 'ascii'), cert: Buffer.from(serverCertPem, 'ascii'), @@ -874,8 +892,17 @@ describe(Proxy.name, () => { // This UTP server will hold the connection const utpSocket = UTP.createServer(async (utpConn) => { utpConn.on('error', (e) => { + logger.warn('utpConn threw: ' + e.message); + // UTP implementation is buggy, + // we sometimes expect to see write after end error + if (e.message === 'Cannot call write after a stream was destroyed') { + return; + } utpConnError(e); }); + utpConn.on('end', async () => { + utpConn.destroy(); + }) const tlsSocket = new tls.TLSSocket(utpConn, { key: Buffer.from(serverKeyPairPem.privateKey, 'ascii'), cert: Buffer.from(serverCertPem, 'ascii'), @@ -1150,8 +1177,17 @@ describe(Proxy.name, () => { // This UTP server will hold the connection const utpSocket = UTP.createServer(async (utpConn) => { utpConn.on('error', (e) => { + logger.warn('utpConn threw: ' + e.message); + // UTP implementation is buggy, + // we sometimes expect to see write after end error + if (e.message === 'Cannot call write after a stream was destroyed') { + return; + } utpConnError(e); }); + utpConn.on('end', async () => { + utpConn.destroy(); + }) const tlsSocket = new tls.TLSSocket(utpConn, { key: Buffer.from(serverKeyPairPem.privateKey, 'ascii'), cert: Buffer.from(serverCertPem, 'ascii'), From 8ec9cdb8ef3efac9a4c1c5bc1778083425fad4fe Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 26 May 2022 15:48:38 +1000 Subject: [PATCH 059/137] tests: fixed odd internal error for one test It was just a problem with trying to connect to '0.0.0.0' with the UTP socket. --- tests/network/Proxy.test.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/network/Proxy.test.ts b/tests/network/Proxy.test.ts index 6d2c685eb..024425ff8 100644 --- a/tests/network/Proxy.test.ts +++ b/tests/network/Proxy.test.ts @@ -645,7 +645,7 @@ describe(Proxy.name, () => { }); utpConn.on('end', async () => { utpConn.destroy(); - }) + }); const tlsSocket = new tls.TLSSocket(utpConn, { key: Buffer.from(serverKeyPairPem.privateKey, 'ascii'), cert: Buffer.from(serverCertPem, 'ascii'), @@ -770,7 +770,7 @@ describe(Proxy.name, () => { }); utpConn.on('end', async () => { utpConn.destroy(); - }) + }); const tlsSocket = new tls.TLSSocket(utpConn, { key: Buffer.from(serverKeyPairPem.privateKey, 'ascii'), cert: Buffer.from(serverCertPem, 'ascii'), @@ -902,7 +902,7 @@ describe(Proxy.name, () => { }); utpConn.on('end', async () => { utpConn.destroy(); - }) + }); const tlsSocket = new tls.TLSSocket(utpConn, { key: Buffer.from(serverKeyPairPem.privateKey, 'ascii'), cert: Buffer.from(serverCertPem, 'ascii'), @@ -1187,7 +1187,7 @@ describe(Proxy.name, () => { }); utpConn.on('end', async () => { utpConn.destroy(); - }) + }); const tlsSocket = new tls.TLSSocket(utpConn, { key: Buffer.from(serverKeyPairPem.privateKey, 'ascii'), cert: Buffer.from(serverCertPem, 'ascii'), @@ -2554,7 +2554,8 @@ describe(Proxy.name, () => { await proxy.start({ serverHost: serverHost(), serverPort: serverPort(), - + forwardHost: localHost, + proxyHost: localHost, tlsConfig: { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, From 58d36167db77251ace35287b1f0ec100b69018c3 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 26 May 2022 16:14:53 +1000 Subject: [PATCH 060/137] syntax: general clean up proxy tests --- tests/network/Proxy.test.ts | 56 +++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/tests/network/Proxy.test.ts b/tests/network/Proxy.test.ts index 024425ff8..f199f7a0b 100644 --- a/tests/network/Proxy.test.ts +++ b/tests/network/Proxy.test.ts @@ -11,7 +11,7 @@ import * as networkUtils from '@/network/utils'; import * as networkErrors from '@/network/errors'; import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; -import { promisify, promise, timerStart, timerStop, poll } from '@/utils'; +import { poll, promise, promisify, timerStart, timerStop } from '@/utils'; import * as testUtils from '../utils'; /** @@ -141,6 +141,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -157,6 +159,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -170,6 +174,7 @@ describe(Proxy.name, () => { // Start it again await proxy.start({ forwardHost: '::1' as Host, + proxyHost: localHost, serverHost: localHost, serverPort: port, tlsConfig: { @@ -193,6 +198,7 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, serverHost: localHost, serverPort: port, }); @@ -244,6 +250,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -278,6 +286,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -336,6 +346,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -395,6 +407,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -501,6 +515,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -619,6 +635,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -744,6 +762,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -875,6 +895,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -1011,6 +1033,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -1160,6 +1184,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -1318,6 +1344,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -1489,6 +1517,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -1645,6 +1675,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -1777,6 +1809,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -1895,6 +1929,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -2033,6 +2069,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -2140,6 +2178,8 @@ describe(Proxy.name, () => { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, }, + proxyHost: localHost, + forwardHost: localHost, serverHost: localHost, serverPort: port, }); @@ -2291,7 +2331,8 @@ describe(Proxy.name, () => { await proxy.start({ serverHost: serverHost(), serverPort: serverPort(), - + proxyHost: localHost, + forwardHost: localHost, tlsConfig: { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, @@ -2322,7 +2363,8 @@ describe(Proxy.name, () => { await proxy.start({ serverHost: serverHost(), serverPort: serverPort(), - + proxyHost: localHost, + forwardHost: localHost, tlsConfig: { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, @@ -2362,6 +2404,8 @@ describe(Proxy.name, () => { await proxy.start({ serverHost: serverHost(), serverPort: serverPort(), + proxyHost: localHost, + forwardHost: localHost, tlsConfig: { keyPrivatePem: keyPairPem.privateKey, @@ -2413,6 +2457,8 @@ describe(Proxy.name, () => { await proxy.start({ serverHost: serverHost(), serverPort: serverPort(), + proxyHost: localHost, + forwardHost: localHost, tlsConfig: { keyPrivatePem: keyPairPem.privateKey, @@ -2489,6 +2535,8 @@ describe(Proxy.name, () => { await proxy.start({ serverHost: serverHost(), serverPort: serverPort(), + proxyHost: localHost, + forwardHost: localHost, tlsConfig: { keyPrivatePem: keyPairPem.privateKey, @@ -2648,6 +2696,7 @@ describe(Proxy.name, () => { certChainPem: certPem, }, proxyHost: localHost, + forwardHost: localHost, }); const externalHost = proxy.getProxyHost(); const externalPort = proxy.getProxyPort(); @@ -2754,6 +2803,7 @@ describe(Proxy.name, () => { serverHost: serverHost(), serverPort: serverPort(), proxyHost: localHost, + forwardHost: localHost, tlsConfig: { keyPrivatePem: keyPairPem.privateKey, certChainPem: certPem, From 12250b0c8dddd9ea1dded93ab1ecd1e595003c40 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 31 May 2022 14:58:57 +1000 Subject: [PATCH 061/137] build: updated `@matrixai/db` and `encryptedfs` dependencies --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index fdd71bd6a..720ebc311 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@grpc/grpc-js": "1.6.7", "@matrixai/async-init": "^1.7.3", "@matrixai/async-locks": "^2.2.4", - "@matrixai/db": "^4.0.1", + "@matrixai/db": "^4.0.2", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", "@matrixai/logger": "^2.1.1", @@ -25,7 +25,7 @@ "commander": "^8.3.0", "cross-fetch": "^3.0.6", "cross-spawn": "^7.0.3", - "encryptedfs": "^3.5.1", + "encryptedfs": "^3.5.2", "fast-fuzzy": "^1.10.8", "fd-lock": "^1.2.0", "google-protobuf": "^3.14.0", diff --git a/package.json b/package.json index bed43797e..c0badf5f4 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "@grpc/grpc-js": "1.6.7", "@matrixai/async-init": "^1.7.3", "@matrixai/async-locks": "^2.2.4", - "@matrixai/db": "^4.0.1", + "@matrixai/db": "^4.0.2", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", "@matrixai/logger": "^2.1.1", @@ -88,7 +88,7 @@ "commander": "^8.3.0", "cross-fetch": "^3.0.6", "cross-spawn": "^7.0.3", - "encryptedfs": "^3.5.1", + "encryptedfs": "^3.5.2", "fast-fuzzy": "^1.10.8", "fd-lock": "^1.2.0", "google-protobuf": "^3.14.0", From 7543a3c525ab906988285726a48aa363579db5c3 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 31 May 2022 16:18:36 +1000 Subject: [PATCH 062/137] fix: updated usage of iterators to use `valueAsBuff: false` option --- src/acl/ACL.ts | 9 ++++----- src/discovery/Discovery.ts | 13 +++++++------ src/gestalts/GestaltGraph.ts | 9 ++++----- src/nodes/NodeGraph.ts | 9 ++++----- src/notifications/NotificationsManager.ts | 13 +++++++------ src/sigchain/Sigchain.ts | 17 +++++++++-------- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/acl/ACL.ts b/src/acl/ACL.ts index caa308f13..ac83ade13 100644 --- a/src/acl/ACL.ts +++ b/src/acl/ACL.ts @@ -16,7 +16,6 @@ import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; -import { utils as dbUtils } from '@matrixai/db'; import { withF } from '@matrixai/resources'; import * as aclUtils from './utils'; import * as aclErrors from './errors'; @@ -176,12 +175,12 @@ class ACL { return this.withTransactionF(async (tran) => this.getVaultPerms(tran)); } const vaultPerms: Record> = {}; - for await (const [keyPath, value] of tran.iterator(undefined, [ - ...this.aclVaultsDbPath, - ])) { + for await (const [keyPath, nodeIds] of tran.iterator>( + { valueAsBuffer: false }, + [...this.aclVaultsDbPath], + )) { const key = keyPath[0] as Buffer; const vaultId = IdInternal.fromBuffer(key); - const nodeIds = dbUtils.deserialize>(value); const nodePerm: Record = {}; const nodeIdsGc: Set = new Set(); for (const nodeIdString in nodeIds) { diff --git a/src/discovery/Discovery.ts b/src/discovery/Discovery.ts index 576ecf29f..3e4f9d7d0 100644 --- a/src/discovery/Discovery.ts +++ b/src/discovery/Discovery.ts @@ -26,7 +26,6 @@ import { import { IdInternal } from '@matrixai/id'; import { Lock } from '@matrixai/async-locks'; import * as idUtils from '@matrixai/id/dist/utils'; -import { utils as dbUtils } from '@matrixai/db'; import * as resources from '@matrixai/resources'; import * as discoveryUtils from './utils'; import * as discoveryErrors from './errors'; @@ -203,13 +202,12 @@ class Discovery { // Processing queue this.logger.debug('DiscoveryQueue is processing'); - for await (const [keyPath, value] of this.db.iterator( - {}, + for await (const [keyPath, vertex] of this.db.iterator( + { valueAsBuffer: false }, this.discoveryQueueDbPath, )) { const key = keyPath[0] as Buffer; const vertexId = IdInternal.fromBuffer(key); - const vertex = dbUtils.deserialize(value); this.logger.debug(`Processing vertex: ${vertex}`); const vertexGId = gestaltsUtils.ungestaltKey(vertex); switch (vertexGId.type) { @@ -448,9 +446,12 @@ class Discovery { await resources.withF( [this.db.transaction(), this.lock.lock()], async ([tran]) => { - const valueIterator = tran.iterator({}, this.discoveryQueueDbPath); + const valueIterator = tran.iterator( + { valueAsBuffer: false }, + this.discoveryQueueDbPath, + ); for await (const [, value] of valueIterator) { - if (value.toString() === gestaltKey) { + if (value === gestaltKey) { return; } } diff --git a/src/gestalts/GestaltGraph.ts b/src/gestalts/GestaltGraph.ts index 0cb613a31..b746700d9 100644 --- a/src/gestalts/GestaltGraph.ts +++ b/src/gestalts/GestaltGraph.ts @@ -17,7 +17,6 @@ import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; -import { utils as dbUtils } from '@matrixai/db'; import { withF } from '@matrixai/resources'; import * as gestaltsUtils from './utils'; import * as gestaltsErrors from './errors'; @@ -104,11 +103,11 @@ class GestaltGraph { return this.withTransactionF(async (tran) => this.getGestalts(tran)); } const unvisited: Map = new Map(); - for await (const [k, v] of tran.iterator(undefined, [ - ...this.gestaltGraphMatrixDbPath, - ])) { + for await (const [k, gKs] of tran.iterator( + { valueAsBuffer: false }, + [...this.gestaltGraphMatrixDbPath], + )) { const gK = k.toString() as GestaltKey; - const gKs = dbUtils.deserialize(v); unvisited.set(gK, gKs); } const gestalts: Array = []; diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index 31cc5d130..4d623dbce 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -2,7 +2,6 @@ import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; import type { NodeAddress, NodeBucket, NodeId } from './types'; import type KeyManager from '../keys/KeyManager'; import type { Host, Hostname, Port } from '../network/types'; -import { utils as dbUtils } from '@matrixai/db'; import lexi from 'lexicographic-integer'; import Logger from '@matrixai/logger'; import { @@ -309,10 +308,10 @@ class NodeGraph { return this.withTransactionF(async (tran) => this.getAllBuckets(tran)); } const buckets: Array = []; - for await (const [, v] of tran.iterator({ keys: false }, [ - ...this.nodeGraphBucketsDbPath, - ])) { - const bucket = dbUtils.deserialize(v); + for await (const [, bucket] of tran.iterator( + { keys: false, valueAsBuffer: false }, + [...this.nodeGraphBucketsDbPath], + )) { buckets.push(bucket); } return buckets; diff --git a/src/notifications/NotificationsManager.ts b/src/notifications/NotificationsManager.ts index 58b6fc42c..8031311bf 100644 --- a/src/notifications/NotificationsManager.ts +++ b/src/notifications/NotificationsManager.ts @@ -367,11 +367,13 @@ class NotificationsManager { tran: DBTransaction, ): Promise> { const notificationIds: Array = []; - const messageIterator = tran.iterator({}, this.notificationsMessagesDbPath); - for await (const [keyPath, value] of messageIterator) { + const messageIterator = tran.iterator( + { valueAsBuffer: false }, + this.notificationsMessagesDbPath, + ); + for await (const [keyPath, notification] of messageIterator) { const key = keyPath[0] as Buffer; const notificationId = IdInternal.fromBuffer(key); - const notification = JSON.parse(value.toString()) as Notification; if (type === 'all') { notificationIds.push(notificationId); } else if (type === 'unread') { @@ -388,11 +390,10 @@ class NotificationsManager { tran: DBTransaction, ): Promise> { const notifications: Array = []; - for await (const [, value] of tran.iterator( - {}, + for await (const [, notification] of tran.iterator( + { valueAsBuffer: false }, this.notificationsMessagesDbPath, )) { - const notification = JSON.parse(value.toString()) as Notification; if (type === 'all') { notifications.push(notification); } else if (type === 'unread') { diff --git a/src/sigchain/Sigchain.ts b/src/sigchain/Sigchain.ts index a2a1f0af4..da543b82b 100644 --- a/src/sigchain/Sigchain.ts +++ b/src/sigchain/Sigchain.ts @@ -10,7 +10,6 @@ import type { } from '../claims/types'; import type KeyManager from '../keys/KeyManager'; import type { NodeIdEncoded } from '../nodes/types'; -import { utils as dbUtils } from '@matrixai/db'; import Logger from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; import { @@ -287,12 +286,13 @@ class Sigchain { return this.withTransactionF(async (tran) => this.getChainData(tran)); } const chainData: ChainDataEncoded = {}; - const readIterator = tran.iterator({}, [...this.sigchainClaimsDbPath]); - for await (const [keyPath, value] of readIterator) { + const readIterator = tran.iterator({ valueAsBuffer: false }, [ + ...this.sigchainClaimsDbPath, + ]); + for await (const [keyPath, claimEncoded] of readIterator) { const key = keyPath[0] as Buffer; const claimId = IdInternal.fromBuffer(key); - chainData[claimsUtils.encodeClaimId(claimId)] = - dbUtils.deserialize(value); + chainData[claimsUtils.encodeClaimId(claimId)] = claimEncoded; } return chainData; } @@ -316,9 +316,10 @@ class Sigchain { ); } const relevantClaims: Array = []; - const readIterator = tran.iterator({}, [...this.sigchainClaimsDbPath]); - for await (const [, value] of readIterator) { - const claim = dbUtils.deserialize(value); + const readIterator = tran.iterator({ valueAsBuffer: false }, [ + ...this.sigchainClaimsDbPath, + ]); + for await (const [, claim] of readIterator) { const decodedClaim = claimsUtils.decodeClaim(claim); if (decodedClaim.payload.data.type === claimType) { relevantClaims.push(claim); From 934bbd859c77270b5845386f786cf2aac46ccf91 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 1 Jun 2022 11:56:17 +1000 Subject: [PATCH 063/137] fix: importing `LockRequest` for `VaultManager` --- package-lock.json | 6 +++++- package.json | 2 +- src/vaults/VaultManager.ts | 11 ++--------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 720ebc311..84249b50b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@grpc/grpc-js": "1.6.7", "@matrixai/async-init": "^1.7.3", - "@matrixai/async-locks": "^2.2.4", + "@matrixai/async-locks": "^2.2.5", "@matrixai/db": "^4.0.2", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", @@ -2349,6 +2349,8 @@ }, "node_modules/@matrixai/async-locks": { "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.2.5.tgz", + "integrity": "sha512-Yokd3p64FciLNSW04Qox+UHJulxnWQIhHt3h9sMmgoiTsyZcOgeYfPAJrtZiRnhaUXhfBczPy4VPP2e5lrXgig==", "license": "Apache-2.0", "dependencies": { "@matrixai/errors": "^1.1.1", @@ -12133,6 +12135,8 @@ }, "@matrixai/async-locks": { "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.2.5.tgz", + "integrity": "sha512-Yokd3p64FciLNSW04Qox+UHJulxnWQIhHt3h9sMmgoiTsyZcOgeYfPAJrtZiRnhaUXhfBczPy4VPP2e5lrXgig==", "requires": { "@matrixai/errors": "^1.1.1", "@matrixai/resources": "^1.1.3", diff --git a/package.json b/package.json index c0badf5f4..631f960b2 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "dependencies": { "@grpc/grpc-js": "1.6.7", "@matrixai/async-init": "^1.7.3", - "@matrixai/async-locks": "^2.2.4", + "@matrixai/async-locks": "^2.2.5", "@matrixai/db": "^4.0.2", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", diff --git a/src/vaults/VaultManager.ts b/src/vaults/VaultManager.ts index ecf795a7f..fb09137a0 100644 --- a/src/vaults/VaultManager.ts +++ b/src/vaults/VaultManager.ts @@ -7,7 +7,7 @@ import type { VaultIdEncoded, } from './types'; import type { Vault } from './Vault'; -import type { FileSystem, ToString } from '../types'; +import type { FileSystem } from '../types'; import type { PolykeyWorkerManagerInterface } from '../workers/types'; import type { NodeId } from '../nodes/types'; import type KeyManager from '../keys/KeyManager'; @@ -17,7 +17,7 @@ import type NotificationsManager from '../notifications/NotificationsManager'; import type ACL from '../acl/ACL'; import type { RemoteInfo } from './VaultInternal'; import type { VaultAction } from './types'; -import type { Lockable } from '@matrixai/async-locks'; +import type { LockRequest } from '@matrixai/async-locks'; import path from 'path'; import { PassThrough } from 'readable-stream'; import { EncryptedFS, errors as encryptedFsErrors } from 'encryptedfs'; @@ -52,13 +52,6 @@ type VaultMetadata = { remoteInfo?: RemoteInfo; }; -// FIXME, this is a HACK since this type isn't exported -type LockRequest = [ - key: ToString, - lockConstructor: new () => L, - ...lockingParams: Parameters, -]; - interface VaultManager extends CreateDestroyStartStop {} @CreateDestroyStartStop( new vaultsErrors.ErrorVaultManagerRunning(), From 8a5f8b27127cd8926c3bb8b960efc56954400915 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 1 Jun 2022 12:34:06 +1000 Subject: [PATCH 064/137] fix: bug with `decryptWithKey` utility --- src/keys/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keys/utils.ts b/src/keys/utils.ts index 02ea313f9..e36849f47 100644 --- a/src/keys/utils.ts +++ b/src/keys/utils.ts @@ -541,7 +541,7 @@ async function decryptWithKey( cipherText: ArrayBuffer, ): Promise { const cipherTextBuf = Buffer.from(cipherText); - if (cipherTextBuf.byteLength <= 32) { + if (cipherTextBuf.byteLength < 32) { return; } const iv = cipherTextBuf.subarray(0, ivSize); From 3ba04db494a49146fba5b73f0752c68412552913 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 1 Jun 2022 14:08:28 +1000 Subject: [PATCH 065/137] build: Updated `encryptedfs` and `@matrixai/db` version --- package-lock.json | 8 ++++++-- package.json | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 84249b50b..8674bf340 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@grpc/grpc-js": "1.6.7", "@matrixai/async-init": "^1.7.3", "@matrixai/async-locks": "^2.2.5", - "@matrixai/db": "^4.0.2", + "@matrixai/db": "^4.0.5", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", "@matrixai/logger": "^2.1.1", @@ -25,7 +25,7 @@ "commander": "^8.3.0", "cross-fetch": "^3.0.6", "cross-spawn": "^7.0.3", - "encryptedfs": "^3.5.2", + "encryptedfs": "^3.5.3", "fast-fuzzy": "^1.10.8", "fd-lock": "^1.2.0", "google-protobuf": "^3.14.0", @@ -4200,6 +4200,8 @@ }, "node_modules/encryptedfs": { "version": "3.5.3", + "resolved": "https://registry.npmjs.org/encryptedfs/-/encryptedfs-3.5.3.tgz", + "integrity": "sha512-2cTz6/8lUF2WFv6YNA9RwSASBh6bHIJqCbOWFr1RCo/vEHeR1+OKK0F+Xu4ujBlLsz3/a6NwT6/UoHl8Zn5rCg==", "license": "Apache-2.0", "dependencies": { "@matrixai/async-init": "^1.7.3", @@ -13348,6 +13350,8 @@ }, "encryptedfs": { "version": "3.5.3", + "resolved": "https://registry.npmjs.org/encryptedfs/-/encryptedfs-3.5.3.tgz", + "integrity": "sha512-2cTz6/8lUF2WFv6YNA9RwSASBh6bHIJqCbOWFr1RCo/vEHeR1+OKK0F+Xu4ujBlLsz3/a6NwT6/UoHl8Zn5rCg==", "requires": { "@matrixai/async-init": "^1.7.3", "@matrixai/async-locks": "^2.2.4", diff --git a/package.json b/package.json index 631f960b2..dc5780c81 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "@grpc/grpc-js": "1.6.7", "@matrixai/async-init": "^1.7.3", "@matrixai/async-locks": "^2.2.5", - "@matrixai/db": "^4.0.2", + "@matrixai/db": "^4.0.5", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", "@matrixai/logger": "^2.1.1", @@ -88,7 +88,7 @@ "commander": "^8.3.0", "cross-fetch": "^3.0.6", "cross-spawn": "^7.0.3", - "encryptedfs": "^3.5.2", + "encryptedfs": "^3.5.3", "fast-fuzzy": "^1.10.8", "fd-lock": "^1.2.0", "google-protobuf": "^3.14.0", From a11fc556db4ad0435a7d3181ebf3945f04132bbf Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 1 Jun 2022 15:16:45 +1000 Subject: [PATCH 066/137] refactor: moving `ClientMetadata` to GRPC domain Having `ClientMetadata` in the top-level types caused an import loop. By moving it and `ErrorPolykeyRemote` to the grpc domain this loop is resolved. This was the best option since now all usage of `ClientMetadata` is inside the grpc domain. --- src/bin/utils/utils.ts | 11 ++-- src/errors.ts | 55 ------------------- src/grpc/errors.ts | 55 +++++++++++++++++++ src/grpc/types.ts | 11 ++++ src/grpc/utils/utils.ts | 5 +- src/types.ts | 10 ---- .../agent/service/nodesCrossSignClaim.test.ts | 10 +++- tests/bin/utils.test.ts | 13 +++-- tests/grpc/utils.test.ts | 16 +++--- tests/utils.ts | 4 +- 10 files changed, 99 insertions(+), 91 deletions(-) diff --git a/src/bin/utils/utils.ts b/src/bin/utils/utils.ts index 0e66b8e23..51b259dfb 100644 --- a/src/bin/utils/utils.ts +++ b/src/bin/utils/utils.ts @@ -4,10 +4,11 @@ import { LogLevel } from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; import { AbstractError } from '@matrixai/errors'; import * as binProcessors from './processors'; +import ErrorPolykey from '../../ErrorPolykey'; import * as binErrors from '../errors'; import * as clientUtils from '../../client/utils'; import * as clientErrors from '../../client/errors'; -import * as errors from '../../errors'; +import * as grpcErrors from '../../grpc/errors'; import * as nodesUtils from '../../nodes/utils'; import * as utils from '../../utils'; @@ -105,7 +106,7 @@ function outputFormatter(msg: OutputObject): string { let currError = msg.data; let indent = ' '; while (currError != null) { - if (currError instanceof errors.ErrorPolykeyRemote) { + if (currError instanceof grpcErrors.ErrorPolykeyRemote) { output += `${currError.name}: ${currError.description}`; if (currError.message && currError.message !== '') { output += ` - ${currError.message}`; @@ -120,7 +121,7 @@ function outputFormatter(msg: OutputObject): string { output += `${indent}timestamp\t${currError.timestamp}\n`; output += `${indent}remote error: `; currError = currError.cause; - } else if (currError instanceof errors.ErrorPolykey) { + } else if (currError instanceof ErrorPolykey) { output += `${currError.name}: ${currError.description}`; if (currError.message && currError.message !== '') { output += ` - ${currError.message}`; @@ -133,7 +134,7 @@ function outputFormatter(msg: OutputObject): string { } if (currError.cause) { output += `${indent}cause: `; - if (currError.cause instanceof errors.ErrorPolykey) { + if (currError.cause instanceof ErrorPolykey) { currError = currError.cause; } else if (currError.cause instanceof Error) { output += `${currError.cause.name}`; @@ -214,7 +215,7 @@ async function retryAuthentication( function remoteErrorCause(e: any): [any, number] { let errorCause = e; let depth = 0; - while (errorCause instanceof errors.ErrorPolykeyRemote) { + while (errorCause instanceof grpcErrors.ErrorPolykeyRemote) { errorCause = errorCause.cause; depth++; } diff --git a/src/errors.ts b/src/errors.ts index 12af747ab..3f6aba171 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,59 +1,5 @@ -import type { Class } from '@matrixai/errors'; -import type { ClientMetadata } from './types'; import ErrorPolykey from './ErrorPolykey'; import sysexits from './utils/sysexits'; -import * as nodesUtils from './nodes/utils'; - -class ErrorPolykeyRemote extends ErrorPolykey { - static description = 'Remote error from RPC call'; - exitCode = sysexits.UNAVAILABLE; - metadata: ClientMetadata; - - constructor(metadata: ClientMetadata, message?: string, options?) { - super(message, options); - this.metadata = metadata; - } - - public static fromJSON>( - this: T, - json: any, - ): InstanceType { - if ( - typeof json !== 'object' || - json.type !== this.name || - typeof json.data !== 'object' || - typeof json.data.message !== 'string' || - isNaN(Date.parse(json.data.timestamp)) || - typeof json.data.metadata !== 'object' || - typeof json.data.data !== 'object' || - typeof json.data.exitCode !== 'number' || - ('stack' in json.data && typeof json.data.stack !== 'string') - ) { - throw new TypeError(`Cannot decode JSON to ${this.name}`); - } - const parsedMetadata: ClientMetadata = { - ...json.data.metadata, - nodeId: nodesUtils.decodeNodeId(json.data.metadata.nodeId), - }; - const e = new this(parsedMetadata, json.data.message, { - timestamp: new Date(json.data.timestamp), - data: json.data.data, - cause: json.data.cause, - }); - e.exitCode = json.data.exitCode; - e.stack = json.data.stack; - return e; - } - - public toJSON(): any { - const json = super.toJSON(); - json.data.metadata = { - ...this.metadata, - nodeId: nodesUtils.encodeNodeId(this.metadata.nodeId), - }; - return json; - } -} class ErrorPolykeyUnimplemented extends ErrorPolykey { static description = 'This is an unimplemented functionality'; @@ -104,7 +50,6 @@ export { ErrorPolykey, ErrorPolykeyUnimplemented, ErrorPolykeyUnknown, - ErrorPolykeyRemote, ErrorPolykeyAgentRunning, ErrorPolykeyAgentNotRunning, ErrorPolykeyAgentDestroyed, diff --git a/src/grpc/errors.ts b/src/grpc/errors.ts index 023dffdc3..aed2281c2 100644 --- a/src/grpc/errors.ts +++ b/src/grpc/errors.ts @@ -1,4 +1,7 @@ +import type { Class } from '@matrixai/errors'; +import type { ClientMetadata } from './types'; import { ErrorPolykey, sysexits } from '../errors'; +import * as nodesUtils from '../nodes/utils'; class ErrorGRPC extends ErrorPolykey {} @@ -47,6 +50,57 @@ class ErrorGRPCServerVerification extends ErrorGRPC { exitCode = sysexits.UNAVAILABLE; } +class ErrorPolykeyRemote extends ErrorPolykey { + static description = 'Remote error from RPC call'; + exitCode = sysexits.UNAVAILABLE; + metadata: ClientMetadata; + + constructor(metadata: ClientMetadata, message?: string, options?) { + super(message, options); + this.metadata = metadata; + } + + public static fromJSON>( + this: T, + json: any, + ): InstanceType { + if ( + typeof json !== 'object' || + json.type !== this.name || + typeof json.data !== 'object' || + typeof json.data.message !== 'string' || + isNaN(Date.parse(json.data.timestamp)) || + typeof json.data.metadata !== 'object' || + typeof json.data.data !== 'object' || + typeof json.data.exitCode !== 'number' || + ('stack' in json.data && typeof json.data.stack !== 'string') + ) { + throw new TypeError(`Cannot decode JSON to ${this.name}`); + } + const parsedMetadata: ClientMetadata = { + ...json.data.metadata, + nodeId: nodesUtils.decodeNodeId(json.data.metadata.nodeId), + }; + const e = new this(parsedMetadata, json.data.message, { + timestamp: new Date(json.data.timestamp), + data: json.data.data, + cause: json.data.cause, + }); + e.exitCode = json.data.exitCode; + e.stack = json.data.stack; + return e; + } + + public toJSON(): any { + const json = super.toJSON(); + json.data.metadata = { + ...this.metadata, + nodeId: nodesUtils.encodeNodeId(this.metadata.nodeId), + }; + return json; + } +} + export { ErrorGRPC, ErrorGRPCClientTimeout, @@ -58,4 +112,5 @@ export { ErrorGRPCServerShutdown, ErrorGRPCServerNotSecured, ErrorGRPCServerVerification, + ErrorPolykeyRemote, }; diff --git a/src/grpc/types.ts b/src/grpc/types.ts index 41061c3dd..8f600c2ce 100644 --- a/src/grpc/types.ts +++ b/src/grpc/types.ts @@ -8,6 +8,9 @@ import type { UntypedServiceImplementation, Metadata, } from '@grpc/grpc-js'; +import type { NodeId } from '../nodes/types'; +import type { Host, Port } from '../network/types'; +import type { POJO } from '../types'; type Services = Array< [ @@ -100,6 +103,13 @@ interface AsyncGeneratorDuplexStreamClient< meta: Promise; } +type ClientMetadata = { + nodeId: NodeId; + host: Host; + port: Port; + command: string; +} & POJO; + export type { Services, PromiseUnaryCall, @@ -109,4 +119,5 @@ export type { AsyncGeneratorWritableStreamClient, AsyncGeneratorDuplexStream, AsyncGeneratorDuplexStreamClient, + ClientMetadata, }; diff --git a/src/grpc/utils/utils.ts b/src/grpc/utils/utils.ts index 1b98d310f..f696f37a2 100644 --- a/src/grpc/utils/utils.ts +++ b/src/grpc/utils/utils.ts @@ -28,7 +28,8 @@ import type { AsyncGeneratorDuplexStreamClient, } from '../types'; import type { CertificatePemChain, PrivateKeyPem } from '../../keys/types'; -import type { POJO, ClientMetadata } from '../../types'; +import type { POJO } from '../../types'; +import type { ClientMetadata } from '../types'; import type { NodeId } from '../../nodes/types'; import { Buffer } from 'buffer'; import { AbstractError } from '@matrixai/errors'; @@ -199,7 +200,7 @@ function toError( if (isNaN(parseInt(key)) && e.code === grpc.status[key]) { if (key === 'UNKNOWN' && errorData != null) { const error: Error = JSON.parse(errorData, reviver); - const remoteError = new errors.ErrorPolykeyRemote( + const remoteError = new grpcErrors.ErrorPolykeyRemote( metadata, error.message, { diff --git a/src/types.ts b/src/types.ts index 0e41f366f..8fba1fc08 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,5 @@ // eslint-disable-next-line no-restricted-imports -- Interim types for FileSystem import type fs from 'fs'; -import type { Host, Port } from './network/types'; -import type { NodeId } from './nodes/types'; /** * Plain data dictionary @@ -79,13 +77,6 @@ interface FileSystem { type FileHandle = fs.promises.FileHandle; -type ClientMetadata = { - nodeId: NodeId; - host: Host; - port: Port; - command: string; -} & POJO; - export type { POJO, Opaque, @@ -98,5 +89,4 @@ export type { Timer, FileSystem, FileHandle, - ClientMetadata, }; diff --git a/tests/agent/service/nodesCrossSignClaim.test.ts b/tests/agent/service/nodesCrossSignClaim.test.ts index bc676db86..aea5d7a6e 100644 --- a/tests/agent/service/nodesCrossSignClaim.test.ts +++ b/tests/agent/service/nodesCrossSignClaim.test.ts @@ -5,7 +5,6 @@ import fs from 'fs'; import path from 'path'; import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import { ErrorPolykeyRemote } from '@/errors'; import PolykeyAgent from '@/PolykeyAgent'; import GRPCServer from '@/grpc/GRPCServer'; import GRPCClientAgent from '@/agent/GRPCClientAgent'; @@ -15,6 +14,7 @@ import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import * as claimsUtils from '@/claims/utils'; +import * as grpcErrors from '@/grpc/errors'; import * as testNodesUtils from '../../nodes/utils'; import * as testUtils from '../../utils'; @@ -203,7 +203,9 @@ describe('nodesCrossSignClaim', () => { // 2. X <- sends its intermediary signed claim <- Y const crossSignMessageUndefinedSingly = new nodesPB.CrossSign(); await genClaims.write(crossSignMessageUndefinedSingly); - await expect(() => genClaims.read()).rejects.toThrow(ErrorPolykeyRemote); + await expect(() => genClaims.read()).rejects.toThrow( + grpcErrors.ErrorPolykeyRemote, + ); expect(genClaims.stream.destroyed).toBe(true); // Check sigchain's lock is released // Revert side effects @@ -222,7 +224,9 @@ describe('nodesCrossSignClaim', () => { intermediaryNoSignature, ); await genClaims.write(crossSignMessageUndefinedSinglySignature); - await expect(() => genClaims.read()).rejects.toThrow(ErrorPolykeyRemote); + await expect(() => genClaims.read()).rejects.toThrow( + grpcErrors.ErrorPolykeyRemote, + ); expect(genClaims.stream.destroyed).toBe(true); // Check sigchain's lock is released // Revert side effects diff --git a/tests/bin/utils.test.ts b/tests/bin/utils.test.ts index 45e6bd870..80b9aa3bf 100644 --- a/tests/bin/utils.test.ts +++ b/tests/bin/utils.test.ts @@ -1,7 +1,8 @@ import type { Host, Port } from '@/network/types'; +import ErrorPolykey from '@/ErrorPolykey'; import * as binUtils from '@/bin/utils/utils'; import * as nodesUtils from '@/nodes/utils'; -import * as errors from '@/errors'; +import * as grpcErrors from '@/grpc/errors'; import * as testUtils from '../utils'; describe('bin/utils', () => { @@ -81,11 +82,11 @@ describe('bin/utils', () => { const port = 55555 as Port; const nodeId = testUtils.generateRandomNodeId(); const standardError = new TypeError('some error'); - const pkError = new errors.ErrorPolykey('some pk error', { + const pkError = new ErrorPolykey('some pk error', { timestamp, data, }); - const remoteError = new errors.ErrorPolykeyRemote( + const remoteError = new grpcErrors.ErrorPolykeyRemote( { nodeId, host, @@ -95,7 +96,7 @@ describe('bin/utils', () => { 'some remote error', { timestamp, cause: pkError }, ); - const twoRemoteErrors = new errors.ErrorPolykeyRemote( + const twoRemoteErrors = new grpcErrors.ErrorPolykeyRemote( { nodeId, host, @@ -105,7 +106,7 @@ describe('bin/utils', () => { 'remote error', { timestamp, - cause: new errors.ErrorPolykeyRemote( + cause: new grpcErrors.ErrorPolykeyRemote( { nodeId, host, @@ -115,7 +116,7 @@ describe('bin/utils', () => { undefined, { timestamp, - cause: new errors.ErrorPolykey('pk error', { + cause: new ErrorPolykey('pk error', { timestamp, cause: standardError, }), diff --git a/tests/grpc/utils.test.ts b/tests/grpc/utils.test.ts index 7364d6bff..f757ee78e 100644 --- a/tests/grpc/utils.test.ts +++ b/tests/grpc/utils.test.ts @@ -74,7 +74,7 @@ describe('GRPC utils', () => { const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('error'); const pCall = unary(messageTo); - await expect(pCall).rejects.toThrow(errors.ErrorPolykeyRemote); + await expect(pCall).rejects.toThrow(grpcErrors.ErrorPolykeyRemote); try { await pCall; } catch (e) { @@ -138,7 +138,7 @@ describe('GRPC utils', () => { messageTo.setChallenge(challenge); const stream = serverStream(messageTo); await expect(() => stream.next()).rejects.toThrow( - errors.ErrorPolykeyRemote, + grpcErrors.ErrorPolykeyRemote, ); // The generator will have ended // the internal stream will be automatically destroyed @@ -386,7 +386,7 @@ describe('GRPC utils', () => { messageTo.setChallenge('error'); await genDuplex.write(messageTo); await expect(() => genDuplex.read()).rejects.toThrow( - errors.ErrorPolykeyRemote, + grpcErrors.ErrorPolykeyRemote, ); expect(genDuplex.stream.destroyed).toBe(true); expect(genDuplex.stream.getPeer()).toBe(`127.0.0.1:${port}`); @@ -409,7 +409,7 @@ describe('GRPC utils', () => { const messageTo = new utilsPB.EchoMessage(); messageTo.setChallenge('error'); await expect(() => genDuplex.next(messageTo)).rejects.toThrow( - errors.ErrorPolykeyRemote, + grpcErrors.ErrorPolykeyRemote, ); expect(genDuplex.stream.destroyed).toBe(true); expect(genDuplex.stream.getPeer()).toBe(`127.0.0.1:${port}`); @@ -446,7 +446,7 @@ describe('GRPC utils', () => { command: 'testCall', }, ); - expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); + expect(deserialisedError).toBeInstanceOf(grpcErrors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); // @ts-ignore - already checked above that error is ErrorPolykeyRemote expect(deserialisedError.metadata.nodeId).toBe(nodeId); @@ -487,7 +487,7 @@ describe('GRPC utils', () => { command: 'testCall', }, ); - expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); + expect(deserialisedError).toBeInstanceOf(grpcErrors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); // @ts-ignore - already checked above that error is ErrorPolykeyRemote expect(deserialisedError.metadata.nodeId).toBe(nodeId); @@ -522,7 +522,7 @@ describe('GRPC utils', () => { command: 'testCall', }, ); - expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); + expect(deserialisedError).toBeInstanceOf(grpcErrors.ErrorPolykeyRemote); // @ts-ignore - already checked above that error is ErrorPolykeyRemote expect(deserialisedError.metadata.nodeId).toBe(nodeId); // @ts-ignore @@ -575,7 +575,7 @@ describe('GRPC utils', () => { command: 'testCall', }, ); - expect(deserialisedError).toBeInstanceOf(errors.ErrorPolykeyRemote); + expect(deserialisedError).toBeInstanceOf(grpcErrors.ErrorPolykeyRemote); expect(deserialisedError.message).toBe('test error'); // @ts-ignore - already checked above that error is ErrorPolykeyRemote expect(deserialisedError.metadata.nodeId).toBe(nodeId); diff --git a/tests/utils.ts b/tests/utils.ts index 38bd48fcd..311743565 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -12,8 +12,8 @@ import GRPCClientClient from '@/client/GRPCClientClient'; import * as clientUtils from '@/client/utils'; import * as keysUtils from '@/keys/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as grpcErrors from '@/grpc/errors'; import { sleep } from '@/utils'; -import * as errors from '@/errors'; import config from '@/config'; /** @@ -189,7 +189,7 @@ const expectRemoteError = async ( promise: Promise, error, ): Promise => { - await expect(promise).rejects.toThrow(errors.ErrorPolykeyRemote); + await expect(promise).rejects.toThrow(grpcErrors.ErrorPolykeyRemote); try { return await promise; } catch (e) { From b6c30b81fef8acd33e2c40ab8b554ca4297ae4bc Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 1 Jun 2022 15:26:27 +1000 Subject: [PATCH 067/137] fix: changed "remote error" to "cause" in cli error logging #323 --- src/bin/utils/utils.ts | 2 +- tests/bin/utils.test.ts | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/bin/utils/utils.ts b/src/bin/utils/utils.ts index 51b259dfb..1345afb04 100644 --- a/src/bin/utils/utils.ts +++ b/src/bin/utils/utils.ts @@ -119,7 +119,7 @@ function outputFormatter(msg: OutputObject): string { output += `${indent}host\t${currError.metadata.host}\n`; output += `${indent}port\t${currError.metadata.port}\n`; output += `${indent}timestamp\t${currError.timestamp}\n`; - output += `${indent}remote error: `; + output += `${indent}cause: `; currError = currError.cause; } else if (currError instanceof ErrorPolykey) { output += `${currError.name}: ${currError.description}`; diff --git a/tests/bin/utils.test.ts b/tests/bin/utils.test.ts index 80b9aa3bf..6a53667da 100644 --- a/tests/bin/utils.test.ts +++ b/tests/bin/utils.test.ts @@ -124,7 +124,7 @@ describe('bin/utils', () => { ), }, ); - // Error + // Human expect( binUtils.outputFormatter({ type: 'error', data: standardError }), ).toBe(`${standardError.name}: ${standardError.message}\n`); @@ -141,7 +141,7 @@ describe('bin/utils', () => { ` host\t${host}\n` + ` port\t${port}\n` + ` timestamp\t${timestamp.toString()}\n` + - ` remote error: ${remoteError.cause.name}: ${remoteError.cause.description} - ${remoteError.cause.message}\n` + + ` cause: ${remoteError.cause.name}: ${remoteError.cause.description} - ${remoteError.cause.message}\n` + ` exitCode\t${pkError.exitCode}\n` + ` timestamp\t${timestamp.toString()}\n` + ` data\t${JSON.stringify(data)}\n`, @@ -155,17 +155,18 @@ describe('bin/utils', () => { ` host\t${host}\n` + ` port\t${port}\n` + ` timestamp\t${timestamp.toString()}\n` + - ` remote error: ${twoRemoteErrors.cause.name}: ${twoRemoteErrors.cause.description}\n` + + ` cause: ${twoRemoteErrors.cause.name}: ${twoRemoteErrors.cause.description}\n` + ` command\t${twoRemoteErrors.cause.metadata.command}\n` + ` nodeId\t${nodesUtils.encodeNodeId(nodeId)}\n` + ` host\t${host}\n` + ` port\t${port}\n` + ` timestamp\t${timestamp.toString()}\n` + - ` remote error: ${twoRemoteErrors.cause.cause.name}: ${twoRemoteErrors.cause.cause.description} - ${twoRemoteErrors.cause.cause.message}\n` + + ` cause: ${twoRemoteErrors.cause.cause.name}: ${twoRemoteErrors.cause.cause.description} - ${twoRemoteErrors.cause.cause.message}\n` + ` exitCode\t${pkError.exitCode}\n` + ` timestamp\t${timestamp.toString()}\n` + ` cause: ${standardError.name}: ${standardError.message}\n`, ); + // JSON expect( binUtils.outputFormatter({ type: 'json', data: standardError }), ).toBe( From 6e209156663652f81cb24d27a522efc39e9c0558 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 1 Jun 2022 17:08:36 +1000 Subject: [PATCH 068/137] feat: filtering error logging in service handlers We only want to log out server errors on the server side, so we now apply filters on errors before logging them. --- src/agent/service/nodesChainDataGet.ts | 3 +- .../service/nodesClosestLocalNodesGet.ts | 3 +- src/agent/service/nodesCrossSignClaim.ts | 9 ++- .../service/nodesHolePunchMessageSend.ts | 3 +- src/agent/service/notificationsSend.ts | 9 ++- src/agent/service/vaultsGitInfoGet.ts | 64 +++++++++------- src/agent/service/vaultsGitPackGet.ts | 55 +++++++++----- src/agent/service/vaultsScan.ts | 9 ++- src/agent/utils.ts | 37 ++++++++- src/client/service/agentLockAll.ts | 3 +- src/client/service/agentStatus.ts | 3 +- src/client/service/agentStop.ts | 3 +- src/client/service/agentUnlock.ts | 3 +- .../service/gestaltsActionsGetByIdentity.ts | 6 +- .../service/gestaltsActionsGetByNode.ts | 3 +- .../service/gestaltsActionsSetByIdentity.ts | 7 +- .../service/gestaltsActionsSetByNode.ts | 6 +- .../service/gestaltsActionsUnsetByIdentity.ts | 7 +- .../service/gestaltsActionsUnsetByNode.ts | 6 +- .../service/gestaltsDiscoveryByIdentity.ts | 3 +- src/client/service/gestaltsDiscoveryByNode.ts | 3 +- .../service/gestaltsGestaltGetByIdentity.ts | 3 +- .../service/gestaltsGestaltGetByNode.ts | 3 +- src/client/service/gestaltsGestaltList.ts | 3 +- .../service/gestaltsGestaltTrustByIdentity.ts | 7 +- .../service/gestaltsGestaltTrustByNode.ts | 6 +- src/client/service/identitiesAuthenticate.ts | 4 +- .../service/identitiesAuthenticatedGet.ts | 3 +- src/client/service/identitiesClaim.ts | 6 +- .../service/identitiesInfoConnectedGet.ts | 7 +- src/client/service/identitiesInfoGet.ts | 6 +- src/client/service/identitiesProvidersList.ts | 3 +- src/client/service/identitiesTokenDelete.ts | 3 +- src/client/service/identitiesTokenGet.ts | 3 +- src/client/service/identitiesTokenPut.ts | 3 +- src/client/service/keysCertsChainGet.ts | 3 +- src/client/service/keysCertsGet.ts | 3 +- src/client/service/keysDecrypt.ts | 3 +- src/client/service/keysEncrypt.ts | 3 +- src/client/service/keysKeyPairRenew.ts | 3 +- src/client/service/keysKeyPairReset.ts | 3 +- src/client/service/keysKeyPairRoot.ts | 3 +- src/client/service/keysPasswordChange.ts | 3 +- src/client/service/keysSign.ts | 3 +- src/client/service/keysVerify.ts | 3 +- src/client/service/nodesAdd.ts | 3 +- src/client/service/nodesClaim.ts | 6 +- src/client/service/nodesFind.ts | 6 +- src/client/service/nodesPing.ts | 6 +- src/client/service/notificationsClear.ts | 3 +- src/client/service/notificationsRead.ts | 3 +- src/client/service/notificationsSend.ts | 6 +- src/client/service/vaultsClone.ts | 51 ++++++++----- src/client/service/vaultsCreate.ts | 5 +- src/client/service/vaultsDelete.ts | 34 +++++++-- src/client/service/vaultsList.ts | 3 +- src/client/service/vaultsLog.ts | 48 ++++++++---- src/client/service/vaultsPermissionGet.ts | 37 ++++++--- src/client/service/vaultsPermissionSet.ts | 68 +++++++++++------ src/client/service/vaultsPermissionUnset.ts | 61 ++++++++++----- src/client/service/vaultsPull.ts | 75 +++++++++++-------- src/client/service/vaultsRename.ts | 44 +++++++---- src/client/service/vaultsScan.ts | 8 +- src/client/service/vaultsSecretsDelete.ts | 42 ++++++++--- src/client/service/vaultsSecretsEdit.ts | 52 ++++++++----- src/client/service/vaultsSecretsGet.ts | 42 ++++++++--- src/client/service/vaultsSecretsList.ts | 34 +++++++-- src/client/service/vaultsSecretsMkdir.ts | 47 ++++++++---- src/client/service/vaultsSecretsNew.ts | 42 ++++++++--- src/client/service/vaultsSecretsNewDir.ts | 40 +++++++--- src/client/service/vaultsSecretsRename.ts | 52 ++++++++----- src/client/service/vaultsSecretsStat.ts | 42 ++++++++--- src/client/service/vaultsVersion.ts | 47 ++++++++---- src/client/utils/utils.ts | 37 +++++++++ 74 files changed, 903 insertions(+), 376 deletions(-) diff --git a/src/agent/service/nodesChainDataGet.ts b/src/agent/service/nodesChainDataGet.ts index 492c8ca73..0e09ff35f 100644 --- a/src/agent/service/nodesChainDataGet.ts +++ b/src/agent/service/nodesChainDataGet.ts @@ -6,6 +6,7 @@ import type { ClaimIdEncoded } from '../../claims/types'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import * as agentUtils from '../utils'; /** * Retrieves the ChainDataEncoded of this node. @@ -50,7 +51,7 @@ function nodesChainDataGet({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - logger.error(e); + !agentUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/agent/service/nodesClosestLocalNodesGet.ts b/src/agent/service/nodesClosestLocalNodesGet.ts index bd562bbe5..e28fbd191 100644 --- a/src/agent/service/nodesClosestLocalNodesGet.ts +++ b/src/agent/service/nodesClosestLocalNodesGet.ts @@ -9,6 +9,7 @@ import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import * as agentUtils from '../utils'; /** * Retrieves the local nodes (i.e. from the current node) that are closest @@ -66,7 +67,7 @@ function nodesClosestLocalNodesGet({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - logger.error(e); + !agentUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/agent/service/nodesCrossSignClaim.ts b/src/agent/service/nodesCrossSignClaim.ts index f9fbb1bbb..63b6304c9 100644 --- a/src/agent/service/nodesCrossSignClaim.ts +++ b/src/agent/service/nodesCrossSignClaim.ts @@ -14,6 +14,7 @@ import * as nodesUtils from '../../nodes/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; +import * as agentUtils from '../utils'; function nodesCrossSignClaim({ db, @@ -172,7 +173,13 @@ function nodesCrossSignClaim({ }); } catch (e) { await genClaims.throw(e); - logger.error(e); + !agentUtils.isClientError(e, [ + claimsErrors.ErrorEmptyStream, + claimsErrors.ErrorUndefinedSinglySignedClaim, + claimsErrors.ErrorUndefinedSignature, + claimsErrors.ErrorNodesClaimType, + claimsErrors.ErrorUndefinedDoublySignedClaim, + ]) && logger.error(e); return; } }; diff --git a/src/agent/service/nodesHolePunchMessageSend.ts b/src/agent/service/nodesHolePunchMessageSend.ts index c1b681054..1ec86a35c 100644 --- a/src/agent/service/nodesHolePunchMessageSend.ts +++ b/src/agent/service/nodesHolePunchMessageSend.ts @@ -12,6 +12,7 @@ import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as agentUtils from '../utils'; function nodesHolePunchMessageSend({ keyManager, @@ -73,7 +74,7 @@ function nodesHolePunchMessageSend({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - logger.error(e); + !agentUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/agent/service/notificationsSend.ts b/src/agent/service/notificationsSend.ts index 07aaf0933..6108cbe74 100644 --- a/src/agent/service/notificationsSend.ts +++ b/src/agent/service/notificationsSend.ts @@ -5,7 +5,9 @@ import type Logger from '@matrixai/logger'; import type { DB } from '@matrixai/db'; import * as grpcUtils from '../../grpc/utils'; import * as notificationsUtils from '../../notifications/utils'; +import * as notificationsErrors from '../../notifications/errors'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as agentUtils from '../utils'; function notificationsSend({ notificationsManager, @@ -34,7 +36,12 @@ function notificationsSend({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - logger.error(e); + !agentUtils.isClientError(e, [ + notificationsErrors.ErrorNotificationsInvalidType, + notificationsErrors.ErrorNotificationsValidationFailed, + notificationsErrors.ErrorNotificationsParse, + notificationsErrors.ErrorNotificationsPermissionsNotFound, + ]) && logger.error(e); return; } }; diff --git a/src/agent/service/vaultsGitInfoGet.ts b/src/agent/service/vaultsGitInfoGet.ts index 4a9893985..aecdde37e 100644 --- a/src/agent/service/vaultsGitInfoGet.ts +++ b/src/agent/service/vaultsGitInfoGet.ts @@ -1,5 +1,5 @@ import type { DB } from '@matrixai/db'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId, VaultAction } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type ACL from '../../acl/ACL'; import type { ConnectionInfoGet } from '../../agent/types'; @@ -9,9 +9,12 @@ import * as grpcUtils from '../../grpc/utils'; import * as vaultsUtils from '../../vaults/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as nodesUtils from '../../nodes/utils'; +import { matchSync } from '../../utils'; import * as agentErrors from '../errors'; +import * as agentUtils from '../utils'; function vaultsGitInfoGet({ vaultManager, @@ -31,29 +34,37 @@ function vaultsGitInfoGet({ ): Promise => { const genWritable = grpcUtils.generatorWritable(call, true); try { - const request = call.request; - const vaultMessage = request.getVault(); - if (vaultMessage == null) { - throw new vaultsErrors.ErrorVaultsVaultUndefined(); - } - let vaultName; - const vaultNameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - vaultNameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultName = vaultNameOrId; - if (vaultId == null) { - try { - vaultId = validationUtils.parseVaultId(vaultNameOrId); - vaultName = (await vaultManager.getVaultMeta(vaultId, tran)) - ?.vaultName; - } catch (e) { - throw new vaultsErrors.ErrorVaultsVaultUndefined(e.message, { - cause: e, - }); - } + const { + vaultId, + actionType, + }: { + vaultId: VaultId; + actionType: VaultAction; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + [['actionType'], () => validationUtils.parseVaultAction(value)], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + actionType: call.request.getAction(), + }, + ); + const vaultName = (await vaultManager.getVaultMeta(vaultId, tran)) + ?.vaultName; + if (vaultName == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); } // Getting the NodeId from the ReverseProxy connection info const connectionInfo = connectionInfoGet(call); @@ -64,9 +75,6 @@ function vaultsGitInfoGet({ } const nodeId = connectionInfo.remoteNodeId; const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); - const actionType = validationUtils.parseVaultAction( - request.getAction(), - ); const permissions = await acl.getNodePerm(nodeId, tran); if (permissions == null) { throw new vaultsErrors.ErrorVaultsPermissionDenied( @@ -97,9 +105,15 @@ function vaultsGitInfoGet({ } }); await genWritable.next(null); + return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !agentUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + agentErrors.ErrorConnectionInfoMissing, + vaultsErrors.ErrorVaultsPermissionDenied, + ]) && logger.error(e); + return; } }; } diff --git a/src/agent/service/vaultsGitPackGet.ts b/src/agent/service/vaultsGitPackGet.ts index c7ec95dbd..e17cad29f 100644 --- a/src/agent/service/vaultsGitPackGet.ts +++ b/src/agent/service/vaultsGitPackGet.ts @@ -1,19 +1,21 @@ import type * as grpc from '@grpc/grpc-js'; import type { DB } from '@matrixai/db'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId, VaultAction } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type { ConnectionInfoGet } from '../../agent/types'; import type ACL from '../../acl/ACL'; import type KeyManager from '../../keys/KeyManager'; import type Logger from '@matrixai/logger'; import * as nodesUtils from '../../nodes/utils'; -import * as grpcErrors from '../../grpc/errors'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultsUtils from '../../vaults/utils'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; +import { matchSync } from '../../utils'; import * as agentErrors from '../errors'; +import * as agentUtils from '../utils'; function vaultsGitPackGet({ vaultManager, @@ -54,29 +56,36 @@ function vaultsGitPackGet({ } const nodeId = connectionInfo.remoteNodeId; const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); - // Getting vaultId - const vaultNameOrId = meta.get('vaultNameOrId').pop()!.toString(); - if (vaultNameOrId == null) { - throw new grpcErrors.ErrorGRPC('vault-name not in metadata'); - } await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - vaultNameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + meta.get('vaultNameOrId').pop()!.toString() as VaultName, tran, ); - vaultId = vaultId ?? vaultsUtils.decodeVaultId(vaultNameOrId); - if (vaultId == null) { - // Throwing permission error to hide information about vaults existence - throw new vaultsErrors.ErrorVaultsPermissionDenied( - `No permissions found for ${nodeIdEncoded}`, - ); - } + const { + vaultId, + actionType, + }: { + vaultId: VaultId; + actionType: VaultAction; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + [['actionType'], () => validationUtils.parseVaultAction(value)], + () => value, + ); + }, + { + vaultId: meta.get('vaultNameOrId').pop(), + actionType: meta.get('vaultAction').pop(), + }, + ); // Checking permissions const permissions = await acl.getNodePerm(nodeId, tran); const vaultPerms = permissions?.vaults[vaultId]; - const actionType = validationUtils.parseVaultAction( - meta.get('vaultAction').pop(), - ); if (vaultPerms?.[actionType] !== null) { throw new vaultsErrors.ErrorVaultsPermissionDenied( `${nodeIdEncoded} does not have permission to ${actionType} from vault ${vaultsUtils.encodeVaultId( @@ -110,9 +119,15 @@ function vaultsGitPackGet({ }); }); await genDuplex.next(null); + return; } catch (e) { await genDuplex.throw(e); - logger.error(e); + !agentUtils.isClientError(e, [ + agentErrors.ErrorConnectionInfoMissing, + vaultsErrors.ErrorVaultsPermissionDenied, + vaultsErrors.ErrorVaultsVaultUndefined, + ]) && logger.error(e); + return; } }; } diff --git a/src/agent/service/vaultsScan.ts b/src/agent/service/vaultsScan.ts index 2fd04d5e5..42e6ca8eb 100644 --- a/src/agent/service/vaultsScan.ts +++ b/src/agent/service/vaultsScan.ts @@ -5,9 +5,11 @@ import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type { ConnectionInfoGet } from '../../agent/types'; import type Logger from '@matrixai/logger'; import * as agentErrors from '../../agent/errors'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import * as vaultsUtils from '../../vaults/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as agentUtils from '../utils'; function vaultsScan({ vaultManager, @@ -48,9 +50,14 @@ function vaultsScan({ } }); await genWritable.next(null); + return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !agentUtils.isClientError(e, [ + agentErrors.ErrorConnectionInfoMissing, + vaultsErrors.ErrorVaultsPermissionDenied, + ]) && logger.error(e); + return; } }; } diff --git a/src/agent/utils.ts b/src/agent/utils.ts index f38e540d5..94b7d97d5 100644 --- a/src/agent/utils.ts +++ b/src/agent/utils.ts @@ -1,7 +1,17 @@ +import type { ServerSurfaceCall } from '@grpc/grpc-js/build/src/server-call'; +import type { Class } from '@matrixai/errors'; import type { Host, Port } from 'network/types'; import type Proxy from 'network/Proxy'; import type { ConnectionInfoGet } from './types'; -import type { ServerSurfaceCall } from '@grpc/grpc-js/build/src/server-call'; +import * as validationErrors from '../validation/errors'; + +/** + * Array of errors that are always considered to be "client errors" + * (4xx errors in HTTP) in the context of the agent service + */ +const defaultClientErrors: Array> = [ + validationErrors.ErrorValidation, +]; function connectionInfoGetter(proxy: Proxy): ConnectionInfoGet { return (call: ServerSurfaceCall) => { @@ -15,4 +25,27 @@ function connectionInfoGetter(proxy: Proxy): ConnectionInfoGet { }; } -export { connectionInfoGetter }; +/** + * Checks whether an error is a "client error" (4xx errors in HTTP) + * Used by the service handlers since client errors should not be + * reported on the server side + * Additional errors that are considered to be client errors in the + * context of a given handler can be supplied in the `extraClientErrors` + * argument + */ +function isClientError( + e: Error, + extraClientErrors?: Array>, +): boolean { + for (const error of defaultClientErrors) { + if (e instanceof error) return true; + } + if (extraClientErrors) { + for (const error of extraClientErrors) { + if (e instanceof error) return true; + } + } + return false; +} + +export { connectionInfoGetter, isClientError }; diff --git a/src/client/service/agentLockAll.ts b/src/client/service/agentLockAll.ts index 1bc011b08..90ad0a93a 100644 --- a/src/client/service/agentLockAll.ts +++ b/src/client/service/agentLockAll.ts @@ -5,6 +5,7 @@ import type { SessionManager } from '../../sessions'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function agentLockAll({ authenticate, @@ -32,7 +33,7 @@ function agentLockAll({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/agentStatus.ts b/src/client/service/agentStatus.ts index ecac4e1c1..52d14144a 100644 --- a/src/client/service/agentStatus.ts +++ b/src/client/service/agentStatus.ts @@ -9,6 +9,7 @@ import process from 'process'; import * as grpcUtils from '../../grpc/utils'; import * as nodesUtils from '../../nodes/utils'; import * as agentPB from '../../proto/js/polykey/v1/agent/agent_pb'; +import * as clientUtils from '../utils'; function agentStatus({ authenticate, @@ -49,7 +50,7 @@ function agentStatus({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/agentStop.ts b/src/client/service/agentStop.ts index f359036b8..a745887e5 100644 --- a/src/client/service/agentStop.ts +++ b/src/client/service/agentStop.ts @@ -5,6 +5,7 @@ import type Logger from '@matrixai/logger'; import { status, running } from '@matrixai/async-init'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function agentStop({ authenticate, @@ -32,7 +33,7 @@ function agentStop({ callback(null, response); } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } // Stop is called after GRPC resources are cleared diff --git a/src/client/service/agentUnlock.ts b/src/client/service/agentUnlock.ts index 1814eb81a..1f726792d 100644 --- a/src/client/service/agentUnlock.ts +++ b/src/client/service/agentUnlock.ts @@ -3,6 +3,7 @@ import type { Authenticate } from '../types'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function agentUnlock({ authenticate, @@ -23,7 +24,7 @@ function agentUnlock({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsGetByIdentity.ts b/src/client/service/gestaltsActionsGetByIdentity.ts index a1ee40c4a..bd0d8ba04 100644 --- a/src/client/service/gestaltsActionsGetByIdentity.ts +++ b/src/client/service/gestaltsActionsGetByIdentity.ts @@ -8,9 +8,9 @@ import type * as identitiesPB from '../../proto/js/polykey/v1/identities/identit import { matchSync } from '../../utils/matchers'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; -import * as validationErrors from '../../validation/errors'; import * as grpcUtils from '../../grpc/utils'; import * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; +import * as clientUtils from '../utils'; function gestaltsActionsGetByIdentity({ authenticate, @@ -63,9 +63,7 @@ function gestaltsActionsGetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - if (!(e instanceof validationErrors.ErrorValidation)) { - logger.error(e); - } + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsGetByNode.ts b/src/client/service/gestaltsActionsGetByNode.ts index 77ad8360a..11187384b 100644 --- a/src/client/service/gestaltsActionsGetByNode.ts +++ b/src/client/service/gestaltsActionsGetByNode.ts @@ -10,6 +10,7 @@ import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as permissionsPB from '../../proto/js/polykey/v1/permissions/permissions_pb'; +import * as clientUtils from '../utils'; function gestaltsActionsGetByNode({ authenticate, @@ -56,7 +57,7 @@ function gestaltsActionsGetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsSetByIdentity.ts b/src/client/service/gestaltsActionsSetByIdentity.ts index b0975d562..3776bbebb 100644 --- a/src/client/service/gestaltsActionsSetByIdentity.ts +++ b/src/client/service/gestaltsActionsSetByIdentity.ts @@ -9,8 +9,10 @@ import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; +import * as gestaltsErrors from '../../gestalts/errors'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function gestaltsActionsSetByIdentity({ authenticate, @@ -66,7 +68,10 @@ function gestaltsActionsSetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, + gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsSetByNode.ts b/src/client/service/gestaltsActionsSetByNode.ts index 917e3b198..91cef278f 100644 --- a/src/client/service/gestaltsActionsSetByNode.ts +++ b/src/client/service/gestaltsActionsSetByNode.ts @@ -9,8 +9,10 @@ import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; +import * as gestaltsErrors from '../../gestalts/errors'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function gestaltsActionsSetByNode({ authenticate, @@ -52,7 +54,9 @@ function gestaltsActionsSetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsUnsetByIdentity.ts b/src/client/service/gestaltsActionsUnsetByIdentity.ts index cb976d117..1b20a5610 100644 --- a/src/client/service/gestaltsActionsUnsetByIdentity.ts +++ b/src/client/service/gestaltsActionsUnsetByIdentity.ts @@ -9,8 +9,10 @@ import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; +import * as gestaltsErrors from '../../gestalts/errors'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function gestaltsActionsUnsetByIdentity({ authenticate, @@ -66,7 +68,10 @@ function gestaltsActionsUnsetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, + gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsUnsetByNode.ts b/src/client/service/gestaltsActionsUnsetByNode.ts index 2bc5d410f..1f06d2c64 100644 --- a/src/client/service/gestaltsActionsUnsetByNode.ts +++ b/src/client/service/gestaltsActionsUnsetByNode.ts @@ -9,8 +9,10 @@ import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; +import * as gestaltsErrors from '../../gestalts/errors'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function gestaltsActionsUnsetByNode({ authenticate, @@ -52,7 +54,9 @@ function gestaltsActionsUnsetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsDiscoveryByIdentity.ts b/src/client/service/gestaltsDiscoveryByIdentity.ts index 9834d4e7c..b63bb83bf 100644 --- a/src/client/service/gestaltsDiscoveryByIdentity.ts +++ b/src/client/service/gestaltsDiscoveryByIdentity.ts @@ -9,6 +9,7 @@ import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; import * as validationUtils from '../../validation/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function gestaltsDiscoveryByIdentity({ authenticate, @@ -51,7 +52,7 @@ function gestaltsDiscoveryByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsDiscoveryByNode.ts b/src/client/service/gestaltsDiscoveryByNode.ts index ed8ab18e6..b37bd777c 100644 --- a/src/client/service/gestaltsDiscoveryByNode.ts +++ b/src/client/service/gestaltsDiscoveryByNode.ts @@ -9,6 +9,7 @@ import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; import * as validationUtils from '../../validation/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function gestaltsDiscoveryByNode({ authenticate, @@ -47,7 +48,7 @@ function gestaltsDiscoveryByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltGetByIdentity.ts b/src/client/service/gestaltsGestaltGetByIdentity.ts index 4e4a25d78..9396c3d6d 100644 --- a/src/client/service/gestaltsGestaltGetByIdentity.ts +++ b/src/client/service/gestaltsGestaltGetByIdentity.ts @@ -10,6 +10,7 @@ import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; +import * as clientUtils from '../utils'; function gestaltsGestaltGetByIdentity({ authenticate, @@ -59,7 +60,7 @@ function gestaltsGestaltGetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltGetByNode.ts b/src/client/service/gestaltsGestaltGetByNode.ts index 28fc02c3f..2fbbb8447 100644 --- a/src/client/service/gestaltsGestaltGetByNode.ts +++ b/src/client/service/gestaltsGestaltGetByNode.ts @@ -10,6 +10,7 @@ import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; +import * as clientUtils from '../utils'; function gestaltsGestaltGetByNode({ authenticate, @@ -55,7 +56,7 @@ function gestaltsGestaltGetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltList.ts b/src/client/service/gestaltsGestaltList.ts index bb96dd53a..cbe2e0027 100644 --- a/src/client/service/gestaltsGestaltList.ts +++ b/src/client/service/gestaltsGestaltList.ts @@ -7,6 +7,7 @@ import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; +import * as clientUtils from '../utils'; function gestaltsGestaltList({ authenticate, @@ -39,7 +40,7 @@ function gestaltsGestaltList({ return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltTrustByIdentity.ts b/src/client/service/gestaltsGestaltTrustByIdentity.ts index 71368e7fb..9fc7c4911 100644 --- a/src/client/service/gestaltsGestaltTrustByIdentity.ts +++ b/src/client/service/gestaltsGestaltTrustByIdentity.ts @@ -9,8 +9,10 @@ import type Logger from '@matrixai/logger'; import { validateSync } from '../../validation'; import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; +import * as gestaltsErrors from '../../gestalts/errors'; import * as validationUtils from '../../validation/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function gestaltsGestaltTrustByIdentity({ authenticate, @@ -82,7 +84,10 @@ function gestaltsGestaltTrustByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, + gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltTrustByNode.ts b/src/client/service/gestaltsGestaltTrustByNode.ts index 097a94b07..9be7fa628 100644 --- a/src/client/service/gestaltsGestaltTrustByNode.ts +++ b/src/client/service/gestaltsGestaltTrustByNode.ts @@ -9,9 +9,11 @@ import type Logger from '@matrixai/logger'; import { validateSync } from '../../validation'; import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; +import * as gestaltsErrors from '../../gestalts/errors'; import * as validationUtils from '../../validation/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import * as nodesUtils from '../../nodes/utils'; +import * as clientUtils from '../utils'; function gestaltsGestaltTrustByNode({ authenticate, @@ -69,7 +71,9 @@ function gestaltsGestaltTrustByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesAuthenticate.ts b/src/client/service/identitiesAuthenticate.ts index 05c3e05d3..9aa0927e0 100644 --- a/src/client/service/identitiesAuthenticate.ts +++ b/src/client/service/identitiesAuthenticate.ts @@ -9,6 +9,7 @@ import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync, never } from '../../utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import * as clientUtils from '../utils'; function identitiesAuthenticate({ authenticate, @@ -74,7 +75,8 @@ function identitiesAuthenticate({ return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !clientUtils.isClientError(e, [identitiesErrors.ErrorProviderMissing]) && + logger.error(e); return; } }; diff --git a/src/client/service/identitiesAuthenticatedGet.ts b/src/client/service/identitiesAuthenticatedGet.ts index 82262f89d..64d0d7232 100644 --- a/src/client/service/identitiesAuthenticatedGet.ts +++ b/src/client/service/identitiesAuthenticatedGet.ts @@ -8,6 +8,7 @@ import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; import * as validationUtils from '../../validation/utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import * as clientUtils from '../utils'; function identitiesAuthenticatedGet({ authenticate, @@ -63,7 +64,7 @@ function identitiesAuthenticatedGet({ return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesClaim.ts b/src/client/service/identitiesClaim.ts index 43919bd45..884a5ca1c 100644 --- a/src/client/service/identitiesClaim.ts +++ b/src/client/service/identitiesClaim.ts @@ -14,6 +14,7 @@ import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import * as clientUtils from '../utils'; /** * Augments the keynode with a new identity. @@ -92,7 +93,10 @@ function identitiesClaim({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + identitiesErrors.ErrorProviderMissing, + identitiesErrors.ErrorProviderUnauthenticated, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesInfoConnectedGet.ts b/src/client/service/identitiesInfoConnectedGet.ts index b9d7ac441..7ac96810c 100644 --- a/src/client/service/identitiesInfoConnectedGet.ts +++ b/src/client/service/identitiesInfoConnectedGet.ts @@ -13,6 +13,7 @@ import * as grpcUtils from '../../grpc/utils'; import * as validationUtils from '../../validation/utils'; import * as identitiesErrors from '../../identities/errors'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import * as clientUtils from '../utils'; function identitiesInfoConnectedGet({ authenticate, @@ -119,7 +120,11 @@ function identitiesInfoConnectedGet({ return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !clientUtils.isClientError(e, [ + identitiesErrors.ErrorProviderMissing, + identitiesErrors.ErrorProviderUnauthenticated, + identitiesErrors.ErrorProviderUnimplemented, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesInfoGet.ts b/src/client/service/identitiesInfoGet.ts index 5f456dac5..bd29cf2f3 100644 --- a/src/client/service/identitiesInfoGet.ts +++ b/src/client/service/identitiesInfoGet.ts @@ -14,6 +14,7 @@ import * as validationUtils from '../../validation/utils'; import * as identitiesUtils from '../../identities/utils'; import * as identitiesErrors from '../../identities/errors'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import * as clientUtils from '../utils'; function identitiesInfoGet({ authenticate, @@ -112,7 +113,10 @@ function identitiesInfoGet({ return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !clientUtils.isClientError(e, [ + identitiesErrors.ErrorProviderMissing, + identitiesErrors.ErrorProviderUnauthenticated, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesProvidersList.ts b/src/client/service/identitiesProvidersList.ts index 35751c3fb..cd451d2f9 100644 --- a/src/client/service/identitiesProvidersList.ts +++ b/src/client/service/identitiesProvidersList.ts @@ -5,6 +5,7 @@ import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import * as clientUtils from '../utils'; function identitiesProvidersList({ authenticate, @@ -29,7 +30,7 @@ function identitiesProvidersList({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesTokenDelete.ts b/src/client/service/identitiesTokenDelete.ts index 82d0d57d5..9abe9d624 100644 --- a/src/client/service/identitiesTokenDelete.ts +++ b/src/client/service/identitiesTokenDelete.ts @@ -10,6 +10,7 @@ import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function identitiesTokenDelete({ authenticate, @@ -56,7 +57,7 @@ function identitiesTokenDelete({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesTokenGet.ts b/src/client/service/identitiesTokenGet.ts index 09199866d..193cf2553 100644 --- a/src/client/service/identitiesTokenGet.ts +++ b/src/client/service/identitiesTokenGet.ts @@ -9,6 +9,7 @@ import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; +import * as clientUtils from '../utils'; function identitiesTokenGet({ authenticate, @@ -56,7 +57,7 @@ function identitiesTokenGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesTokenPut.ts b/src/client/service/identitiesTokenPut.ts index 336f1646a..c06ad8106 100644 --- a/src/client/service/identitiesTokenPut.ts +++ b/src/client/service/identitiesTokenPut.ts @@ -10,6 +10,7 @@ import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function identitiesTokenPut({ authenticate, @@ -66,7 +67,7 @@ function identitiesTokenPut({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysCertsChainGet.ts b/src/client/service/keysCertsChainGet.ts index 6290a313c..94418b7b6 100644 --- a/src/client/service/keysCertsChainGet.ts +++ b/src/client/service/keysCertsChainGet.ts @@ -5,6 +5,7 @@ import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; +import * as clientUtils from '../utils'; function keysCertsChainGet({ authenticate, @@ -33,7 +34,7 @@ function keysCertsChainGet({ return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysCertsGet.ts b/src/client/service/keysCertsGet.ts index eabde463b..da8792aa1 100644 --- a/src/client/service/keysCertsGet.ts +++ b/src/client/service/keysCertsGet.ts @@ -5,6 +5,7 @@ import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; +import * as clientUtils from '../utils'; function keysCertsGet({ authenticate, @@ -29,7 +30,7 @@ function keysCertsGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysDecrypt.ts b/src/client/service/keysDecrypt.ts index ed1776cda..092e7f67b 100644 --- a/src/client/service/keysDecrypt.ts +++ b/src/client/service/keysDecrypt.ts @@ -4,6 +4,7 @@ import type KeyManager from '../../keys/KeyManager'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; +import * as clientUtils from '../utils'; function keysDecrypt({ authenticate, @@ -30,7 +31,7 @@ function keysDecrypt({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysEncrypt.ts b/src/client/service/keysEncrypt.ts index 35159f870..df8f4ff62 100644 --- a/src/client/service/keysEncrypt.ts +++ b/src/client/service/keysEncrypt.ts @@ -4,6 +4,7 @@ import type KeyManager from '../../keys/KeyManager'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; +import * as clientUtils from '../utils'; function keysEncrypt({ authenticate, @@ -30,7 +31,7 @@ function keysEncrypt({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysKeyPairRenew.ts b/src/client/service/keysKeyPairRenew.ts index dcd90d7c1..3660c9bc5 100644 --- a/src/client/service/keysKeyPairRenew.ts +++ b/src/client/service/keysKeyPairRenew.ts @@ -5,6 +5,7 @@ import type * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function keysKeyPairRenew({ authenticate, @@ -30,7 +31,7 @@ function keysKeyPairRenew({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysKeyPairReset.ts b/src/client/service/keysKeyPairReset.ts index 87498f733..3d04f12aa 100644 --- a/src/client/service/keysKeyPairReset.ts +++ b/src/client/service/keysKeyPairReset.ts @@ -5,6 +5,7 @@ import type * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function keysKeyPairReset({ authenticate, @@ -30,7 +31,7 @@ function keysKeyPairReset({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysKeyPairRoot.ts b/src/client/service/keysKeyPairRoot.ts index 7bfc95549..ad1eb3e5a 100644 --- a/src/client/service/keysKeyPairRoot.ts +++ b/src/client/service/keysKeyPairRoot.ts @@ -5,6 +5,7 @@ import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; +import * as clientUtils from '../utils'; function keysKeyPairRoot({ authenticate, @@ -30,7 +31,7 @@ function keysKeyPairRoot({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysPasswordChange.ts b/src/client/service/keysPasswordChange.ts index 639e60ac9..b96a44ca1 100644 --- a/src/client/service/keysPasswordChange.ts +++ b/src/client/service/keysPasswordChange.ts @@ -5,6 +5,7 @@ import type * as sessionsPB from '../../proto/js/polykey/v1/sessions/sessions_pb import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function keysPasswordChange({ authenticate, @@ -28,7 +29,7 @@ function keysPasswordChange({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysSign.ts b/src/client/service/keysSign.ts index b998e0561..bae99915f 100644 --- a/src/client/service/keysSign.ts +++ b/src/client/service/keysSign.ts @@ -4,6 +4,7 @@ import type KeyManager from '../../keys/KeyManager'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; +import * as clientUtils from '../utils'; function keysSign({ authenticate, @@ -31,7 +32,7 @@ function keysSign({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysVerify.ts b/src/client/service/keysVerify.ts index efbfb7b4c..a7cfaae3a 100644 --- a/src/client/service/keysVerify.ts +++ b/src/client/service/keysVerify.ts @@ -5,6 +5,7 @@ import type * as keysPB from '../../proto/js/polykey/v1/keys/keys_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function keysVerify({ authenticate, @@ -32,7 +33,7 @@ function keysVerify({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/nodesAdd.ts b/src/client/service/nodesAdd.ts index 1433e0896..8c089ff0b 100644 --- a/src/client/service/nodesAdd.ts +++ b/src/client/service/nodesAdd.ts @@ -11,6 +11,7 @@ import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; /** * Adds a node ID -> node address mapping into the buckets database. @@ -73,7 +74,7 @@ function nodesAdd({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/nodesClaim.ts b/src/client/service/nodesClaim.ts index 4d9cdc783..4022e10c7 100644 --- a/src/client/service/nodesClaim.ts +++ b/src/client/service/nodesClaim.ts @@ -9,8 +9,10 @@ import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; +import * as nodesErrors from '../../nodes/errors'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; /** * Checks whether there is an existing Gestalt Invitation from the other node. @@ -75,7 +77,9 @@ function nodesClaim({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + nodesErrors.ErrorNodeGraphNodeIdNotFound, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/nodesFind.ts b/src/client/service/nodesFind.ts index 284e50748..4826f9d96 100644 --- a/src/client/service/nodesFind.ts +++ b/src/client/service/nodesFind.ts @@ -4,11 +4,13 @@ import type NodeConnectionManager from '../../nodes/NodeConnectionManager'; import type { NodeId } from '../../nodes/types'; import type Logger from '@matrixai/logger'; import * as nodesUtils from '../../nodes/utils'; +import * as nodesErrors from '../../nodes/errors'; import * as grpcUtils from '../../grpc/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import { matchSync } from '../../utils'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import * as clientUtils from '../utils'; /** * Attempts to get the node address of a provided node ID (by contacting @@ -57,7 +59,9 @@ function nodesFind({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + nodesErrors.ErrorNodeGraphNodeIdNotFound, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/nodesPing.ts b/src/client/service/nodesPing.ts index 449905cc7..f86c8c1fa 100644 --- a/src/client/service/nodesPing.ts +++ b/src/client/service/nodesPing.ts @@ -7,8 +7,10 @@ import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; +import * as nodesErrors from '../../nodes/errors'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; /** * Checks if a remote node is online. @@ -51,7 +53,9 @@ function nodesPing({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + nodesErrors.ErrorNodeGraphNodeIdNotFound, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/notificationsClear.ts b/src/client/service/notificationsClear.ts index 56b2fabef..8d1d501c1 100644 --- a/src/client/service/notificationsClear.ts +++ b/src/client/service/notificationsClear.ts @@ -5,6 +5,7 @@ import type NotificationsManager from '../../notifications/NotificationsManager' import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function notificationsClear({ authenticate, @@ -32,7 +33,7 @@ function notificationsClear({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/notificationsRead.ts b/src/client/service/notificationsRead.ts index 63b94438d..60d55b7c7 100644 --- a/src/client/service/notificationsRead.ts +++ b/src/client/service/notificationsRead.ts @@ -5,6 +5,7 @@ import type NotificationsManager from '../../notifications/NotificationsManager' import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as notificationsPB from '../../proto/js/polykey/v1/notifications/notifications_pb'; +import * as clientUtils from '../utils'; function notificationsRead({ authenticate, @@ -74,7 +75,7 @@ function notificationsRead({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/notificationsSend.ts b/src/client/service/notificationsSend.ts index 4ff96fea6..c592aa476 100644 --- a/src/client/service/notificationsSend.ts +++ b/src/client/service/notificationsSend.ts @@ -8,8 +8,10 @@ import * as grpcUtils from '../../grpc/utils'; import * as notificationsUtils from '../../notifications/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; +import * as nodesErrors from '../../nodes/errors'; import { matchSync } from '../../utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as clientUtils from '../utils'; function notificationsSend({ authenticate, @@ -54,7 +56,9 @@ function notificationsSend({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + nodesErrors.ErrorNodeGraphNodeIdNotFound, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsClone.ts b/src/client/service/vaultsClone.ts index bd3693c5c..4e931e551 100644 --- a/src/client/service/vaultsClone.ts +++ b/src/client/service/vaultsClone.ts @@ -1,13 +1,20 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; +import type { VaultId } from '../../vaults/types'; +import type { NodeId } from '../../nodes/types'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import * as nodesErrors from '../../nodes/errors'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as vaultsUtils from '../../vaults/utils'; +import * as vaultsErrors from '../../vaults/errors'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsClone({ authenticate, @@ -28,24 +35,25 @@ function vaultsClone({ const response = new utilsPB.StatusMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - - const vaultMessage = call.request.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nodeMessage = call.request.getNode(); - if (nodeMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - // Vault id - let vaultId; - const vaultNameOrId = vaultMessage.getNameOrId(); - vaultId = vaultsUtils.decodeVaultId(vaultNameOrId); - vaultId = vaultId ?? vaultNameOrId; - // Node id - const nodeId = validationUtils.parseNodeId(nodeMessage.getNodeId()); + const { + nodeId, + vaultId, + }: { + nodeId: NodeId; + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [['nodeId'], () => validationUtils.parseNodeId(value)], + [['vaultId'], () => vaultsUtils.decodeVaultId(value) ?? value], + () => value, + ); + }, + { + nodeId: call.request.getNode()?.getNodeId(), + vaultId: call.request.getVault()?.getNameOrId(), + }, + ); await db.withTransactionF(async (tran) => vaultManager.cloneVault(nodeId, vaultId, tran), ); @@ -54,7 +62,10 @@ function vaultsClone({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + nodesErrors.ErrorNodeGraphNodeIdNotFound, + vaultsErrors.ErrorVaultsNameConflict, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsCreate.ts b/src/client/service/vaultsCreate.ts index a739604e7..4175a7de0 100644 --- a/src/client/service/vaultsCreate.ts +++ b/src/client/service/vaultsCreate.ts @@ -7,7 +7,9 @@ import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsUtils from '../../vaults/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import * as clientUtils from '../utils'; function vaultsCreate({ authenticate, @@ -37,7 +39,8 @@ function vaultsCreate({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [vaultsErrors.ErrorVaultsVaultDefined]) && + logger.error(e); return; } }; diff --git a/src/client/service/vaultsDelete.ts b/src/client/service/vaultsDelete.ts index 7a87f2da0..6aea1c1c0 100644 --- a/src/client/service/vaultsDelete.ts +++ b/src/client/service/vaultsDelete.ts @@ -1,5 +1,5 @@ import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; import type { DB } from '@matrixai/db'; @@ -7,7 +7,11 @@ import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; +import * as vaultsErrors from '../../vaults/errors'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsDelete({ authenticate, @@ -24,18 +28,33 @@ function vaultsDelete({ call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData, ): Promise => { - const vaultMessage = call.request; try { const response = new utilsPB.StatusMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getNameOrId(), + }, + ); await vaultManager.destroyVault(vaultId, tran); }); response.setSuccess(true); @@ -43,7 +62,8 @@ function vaultsDelete({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [vaultsErrors.ErrorVaultsVaultUndefined]) && + logger.error(e); return; } }; diff --git a/src/client/service/vaultsList.ts b/src/client/service/vaultsList.ts index a4a618275..08646c59b 100644 --- a/src/client/service/vaultsList.ts +++ b/src/client/service/vaultsList.ts @@ -7,6 +7,7 @@ import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsUtils from '../../vaults/utils'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import * as clientUtils from '../utils'; function vaultsList({ authenticate, @@ -39,7 +40,7 @@ function vaultsList({ return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsLog.ts b/src/client/service/vaultsLog.ts index 367dd0a1e..88873dca5 100644 --- a/src/client/service/vaultsLog.ts +++ b/src/client/service/vaultsLog.ts @@ -1,13 +1,17 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; +import * as vaultsErrors from '../../vaults/errors'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsLog({ authenticate, @@ -27,23 +31,32 @@ function vaultsLog({ try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - // Getting the vault - const vaultsLogMessage = call.request; - const vaultMessage = vaultsLogMessage.getVault(); - if (vaultMessage == null) { - await genWritable.throw({ code: grpc.status.NOT_FOUND }); - return; - } - const nameOrId = vaultMessage.getNameOrId(); const log = await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + }, + ); // Getting the log - const depth = vaultsLogMessage.getLogDepth(); - let commitId: string | undefined = vaultsLogMessage.getCommitId(); + const depth = call.request.getLogDepth(); + let commitId: string | undefined = call.request.getCommitId(); commitId = commitId ? commitId : undefined; return await vaultManager.withVaults( [vaultId], @@ -67,7 +80,10 @@ function vaultsLog({ return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + vaultsErrors.ErrorVaultReferenceInvalid, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsPermissionGet.ts b/src/client/service/vaultsPermissionGet.ts index 8e62be35a..d612f5b8c 100644 --- a/src/client/service/vaultsPermissionGet.ts +++ b/src/client/service/vaultsPermissionGet.ts @@ -2,8 +2,7 @@ import type * as grpc from '@grpc/grpc-js'; import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; -import type { VaultName } from '../../vaults/types'; -import type { VaultActions } from '../../vaults/types'; +import type { VaultName, VaultId, VaultActions } from '../../vaults/types'; import type ACL from '../../acl/ACL'; import type { NodeId, NodeIdEncoded } from 'nodes/types'; import type Logger from '@matrixai/logger'; @@ -11,8 +10,11 @@ import { IdInternal } from '@matrixai/id'; import * as grpcUtils from '../../grpc/utils'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as nodesUtils from '../../nodes/utils'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsPermissionGet({ authenticate, @@ -32,18 +34,33 @@ function vaultsPermissionGet({ ): Promise => { const genWritable = grpcUtils.generatorWritable(call, false); try { - const vaultMessage = call.request; const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); // Getting vaultId - const nameOrId = vaultMessage.getNameOrId(); const [rawPermissions, vaultId] = await db.withTransactionF( async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getNameOrId(), + }, + ); // Getting permissions return [await acl.getVaultPerm(vaultId, tran), vaultId]; }, @@ -53,11 +70,9 @@ function vaultsPermissionGet({ for (const nodeId in rawPermissions) { permissionList[nodeId] = rawPermissions[nodeId].vaults[vaultId]; } - const vaultPermissionsMessage = new vaultsPB.Permissions(); - vaultPermissionsMessage.setVault(vaultMessage); + vaultPermissionsMessage.setVault(call.request); const nodeMessage = new nodesPB.Node(); - // Constructing the message for (const nodeIdString in permissionList) { const nodeId = IdInternal.fromString(nodeIdString); @@ -71,7 +86,7 @@ function vaultsPermissionGet({ return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !clientUtils.isClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsPermissionSet.ts b/src/client/service/vaultsPermissionSet.ts index f91ccd81f..335165ef7 100644 --- a/src/client/service/vaultsPermissionSet.ts +++ b/src/client/service/vaultsPermissionSet.ts @@ -1,19 +1,29 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { NodeId } from '../../nodes/types'; +import type { + VaultName, + VaultId, + VaultAction, + VaultActions, +} from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type ACL from '../../acl/ACL'; import type NotificationsManager from '../../notifications/NotificationsManager'; -import type { VaultActions } from '../../vaults/types'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; import * as vaultsUtils from '../../vaults/utils'; import * as vaultsErrors from '../../vaults/errors'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as aclErrors from '../../acl/errors'; +import * as nodesErrors from '../../nodes/errors'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsPermissionSet({ authenticate, @@ -40,27 +50,37 @@ function vaultsPermissionSet({ // Checking session token const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaultsPermissionsMessage = call.request; - const vaultMessage = vaultsPermissionsMessage.getVault(); - const nodeMessage = vaultsPermissionsMessage.getNode(); - if (vaultMessage == null || nodeMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } await db.withTransactionF(async (tran) => { - // Parsing VaultId - const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - // Parsing NodeId - const nodeId = validationUtils.parseNodeId(nodeMessage.getNodeId()); - // Parsing actions - const actions = vaultsPermissionsMessage - .getVaultPermissionsList() - .map((vaultAction) => validationUtils.parseVaultAction(vaultAction)); + const { + nodeId, + vaultId, + actions, + }: { + nodeId: NodeId; + vaultId: VaultId; + actions: Array; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [['nodeId'], () => validationUtils.parseNodeId(value)], + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + [['actions'], () => value.map(validationUtils.parseVaultAction)], + () => value, + ); + }, + { + nodeId: call.request.getNode()?.getNodeId(), + vaultId: call.request.getVault()?.getNameOrId(), + actions: call.request.getVaultPermissionsList(), + }, + ); // Checking if vault exists const vaultMeta = await vaultManager.getVaultMeta(vaultId, tran); if (!vaultMeta) throw new vaultsErrors.ErrorVaultsVaultUndefined(); @@ -85,7 +105,11 @@ function vaultsPermissionSet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + aclErrors.ErrorACLNodeIdMissing, + nodesErrors.ErrorNodeGraphNodeIdNotFound, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsPermissionUnset.ts b/src/client/service/vaultsPermissionUnset.ts index 8095e21c4..9b561b173 100644 --- a/src/client/service/vaultsPermissionUnset.ts +++ b/src/client/service/vaultsPermissionUnset.ts @@ -1,16 +1,21 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { NodeId } from '../../nodes/types'; +import type { VaultName, VaultId, VaultAction } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type ACL from '../../acl/ACL'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; import * as vaultsErrors from '../../vaults/errors'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as gestaltsErrors from '../../gestalts/errors'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsPermissionUnset({ authenticate, @@ -35,24 +40,37 @@ function vaultsPermissionUnset({ // Checking session token const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaultsPermissionsMessage = call.request; - const vaultMessage = vaultsPermissionsMessage.getVault(); - const nodeMessage = vaultsPermissionsMessage.getNode(); - if (vaultMessage == null || nodeMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } await db.withTransactionF(async (tran) => { - // Parsing VaultId - const nameOrId = vaultMessage.getNameOrId(); - let vaultId = await vaultManager.getVaultId(nameOrId as VaultName); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - // Parsing NodeId - const nodeId = validationUtils.parseNodeId(nodeMessage.getNodeId()); - // Parsing actions - const actions = vaultsPermissionsMessage - .getVaultPermissionsList() - .map((vaultAction) => validationUtils.parseVaultAction(vaultAction)); + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, + tran, + ); + const { + nodeId, + vaultId, + actions, + }: { + nodeId: NodeId; + vaultId: VaultId; + actions: Array; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [['nodeId'], () => validationUtils.parseNodeId(value)], + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + [['actions'], () => value.map(validationUtils.parseVaultAction)], + () => value, + ); + }, + { + nodeId: call.request.getNode()?.getNodeId(), + vaultId: call.request.getVault()?.getNameOrId(), + actions: call.request.getVaultPermissionsList(), + }, + ); // Checking if vault exists const vaultMeta = await vaultManager.getVaultMeta(vaultId, tran); if (!vaultMeta) throw new vaultsErrors.ErrorVaultsVaultUndefined(); @@ -81,7 +99,10 @@ function vaultsPermissionUnset({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsPull.ts b/src/client/service/vaultsPull.ts index f68a62903..c2e4342f6 100644 --- a/src/client/service/vaultsPull.ts +++ b/src/client/service/vaultsPull.ts @@ -1,14 +1,19 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; +import type { NodeId } from '../../nodes/types'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as vaultsUtils from '../../vaults/utils'; +import * as nodesErrors from '../../nodes/errors'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsPull({ authenticate, @@ -29,39 +34,47 @@ function vaultsPull({ const response = new utilsPB.StatusMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - - const vaultMessage = call.request.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - let nodeId; - const nodeMessage = call.request.getNode(); - if (nodeMessage == null) { - nodeId = null; - } else { - nodeId = validationUtils.parseNodeId(nodeMessage.getNodeId()); - } - let pullVault; - const pullVaultMessage = call.request.getPullVault(); - if (pullVaultMessage == null) { - pullVault = null; - } else { - pullVault = vaultsUtils.decodeVaultId(pullVaultMessage.getNameOrId()); - pullVault = pullVault ?? pullVaultMessage.getNameOrId(); - if (pullVault == null) pullVault = pullVaultMessage.getNameOrId(); - } + const { + vaultId, + nodeId, + pullVaultId, + }: { + vaultId: VaultId; + nodeId: NodeId | undefined; + pullVaultId: VaultId | VaultName | undefined; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + [ + ['nodeId'], + () => (value ? validationUtils.parseNodeId(value) : undefined), + ], + [ + ['pullVaultId'], + () => vaultsUtils.decodeVaultId(value) ?? value, + ], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + nodeId: call.request.getNode()?.getNodeId(), + pullVaultId: call.request.getPullVault()?.getNameOrId(), + }, + ); await vaultManager.pullVault({ vaultId, pullNodeId: nodeId, - pullVaultNameOrId: pullVault, + pullVaultNameOrId: pullVaultId, tran, }); }); @@ -70,7 +83,9 @@ function vaultsPull({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + nodesErrors.ErrorNodeGraphNodeIdNotFound, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsRename.ts b/src/client/service/vaultsRename.ts index 0689b2506..9647d7ef1 100644 --- a/src/client/service/vaultsRename.ts +++ b/src/client/service/vaultsRename.ts @@ -1,13 +1,17 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsUtils from '../../vaults/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsRename({ authenticate, @@ -28,27 +32,41 @@ function vaultsRename({ const response = new vaultsPB.Vault(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaultMessage = call.request.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + }, + ); const newName = call.request.getNewName() as VaultName; - await vaultManager.renameVault(vaultId, newName); + await vaultManager.renameVault(vaultId, newName, tran); response.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); }); callback(null, response); return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + vaultsErrors.ErrorVaultsVaultDefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsScan.ts b/src/client/service/vaultsScan.ts index f0392dba5..48556105e 100644 --- a/src/client/service/vaultsScan.ts +++ b/src/client/service/vaultsScan.ts @@ -7,8 +7,10 @@ import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; -import { matchSync } from '../../utils'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import * as nodesErrors from '../../nodes/errors'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsScan({ authenticate, @@ -56,7 +58,9 @@ function vaultsScan({ return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !clientUtils.isClientError(e, [ + nodesErrors.ErrorNodeGraphNodeIdNotFound, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsDelete.ts b/src/client/service/vaultsSecretsDelete.ts index 46784f9fe..86a9a77b0 100644 --- a/src/client/service/vaultsSecretsDelete.ts +++ b/src/client/service/vaultsSecretsDelete.ts @@ -1,14 +1,18 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsSecretsDelete({ authenticate, @@ -29,18 +33,29 @@ function vaultsSecretsDelete({ const response = new utilsPB.StatusMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaultMessage = call.request.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + }, + ); const secretName = call.request.getSecretName(); await vaultManager.withVaults( [vaultId], @@ -55,7 +70,10 @@ function vaultsSecretsDelete({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + vaultsErrors.ErrorSecretsSecretUndefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsEdit.ts b/src/client/service/vaultsSecretsEdit.ts index 897a6dd12..374b5d9dd 100644 --- a/src/client/service/vaultsSecretsEdit.ts +++ b/src/client/service/vaultsSecretsEdit.ts @@ -1,14 +1,18 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsSecretsEdit({ authenticate, @@ -29,25 +33,31 @@ function vaultsSecretsEdit({ const response = new utilsPB.StatusMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const secretMessage = call.request; - if (secretMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const vaultMessage = secretMessage.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - const secretName = secretMessage.getSecretName(); - const secretContent = Buffer.from(secretMessage.getSecretContent()); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + }, + ); + const secretName = call.request.getSecretName(); + const secretContent = Buffer.from(call.request.getSecretContent()); await vaultManager.withVaults( [vaultId], async (vault) => { @@ -61,7 +71,11 @@ function vaultsSecretsEdit({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + vaultsErrors.ErrorSecretsSecretUndefined, + vaultsErrors.ErrorVaultRemoteDefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsGet.ts b/src/client/service/vaultsSecretsGet.ts index cdb2a75fb..c5770db8e 100644 --- a/src/client/service/vaultsSecretsGet.ts +++ b/src/client/service/vaultsSecretsGet.ts @@ -1,14 +1,18 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsSecretsGet({ authenticate, @@ -29,18 +33,29 @@ function vaultsSecretsGet({ const response = new secretsPB.Secret(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaultMessage = call.request.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + }, + ); const secretName = call.request.getSecretName(); const secretContent = await vaultManager.withVaults( [vaultId], @@ -55,7 +70,10 @@ function vaultsSecretsGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + vaultsErrors.ErrorSecretsSecretUndefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsList.ts b/src/client/service/vaultsSecretsList.ts index 8056c7a90..b7c103cc7 100644 --- a/src/client/service/vaultsSecretsList.ts +++ b/src/client/service/vaultsSecretsList.ts @@ -1,14 +1,18 @@ import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; import type { DB } from '@matrixai/db'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsSecretsList({ authenticate, @@ -28,14 +32,29 @@ function vaultsSecretsList({ try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaultMessage = call.request; - const nameOrId = vaultMessage.getNameOrId(); const secrets = await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getNameOrId(), + }, + ); return await vaultManager.withVaults( [vaultId], async (vault) => { @@ -54,7 +73,8 @@ function vaultsSecretsList({ return; } catch (e) { await genWritable.throw(e); - logger.error(e); + !clientUtils.isClientError(e, [vaultsErrors.ErrorVaultsVaultUndefined]) && + logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsMkdir.ts b/src/client/service/vaultsSecretsMkdir.ts index f441207cc..eaa4e8324 100644 --- a/src/client/service/vaultsSecretsMkdir.ts +++ b/src/client/service/vaultsSecretsMkdir.ts @@ -1,14 +1,18 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsSecretsMkdir({ authenticate, @@ -29,24 +33,34 @@ function vaultsSecretsMkdir({ const response = new utilsPB.StatusMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaultMkdirMessge = call.request; - const vaultMessage = vaultMkdirMessge.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + }, + ); await vaultManager.withVaults( [vaultId], async (vault) => { - await vaultOps.mkdir(vault, vaultMkdirMessge.getDirName(), { - recursive: vaultMkdirMessge.getRecursive(), + await vaultOps.mkdir(vault, call.request.getDirName(), { + recursive: call.request.getRecursive(), }); }, tran, @@ -57,7 +71,10 @@ function vaultsSecretsMkdir({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + vaultsErrors.ErrorVaultsRecursive, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsNew.ts b/src/client/service/vaultsSecretsNew.ts index 0a6c1920c..d89064985 100644 --- a/src/client/service/vaultsSecretsNew.ts +++ b/src/client/service/vaultsSecretsNew.ts @@ -1,14 +1,18 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsSecretsNew({ authenticate, @@ -29,18 +33,29 @@ function vaultsSecretsNew({ const response = new utilsPB.StatusMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaultMessage = call.request.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + }, + ); const secret = call.request.getSecretName(); const content = Buffer.from(call.request.getSecretContent()); await vaultManager.withVaults( @@ -56,7 +71,10 @@ function vaultsSecretsNew({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + vaultsErrors.ErrorSecretsSecretUndefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsNewDir.ts b/src/client/service/vaultsSecretsNewDir.ts index daf151f58..6cc7ad0f8 100644 --- a/src/client/service/vaultsSecretsNewDir.ts +++ b/src/client/service/vaultsSecretsNewDir.ts @@ -1,15 +1,19 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type { FileSystem } from '../../types'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsSecretsNewDir({ authenticate, @@ -32,18 +36,29 @@ function vaultsSecretsNewDir({ const response = new utilsPB.StatusMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaultMessage = call.request.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + }, + ); const secretsPath = call.request.getSecretDirectory(); await vaultManager.withVaults( [vaultId], @@ -58,7 +73,8 @@ function vaultsSecretsNewDir({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [vaultsErrors.ErrorVaultsVaultUndefined]) && + logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsRename.ts b/src/client/service/vaultsSecretsRename.ts index fabe0512c..1b17420ff 100644 --- a/src/client/service/vaultsSecretsRename.ts +++ b/src/client/service/vaultsSecretsRename.ts @@ -1,14 +1,18 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsSecretsRename({ authenticate, @@ -29,24 +33,33 @@ function vaultsSecretsRename({ const response = new utilsPB.StatusMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const secretMessage = call.request.getOldSecret(); - if (!secretMessage) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const vaultMessage = secretMessage.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getOldSecret()?.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); - const oldSecret = secretMessage.getSecretName(); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getOldSecret()?.getVault()?.getNameOrId(), + }, + ); + const oldSecret = call.request.getOldSecret()?.getSecretName(); + if (oldSecret == null) { + throw new vaultsErrors.ErrorSecretsSecretUndefined(); + } const newSecret = call.request.getNewName(); await vaultManager.withVaults( [vaultId], @@ -61,7 +74,10 @@ function vaultsSecretsRename({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + vaultsErrors.ErrorSecretsSecretUndefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsStat.ts b/src/client/service/vaultsSecretsStat.ts index d30b1e20f..fc173fe4b 100644 --- a/src/client/service/vaultsSecretsStat.ts +++ b/src/client/service/vaultsSecretsStat.ts @@ -1,13 +1,17 @@ import type { DB } from '@matrixai/db'; import type VaultManager from '../../vaults/VaultManager'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type { Authenticate } from '../types'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsSecretsStat({ authenticate, @@ -28,18 +32,29 @@ function vaultsSecretsStat({ const response = new secretsPB.Stat(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaultMessage = call.request.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + }, + ); const secretName = call.request.getSecretName(); const stat = await vaultManager.withVaults( [vaultId], @@ -54,7 +69,10 @@ function vaultsSecretsStat({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + vaultsErrors.ErrorSecretsSecretUndefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsVersion.ts b/src/client/service/vaultsVersion.ts index 18868456b..7c755aa55 100644 --- a/src/client/service/vaultsVersion.ts +++ b/src/client/service/vaultsVersion.ts @@ -1,12 +1,16 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type Logger from '@matrixai/logger'; -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; +import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; +import { matchSync } from '../../utils'; +import * as clientUtils from '../utils'; function vaultsVersion({ authenticate, @@ -28,22 +32,31 @@ function vaultsVersion({ // Checking session token const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const vaultsVersionMessage = call.request; - // Getting vault ID - const vaultMessage = vaultsVersionMessage.getVault(); - if (vaultMessage == null) { - callback({ code: grpc.status.NOT_FOUND }, null); - return; - } - const nameOrId = vaultMessage.getNameOrId(); await db.withTransactionF(async (tran) => { - let vaultId = await vaultManager.getVaultId( - nameOrId as VaultName, + const vaultIdFromName = await vaultManager.getVaultId( + call.request.getVault()?.getNameOrId() as VaultName, tran, ); - vaultId = vaultId ?? validationUtils.parseVaultId(nameOrId); + const { + vaultId, + }: { + vaultId: VaultId; + } = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [ + ['vaultId'], + () => vaultIdFromName ?? validationUtils.parseVaultId(value), + ], + () => value, + ); + }, + { + vaultId: call.request.getVault()?.getNameOrId(), + }, + ); // Doing the deed - const versionId = vaultsVersionMessage.getVersionId(); + const versionId = call.request.getVersionId(); const [latestOid, currentVersionId] = await vaultManager.withVaults( [vaultId], async (vault) => { @@ -65,7 +78,11 @@ function vaultsVersion({ return; } catch (e) { callback(grpcUtils.fromError(e)); - logger.error(e); + !clientUtils.isClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + vaultsErrors.ErrorVaultReferenceInvalid, + vaultsErrors.ErrorVaultReferenceMissing, + ]) && logger.error(e); return; } }; diff --git a/src/client/utils/utils.ts b/src/client/utils/utils.ts index d49173a6f..b77ac0e76 100644 --- a/src/client/utils/utils.ts +++ b/src/client/utils/utils.ts @@ -3,6 +3,7 @@ import type { Interceptor, InterceptorOptions, } from '@grpc/grpc-js/build/src/client-interceptors'; +import type { Class } from '@matrixai/errors'; import type KeyManager from '../../keys/KeyManager'; import type Session from '../../sessions/Session'; import type SessionManager from '../../sessions/SessionManager'; @@ -10,8 +11,20 @@ import type { SessionToken } from '../../sessions/types'; import type { Authenticate } from '../types'; import * as base64 from 'multiformats/bases/base64'; import * as grpc from '@grpc/grpc-js'; +import * as validationErrors from '../../validation/errors'; import * as clientErrors from '../errors'; +/** + * Array of errors that are always considered to be "client errors" + * (4xx errors in HTTP) in the context of the client service + */ +const defaultClientErrors: Array> = [ + validationErrors.ErrorValidation, + clientErrors.ErrorClientAuthMissing, + clientErrors.ErrorClientAuthFormat, + clientErrors.ErrorClientAuthDenied, +]; + /** * Session interceptor middleware for authenticatio * Session token is read at the beginning of every call @@ -133,10 +146,34 @@ function decodeAuthToSession( return auth.substring(7) as SessionToken; } +/** + * Checks whether an error is a "client error" (4xx errors in HTTP) + * Used by the service handlers since client errors should not be + * reported on the server side + * Additional errors that are considered to be client errors in the + * context of a given handler can be supplied in the `extraClientErrors` + * argument + */ +function isClientError( + e: Error, + extraClientErrors?: Array>, +): boolean { + for (const error of defaultClientErrors) { + if (e instanceof error) return true; + } + if (extraClientErrors) { + for (const error of extraClientErrors) { + if (e instanceof error) return true; + } + } + return false; +} + export { sessionInterceptor, authenticator, encodeAuthFromPassword, encodeAuthFromSession, decodeAuthToSession, + isClientError, }; From 6efc9635932dca6bfa461f5c9a73432f747b01d0 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 3 Jun 2022 15:19:43 +1000 Subject: [PATCH 069/137] feat: updated `Opaque` usage --- src/types.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/types.ts b/src/types.ts index 8fba1fc08..fedc06923 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,7 +10,8 @@ type POJO = { [key: string]: any }; * Opaque types are wrappers of existing types * that require smart constructors */ -type Opaque = T & { __TYPE__: K }; +type Opaque = T & { readonly [brand]: K }; +declare const brand: unique symbol; /** * Non-empty array From a01c7eab36b3262db03177d07a8656d54b496ead Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 3 Jun 2022 15:42:49 +1000 Subject: [PATCH 070/137] feat: `promisify` utility now preserves typing info --- src/bin/polykey-agent.ts | 2 +- src/types.ts | 9 +++++++++ src/utils/utils.ts | 28 ++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/bin/polykey-agent.ts b/src/bin/polykey-agent.ts index de65ebc86..b9476b514 100644 --- a/src/bin/polykey-agent.ts +++ b/src/bin/polykey-agent.ts @@ -37,7 +37,7 @@ const logger = new Logger('polykey', undefined, [new StreamHandler()]); */ async function main(_argv = process.argv): Promise { const exitHandlers = new binUtils.ExitHandlers(); - const processSend = promisify(process.send!.bind(process)); + const processSend = promisify(process.send!.bind(process)); const { p: messageInP, resolveP: resolveMessageInP } = promise(); process.once('message', (data: AgentChildProcessInput) => { diff --git a/src/types.ts b/src/types.ts index fedc06923..161181b8d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -13,6 +13,14 @@ type POJO = { [key: string]: any }; type Opaque = T & { readonly [brand]: K }; declare const brand: unique symbol; +/** + * Generic callback + */ +type Callback

= [], R = any, E extends Error = Error> = { + (e: E, ...params: Partial

): R; + (e?: null | undefined, ...params: P): R; +}; + /** * Non-empty array */ @@ -81,6 +89,7 @@ type FileHandle = fs.promises.FileHandle; export type { POJO, Opaque, + Callback, NonEmptyArray, AbstractConstructorParameters, Initial, diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 6b4ca4759..4d837ecbf 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,4 +1,4 @@ -import type { FileSystem, Timer } from '../types'; +import type { FileSystem, Timer, Callback } from '../types'; import os from 'os'; import process from 'process'; import path from 'path'; @@ -138,18 +138,34 @@ async function poll( /** * Convert callback-style to promise-style + * If this is applied to overloaded function + * it will only choose one of the function signatures to use */ -function promisify(f): (...args: any[]) => Promise { - return function (...args): Promise { +function promisify< + T extends Array, + P extends Array, + R extends T extends [] ? void : T extends [unknown] ? T[0] : T, +>( + f: (...args: [...params: P, callback: Callback]) => unknown, +): (...params: P) => Promise { + // Uses a regular function so that `this` can be bound + return function (...params: P): Promise { return new Promise((resolve, reject) => { const callback = (error, ...values) => { if (error != null) { return reject(error); } - return resolve(values.length === 1 ? values[0] : values); + if (values.length === 0) { + (resolve as () => void)(); + } else if (values.length === 1) { + resolve(values[0] as R); + } else { + resolve(values as R); + } + return; }; - args.push(callback); - f.apply(this, args); + params.push(callback); + f.apply(this, params); }); }; } From 9730e5a6bac28a689e2e36f939a55681f9446f88 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Mon, 6 Jun 2022 12:17:40 +1000 Subject: [PATCH 071/137] fix: bug fixes in vaults service handlers --- src/agent/service/vaultsGitPackGet.ts | 7 ++++--- src/client/service/vaultsClone.ts | 18 ++++++++++-------- src/client/service/vaultsPull.ts | 16 +++++++++------- tests/bin/vaults/vaults.test.ts | 4 ++-- tests/vaults/VaultManager.test.ts | 3 ++- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/agent/service/vaultsGitPackGet.ts b/src/agent/service/vaultsGitPackGet.ts index e17cad29f..276cec84f 100644 --- a/src/agent/service/vaultsGitPackGet.ts +++ b/src/agent/service/vaultsGitPackGet.ts @@ -56,9 +56,10 @@ function vaultsGitPackGet({ } const nodeId = connectionInfo.remoteNodeId; const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); + const nameOrId = meta.get('vaultNameOrId').pop()!.toString(); await db.withTransactionF(async (tran) => { const vaultIdFromName = await vaultManager.getVaultId( - meta.get('vaultNameOrId').pop()!.toString() as VaultName, + nameOrId as VaultName, tran, ); const { @@ -79,8 +80,8 @@ function vaultsGitPackGet({ ); }, { - vaultId: meta.get('vaultNameOrId').pop(), - actionType: meta.get('vaultAction').pop(), + vaultId: nameOrId, + actionType: meta.get('vaultAction').pop()!.toString(), }, ); // Checking permissions diff --git a/src/client/service/vaultsClone.ts b/src/client/service/vaultsClone.ts index 4e931e551..fdefe5697 100644 --- a/src/client/service/vaultsClone.ts +++ b/src/client/service/vaultsClone.ts @@ -1,7 +1,7 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; -import type { VaultId } from '../../vaults/types'; +import type { VaultName, VaultId } from '../../vaults/types'; import type { NodeId } from '../../nodes/types'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; @@ -35,28 +35,30 @@ function vaultsClone({ const response = new utilsPB.StatusMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); + // Node id const { nodeId, - vaultId, }: { nodeId: NodeId; - vaultId: VaultId; } = validateSync( (keyPath, value) => { return matchSync(keyPath)( [['nodeId'], () => validationUtils.parseNodeId(value)], - [['vaultId'], () => vaultsUtils.decodeVaultId(value) ?? value], () => value, ); }, { nodeId: call.request.getNode()?.getNodeId(), - vaultId: call.request.getVault()?.getNameOrId(), }, ); - await db.withTransactionF(async (tran) => - vaultManager.cloneVault(nodeId, vaultId, tran), - ); + // Vault id + let vaultId; + const vaultNameOrId = call.request.getVault()?.getNameOrId(); + vaultId = vaultsUtils.decodeVaultId(vaultNameOrId); + vaultId = vaultId ?? vaultNameOrId; + await db.withTransactionF(async (tran) => { + await vaultManager.cloneVault(nodeId, vaultId, tran); + }); response.setSuccess(true); callback(null, response); return; diff --git a/src/client/service/vaultsPull.ts b/src/client/service/vaultsPull.ts index c2e4342f6..6f7d19106 100644 --- a/src/client/service/vaultsPull.ts +++ b/src/client/service/vaultsPull.ts @@ -34,6 +34,15 @@ function vaultsPull({ const response = new utilsPB.StatusMessage(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); + let pullVaultId; + const pullVaultMessage = call.request.getPullVault(); + if (pullVaultMessage == null) { + pullVaultId = null; + } else { + pullVaultId = vaultsUtils.decodeVaultId(pullVaultMessage.getNameOrId()); + pullVaultId = pullVaultId ?? pullVaultMessage.getNameOrId(); + if (pullVaultId == null) pullVaultId = pullVaultMessage.getNameOrId(); + } await db.withTransactionF(async (tran) => { const vaultIdFromName = await vaultManager.getVaultId( call.request.getVault()?.getNameOrId() as VaultName, @@ -42,11 +51,9 @@ function vaultsPull({ const { vaultId, nodeId, - pullVaultId, }: { vaultId: VaultId; nodeId: NodeId | undefined; - pullVaultId: VaultId | VaultName | undefined; } = validateSync( (keyPath, value) => { return matchSync(keyPath)( @@ -58,17 +65,12 @@ function vaultsPull({ ['nodeId'], () => (value ? validationUtils.parseNodeId(value) : undefined), ], - [ - ['pullVaultId'], - () => vaultsUtils.decodeVaultId(value) ?? value, - ], () => value, ); }, { vaultId: call.request.getVault()?.getNameOrId(), nodeId: call.request.getNode()?.getNodeId(), - pullVaultId: call.request.getPullVault()?.getNameOrId(), }, ); await vaultManager.pullVault({ diff --git a/tests/bin/vaults/vaults.test.ts b/tests/bin/vaults/vaults.test.ts index 52b5f4e4c..a8e6fa3df 100644 --- a/tests/bin/vaults/vaults.test.ts +++ b/tests/bin/vaults/vaults.test.ts @@ -342,8 +342,8 @@ describe('CLI vaults', () => { targetNodeIdEncoded, ]; result = await testBinUtils.pkStdio([...command], {}, dataDir); - expect(result.exitCode).toBe(sysexits.USAGE); - expect(result.stderr).toContain('ErrorVaultsVaultUndefined'); + expect(result.exitCode).toBe(sysexits.DATAERR); + expect(result.stderr).toContain('ErrorValidation'); command = [ 'vaults', diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index e4ed618aa..c62824b1d 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -23,6 +23,7 @@ import KeyManager from '@/keys/KeyManager'; import PolykeyAgent from '@/PolykeyAgent'; import VaultManager from '@/vaults/VaultManager'; import * as vaultsErrors from '@/vaults/errors'; +import * as validationErrors from '@/validation/errors'; import NodeGraph from '@/nodes/NodeGraph'; import * as nodesUtils from '@/nodes/utils'; import Proxy from '@/network/Proxy'; @@ -743,7 +744,7 @@ describe('VaultManager', () => { remoteKeynode1Id, 'not-existing' as VaultName, ), - vaultsErrors.ErrorVaultsVaultUndefined, + validationErrors.ErrorValidation, ); } finally { await vaultManager?.stop(); From 9c2bdea024ddbf39db514c73ff1e48438194f5be Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Mon, 6 Jun 2022 12:24:56 +1000 Subject: [PATCH 072/137] style: lint fix --- src/client/service/vaultsClone.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/client/service/vaultsClone.ts b/src/client/service/vaultsClone.ts index fdefe5697..86129010d 100644 --- a/src/client/service/vaultsClone.ts +++ b/src/client/service/vaultsClone.ts @@ -1,7 +1,6 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; -import type { VaultName, VaultId } from '../../vaults/types'; import type { NodeId } from '../../nodes/types'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; From 4cd91b220cb88ee7617e7879743c8206e30c45bb Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Mon, 6 Jun 2022 14:53:12 +1000 Subject: [PATCH 073/137] fix: service handlers check for client error chains Sometimes an error is only considered a client error when part of the chain of another error (for example ErrorPolykeyRemote) so it is now possible to specify this array. #304 --- src/agent/service/nodesChainDataGet.ts | 2 +- .../service/nodesClosestLocalNodesGet.ts | 2 +- src/agent/service/nodesCrossSignClaim.ts | 2 +- .../service/nodesHolePunchMessageSend.ts | 2 +- src/agent/service/notificationsSend.ts | 2 +- src/agent/service/vaultsGitInfoGet.ts | 17 +++--- src/agent/service/vaultsGitPackGet.ts | 15 ++--- src/agent/service/vaultsScan.ts | 2 +- src/agent/types.ts | 10 +++- src/agent/utils.ts | 56 +++++++++++++++---- src/client/service/agentLockAll.ts | 2 +- src/client/service/agentStatus.ts | 2 +- src/client/service/agentStop.ts | 2 +- src/client/service/agentUnlock.ts | 2 +- .../service/gestaltsActionsGetByIdentity.ts | 2 +- .../service/gestaltsActionsGetByNode.ts | 2 +- .../service/gestaltsActionsSetByIdentity.ts | 2 +- .../service/gestaltsActionsSetByNode.ts | 2 +- .../service/gestaltsActionsUnsetByIdentity.ts | 2 +- .../service/gestaltsActionsUnsetByNode.ts | 2 +- .../service/gestaltsDiscoveryByIdentity.ts | 2 +- src/client/service/gestaltsDiscoveryByNode.ts | 2 +- .../service/gestaltsGestaltGetByIdentity.ts | 2 +- .../service/gestaltsGestaltGetByNode.ts | 2 +- src/client/service/gestaltsGestaltList.ts | 2 +- .../service/gestaltsGestaltTrustByIdentity.ts | 2 +- .../service/gestaltsGestaltTrustByNode.ts | 2 +- src/client/service/identitiesAuthenticate.ts | 5 +- .../service/identitiesAuthenticatedGet.ts | 2 +- src/client/service/identitiesClaim.ts | 2 +- .../service/identitiesInfoConnectedGet.ts | 2 +- src/client/service/identitiesInfoGet.ts | 2 +- src/client/service/identitiesProvidersList.ts | 2 +- src/client/service/identitiesTokenDelete.ts | 2 +- src/client/service/identitiesTokenGet.ts | 2 +- src/client/service/identitiesTokenPut.ts | 2 +- src/client/service/keysCertsChainGet.ts | 2 +- src/client/service/keysCertsGet.ts | 2 +- src/client/service/keysDecrypt.ts | 2 +- src/client/service/keysEncrypt.ts | 2 +- src/client/service/keysKeyPairRenew.ts | 2 +- src/client/service/keysKeyPairReset.ts | 2 +- src/client/service/keysKeyPairRoot.ts | 2 +- src/client/service/keysPasswordChange.ts | 2 +- src/client/service/keysSign.ts | 2 +- src/client/service/keysVerify.ts | 2 +- src/client/service/nodesAdd.ts | 2 +- src/client/service/nodesClaim.ts | 2 +- src/client/service/nodesFind.ts | 2 +- src/client/service/nodesPing.ts | 2 +- src/client/service/notificationsClear.ts | 2 +- src/client/service/notificationsRead.ts | 2 +- src/client/service/notificationsSend.ts | 2 +- src/client/service/vaultsClone.ts | 4 +- src/client/service/vaultsCreate.ts | 5 +- src/client/service/vaultsDelete.ts | 35 ++++-------- src/client/service/vaultsList.ts | 2 +- src/client/service/vaultsLog.ts | 32 +++-------- src/client/service/vaultsPermissionGet.ts | 35 ++++-------- src/client/service/vaultsPermissionSet.ts | 22 +++----- src/client/service/vaultsPermissionUnset.ts | 18 +++--- src/client/service/vaultsPull.ts | 21 ++++--- src/client/service/vaultsRename.ts | 31 +++------- src/client/service/vaultsScan.ts | 2 +- src/client/service/vaultsSecretsDelete.ts | 32 +++-------- src/client/service/vaultsSecretsEdit.ts | 32 +++-------- src/client/service/vaultsSecretsGet.ts | 32 +++-------- src/client/service/vaultsSecretsList.ts | 35 ++++-------- src/client/service/vaultsSecretsMkdir.ts | 32 +++-------- src/client/service/vaultsSecretsNew.ts | 32 +++-------- src/client/service/vaultsSecretsNewDir.ts | 35 ++++-------- src/client/service/vaultsSecretsRename.ts | 36 ++++-------- src/client/service/vaultsSecretsStat.ts | 32 +++-------- src/client/service/vaultsVersion.ts | 32 +++-------- src/client/types.ts | 8 ++- src/client/utils/utils.ts | 52 ++++++++++++++--- tests/bin/vaults/vaults.test.ts | 4 +- tests/vaults/VaultManager.test.ts | 3 +- 78 files changed, 345 insertions(+), 458 deletions(-) diff --git a/src/agent/service/nodesChainDataGet.ts b/src/agent/service/nodesChainDataGet.ts index 0e09ff35f..e0f838b33 100644 --- a/src/agent/service/nodesChainDataGet.ts +++ b/src/agent/service/nodesChainDataGet.ts @@ -51,7 +51,7 @@ function nodesChainDataGet({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - !agentUtils.isClientError(e) && logger.error(e); + !agentUtils.isAgentClientError(e) && logger.error(e); return; } }; diff --git a/src/agent/service/nodesClosestLocalNodesGet.ts b/src/agent/service/nodesClosestLocalNodesGet.ts index e28fbd191..5c2c0e204 100644 --- a/src/agent/service/nodesClosestLocalNodesGet.ts +++ b/src/agent/service/nodesClosestLocalNodesGet.ts @@ -67,7 +67,7 @@ function nodesClosestLocalNodesGet({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - !agentUtils.isClientError(e) && logger.error(e); + !agentUtils.isAgentClientError(e) && logger.error(e); return; } }; diff --git a/src/agent/service/nodesCrossSignClaim.ts b/src/agent/service/nodesCrossSignClaim.ts index 63b6304c9..20d5ac575 100644 --- a/src/agent/service/nodesCrossSignClaim.ts +++ b/src/agent/service/nodesCrossSignClaim.ts @@ -173,7 +173,7 @@ function nodesCrossSignClaim({ }); } catch (e) { await genClaims.throw(e); - !agentUtils.isClientError(e, [ + !agentUtils.isAgentClientError(e, [ claimsErrors.ErrorEmptyStream, claimsErrors.ErrorUndefinedSinglySignedClaim, claimsErrors.ErrorUndefinedSignature, diff --git a/src/agent/service/nodesHolePunchMessageSend.ts b/src/agent/service/nodesHolePunchMessageSend.ts index 1ec86a35c..088787264 100644 --- a/src/agent/service/nodesHolePunchMessageSend.ts +++ b/src/agent/service/nodesHolePunchMessageSend.ts @@ -74,7 +74,7 @@ function nodesHolePunchMessageSend({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - !agentUtils.isClientError(e) && logger.error(e); + !agentUtils.isAgentClientError(e) && logger.error(e); return; } }; diff --git a/src/agent/service/notificationsSend.ts b/src/agent/service/notificationsSend.ts index 6108cbe74..eb336243c 100644 --- a/src/agent/service/notificationsSend.ts +++ b/src/agent/service/notificationsSend.ts @@ -36,7 +36,7 @@ function notificationsSend({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - !agentUtils.isClientError(e, [ + !agentUtils.isAgentClientError(e, [ notificationsErrors.ErrorNotificationsInvalidType, notificationsErrors.ErrorNotificationsValidationFailed, notificationsErrors.ErrorNotificationsParse, diff --git a/src/agent/service/vaultsGitInfoGet.ts b/src/agent/service/vaultsGitInfoGet.ts index aecdde37e..7fe9831ff 100644 --- a/src/agent/service/vaultsGitInfoGet.ts +++ b/src/agent/service/vaultsGitInfoGet.ts @@ -1,5 +1,5 @@ import type { DB } from '@matrixai/db'; -import type { VaultName, VaultId, VaultAction } from '../../vaults/types'; +import type { VaultName, VaultAction } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type ACL from '../../acl/ACL'; import type { ConnectionInfoGet } from '../../agent/types'; @@ -39,25 +39,24 @@ function vaultsGitInfoGet({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const { - vaultId, actionType, }: { - vaultId: VaultId; actionType: VaultAction; } = validateSync( (keyPath, value) => { return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], [['actionType'], () => validationUtils.parseVaultAction(value)], () => value, ); }, { - vaultId: call.request.getVault()?.getNameOrId(), actionType: call.request.getAction(), }, ); @@ -108,7 +107,7 @@ function vaultsGitInfoGet({ return; } catch (e) { await genWritable.throw(e); - !agentUtils.isClientError(e, [ + !agentUtils.isAgentClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, agentErrors.ErrorConnectionInfoMissing, vaultsErrors.ErrorVaultsPermissionDenied, diff --git a/src/agent/service/vaultsGitPackGet.ts b/src/agent/service/vaultsGitPackGet.ts index 276cec84f..50db9da28 100644 --- a/src/agent/service/vaultsGitPackGet.ts +++ b/src/agent/service/vaultsGitPackGet.ts @@ -1,6 +1,6 @@ import type * as grpc from '@grpc/grpc-js'; import type { DB } from '@matrixai/db'; -import type { VaultName, VaultId, VaultAction } from '../../vaults/types'; +import type { VaultName, VaultAction } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type { ConnectionInfoGet } from '../../agent/types'; import type ACL from '../../acl/ACL'; @@ -62,25 +62,22 @@ function vaultsGitPackGet({ nameOrId as VaultName, tran, ); + const vaultId = vaultIdFromName ?? vaultsUtils.decodeVaultId(nameOrId); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const { - vaultId, actionType, }: { - vaultId: VaultId; actionType: VaultAction; } = validateSync( (keyPath, value) => { return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], [['actionType'], () => validationUtils.parseVaultAction(value)], () => value, ); }, { - vaultId: nameOrId, actionType: meta.get('vaultAction').pop()!.toString(), }, ); @@ -123,7 +120,7 @@ function vaultsGitPackGet({ return; } catch (e) { await genDuplex.throw(e); - !agentUtils.isClientError(e, [ + !agentUtils.isAgentClientError(e, [ agentErrors.ErrorConnectionInfoMissing, vaultsErrors.ErrorVaultsPermissionDenied, vaultsErrors.ErrorVaultsVaultUndefined, diff --git a/src/agent/service/vaultsScan.ts b/src/agent/service/vaultsScan.ts index 42e6ca8eb..f1a94c2a9 100644 --- a/src/agent/service/vaultsScan.ts +++ b/src/agent/service/vaultsScan.ts @@ -53,7 +53,7 @@ function vaultsScan({ return; } catch (e) { await genWritable.throw(e); - !agentUtils.isClientError(e, [ + !agentUtils.isAgentClientError(e, [ agentErrors.ErrorConnectionInfoMissing, vaultsErrors.ErrorVaultsPermissionDenied, ]) && logger.error(e); diff --git a/src/agent/types.ts b/src/agent/types.ts index ced17bbf1..b6d0e0259 100644 --- a/src/agent/types.ts +++ b/src/agent/types.ts @@ -1,8 +1,14 @@ -import type { ConnectionInfo } from 'network/types'; import type { ServerSurfaceCall } from '@grpc/grpc-js/build/src/server-call'; +import type { Class } from '@matrixai/errors'; +import type { ConnectionInfo } from '../network/types'; +import type ErrorPolykey from '../ErrorPolykey'; type ConnectionInfoGet = ( call: ServerSurfaceCall, ) => ConnectionInfo | undefined; -export type { ConnectionInfoGet }; +type AgentClientErrors = Array< + Class> | Array>> +>; + +export type { ConnectionInfoGet, AgentClientErrors }; diff --git a/src/agent/utils.ts b/src/agent/utils.ts index 94b7d97d5..48f9ff59f 100644 --- a/src/agent/utils.ts +++ b/src/agent/utils.ts @@ -1,15 +1,15 @@ import type { ServerSurfaceCall } from '@grpc/grpc-js/build/src/server-call'; -import type { Class } from '@matrixai/errors'; -import type { Host, Port } from 'network/types'; -import type Proxy from 'network/Proxy'; -import type { ConnectionInfoGet } from './types'; +import type ErrorPolykey from '../ErrorPolykey'; +import type { Host, Port } from '../network/types'; +import type Proxy from '../network/Proxy'; +import type { ConnectionInfoGet, AgentClientErrors } from './types'; import * as validationErrors from '../validation/errors'; /** * Array of errors that are always considered to be "client errors" * (4xx errors in HTTP) in the context of the agent service */ -const defaultClientErrors: Array> = [ +const defaultClientErrors: AgentClientErrors = [ validationErrors.ErrorValidation, ]; @@ -33,19 +33,53 @@ function connectionInfoGetter(proxy: Proxy): ConnectionInfoGet { * context of a given handler can be supplied in the `extraClientErrors` * argument */ -function isClientError( - e: Error, - extraClientErrors?: Array>, +function isAgentClientError( + thrownError: ErrorPolykey, + extraClientErrors?: AgentClientErrors, ): boolean { for (const error of defaultClientErrors) { - if (e instanceof error) return true; + if (Array.isArray(error)) { + let e = thrownError; + let matches = true; + for (const eType of error) { + if (e == null) { + matches = false; + break; + } + if (!(e instanceof eType)) { + matches = false; + break; + } + e = e.cause; + } + if (matches) return true; + } else if (thrownError instanceof error) { + return true; + } } if (extraClientErrors) { for (const error of extraClientErrors) { - if (e instanceof error) return true; + if (Array.isArray(error)) { + let e = thrownError; + let matches = true; + for (const eType of error) { + if (e == null) { + matches = false; + break; + } + if (!(e instanceof eType)) { + matches = false; + break; + } + e = e.cause; + } + if (matches) return true; + } else if (thrownError instanceof error) { + return true; + } } } return false; } -export { connectionInfoGetter, isClientError }; +export { connectionInfoGetter, isAgentClientError }; diff --git a/src/client/service/agentLockAll.ts b/src/client/service/agentLockAll.ts index 90ad0a93a..29e64bcad 100644 --- a/src/client/service/agentLockAll.ts +++ b/src/client/service/agentLockAll.ts @@ -33,7 +33,7 @@ function agentLockAll({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/agentStatus.ts b/src/client/service/agentStatus.ts index 52d14144a..110555cf8 100644 --- a/src/client/service/agentStatus.ts +++ b/src/client/service/agentStatus.ts @@ -50,7 +50,7 @@ function agentStatus({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/agentStop.ts b/src/client/service/agentStop.ts index a745887e5..f88885f09 100644 --- a/src/client/service/agentStop.ts +++ b/src/client/service/agentStop.ts @@ -33,7 +33,7 @@ function agentStop({ callback(null, response); } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } // Stop is called after GRPC resources are cleared diff --git a/src/client/service/agentUnlock.ts b/src/client/service/agentUnlock.ts index 1f726792d..5147e2718 100644 --- a/src/client/service/agentUnlock.ts +++ b/src/client/service/agentUnlock.ts @@ -24,7 +24,7 @@ function agentUnlock({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsGetByIdentity.ts b/src/client/service/gestaltsActionsGetByIdentity.ts index bd0d8ba04..ef45d57e7 100644 --- a/src/client/service/gestaltsActionsGetByIdentity.ts +++ b/src/client/service/gestaltsActionsGetByIdentity.ts @@ -63,7 +63,7 @@ function gestaltsActionsGetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsGetByNode.ts b/src/client/service/gestaltsActionsGetByNode.ts index 11187384b..b5652d3bb 100644 --- a/src/client/service/gestaltsActionsGetByNode.ts +++ b/src/client/service/gestaltsActionsGetByNode.ts @@ -57,7 +57,7 @@ function gestaltsActionsGetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsActionsSetByIdentity.ts b/src/client/service/gestaltsActionsSetByIdentity.ts index 3776bbebb..0628b2a98 100644 --- a/src/client/service/gestaltsActionsSetByIdentity.ts +++ b/src/client/service/gestaltsActionsSetByIdentity.ts @@ -68,7 +68,7 @@ function gestaltsActionsSetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, ]) && logger.error(e); diff --git a/src/client/service/gestaltsActionsSetByNode.ts b/src/client/service/gestaltsActionsSetByNode.ts index 91cef278f..2aa9a7050 100644 --- a/src/client/service/gestaltsActionsSetByNode.ts +++ b/src/client/service/gestaltsActionsSetByNode.ts @@ -54,7 +54,7 @@ function gestaltsActionsSetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, ]) && logger.error(e); return; diff --git a/src/client/service/gestaltsActionsUnsetByIdentity.ts b/src/client/service/gestaltsActionsUnsetByIdentity.ts index 1b20a5610..88745bc64 100644 --- a/src/client/service/gestaltsActionsUnsetByIdentity.ts +++ b/src/client/service/gestaltsActionsUnsetByIdentity.ts @@ -68,7 +68,7 @@ function gestaltsActionsUnsetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, ]) && logger.error(e); diff --git a/src/client/service/gestaltsActionsUnsetByNode.ts b/src/client/service/gestaltsActionsUnsetByNode.ts index 1f06d2c64..d7a62d68a 100644 --- a/src/client/service/gestaltsActionsUnsetByNode.ts +++ b/src/client/service/gestaltsActionsUnsetByNode.ts @@ -54,7 +54,7 @@ function gestaltsActionsUnsetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, ]) && logger.error(e); return; diff --git a/src/client/service/gestaltsDiscoveryByIdentity.ts b/src/client/service/gestaltsDiscoveryByIdentity.ts index b63bb83bf..37efbf7d3 100644 --- a/src/client/service/gestaltsDiscoveryByIdentity.ts +++ b/src/client/service/gestaltsDiscoveryByIdentity.ts @@ -52,7 +52,7 @@ function gestaltsDiscoveryByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsDiscoveryByNode.ts b/src/client/service/gestaltsDiscoveryByNode.ts index b37bd777c..0c8d1ea4c 100644 --- a/src/client/service/gestaltsDiscoveryByNode.ts +++ b/src/client/service/gestaltsDiscoveryByNode.ts @@ -48,7 +48,7 @@ function gestaltsDiscoveryByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltGetByIdentity.ts b/src/client/service/gestaltsGestaltGetByIdentity.ts index 9396c3d6d..81e3ffc54 100644 --- a/src/client/service/gestaltsGestaltGetByIdentity.ts +++ b/src/client/service/gestaltsGestaltGetByIdentity.ts @@ -60,7 +60,7 @@ function gestaltsGestaltGetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltGetByNode.ts b/src/client/service/gestaltsGestaltGetByNode.ts index 2fbbb8447..fb3e63f56 100644 --- a/src/client/service/gestaltsGestaltGetByNode.ts +++ b/src/client/service/gestaltsGestaltGetByNode.ts @@ -56,7 +56,7 @@ function gestaltsGestaltGetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltList.ts b/src/client/service/gestaltsGestaltList.ts index cbe2e0027..7b4725892 100644 --- a/src/client/service/gestaltsGestaltList.ts +++ b/src/client/service/gestaltsGestaltList.ts @@ -40,7 +40,7 @@ function gestaltsGestaltList({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/gestaltsGestaltTrustByIdentity.ts b/src/client/service/gestaltsGestaltTrustByIdentity.ts index 9fc7c4911..36a0aa982 100644 --- a/src/client/service/gestaltsGestaltTrustByIdentity.ts +++ b/src/client/service/gestaltsGestaltTrustByIdentity.ts @@ -84,7 +84,7 @@ function gestaltsGestaltTrustByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, ]) && logger.error(e); diff --git a/src/client/service/gestaltsGestaltTrustByNode.ts b/src/client/service/gestaltsGestaltTrustByNode.ts index 9be7fa628..8fa7299a0 100644 --- a/src/client/service/gestaltsGestaltTrustByNode.ts +++ b/src/client/service/gestaltsGestaltTrustByNode.ts @@ -71,7 +71,7 @@ function gestaltsGestaltTrustByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, ]) && logger.error(e); return; diff --git a/src/client/service/identitiesAuthenticate.ts b/src/client/service/identitiesAuthenticate.ts index 9aa0927e0..d9c216c6c 100644 --- a/src/client/service/identitiesAuthenticate.ts +++ b/src/client/service/identitiesAuthenticate.ts @@ -75,8 +75,9 @@ function identitiesAuthenticate({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientError(e, [identitiesErrors.ErrorProviderMissing]) && - logger.error(e); + !clientUtils.isClientClientError(e, [ + identitiesErrors.ErrorProviderMissing, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesAuthenticatedGet.ts b/src/client/service/identitiesAuthenticatedGet.ts index 64d0d7232..3ab4cc941 100644 --- a/src/client/service/identitiesAuthenticatedGet.ts +++ b/src/client/service/identitiesAuthenticatedGet.ts @@ -64,7 +64,7 @@ function identitiesAuthenticatedGet({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesClaim.ts b/src/client/service/identitiesClaim.ts index 884a5ca1c..de5e1df57 100644 --- a/src/client/service/identitiesClaim.ts +++ b/src/client/service/identitiesClaim.ts @@ -93,7 +93,7 @@ function identitiesClaim({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ identitiesErrors.ErrorProviderMissing, identitiesErrors.ErrorProviderUnauthenticated, ]) && logger.error(e); diff --git a/src/client/service/identitiesInfoConnectedGet.ts b/src/client/service/identitiesInfoConnectedGet.ts index 7ac96810c..63d681700 100644 --- a/src/client/service/identitiesInfoConnectedGet.ts +++ b/src/client/service/identitiesInfoConnectedGet.ts @@ -120,7 +120,7 @@ function identitiesInfoConnectedGet({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ identitiesErrors.ErrorProviderMissing, identitiesErrors.ErrorProviderUnauthenticated, identitiesErrors.ErrorProviderUnimplemented, diff --git a/src/client/service/identitiesInfoGet.ts b/src/client/service/identitiesInfoGet.ts index bd29cf2f3..e8df1153b 100644 --- a/src/client/service/identitiesInfoGet.ts +++ b/src/client/service/identitiesInfoGet.ts @@ -113,7 +113,7 @@ function identitiesInfoGet({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ identitiesErrors.ErrorProviderMissing, identitiesErrors.ErrorProviderUnauthenticated, ]) && logger.error(e); diff --git a/src/client/service/identitiesProvidersList.ts b/src/client/service/identitiesProvidersList.ts index cd451d2f9..70cbc9ccd 100644 --- a/src/client/service/identitiesProvidersList.ts +++ b/src/client/service/identitiesProvidersList.ts @@ -30,7 +30,7 @@ function identitiesProvidersList({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesTokenDelete.ts b/src/client/service/identitiesTokenDelete.ts index 9abe9d624..779ffea47 100644 --- a/src/client/service/identitiesTokenDelete.ts +++ b/src/client/service/identitiesTokenDelete.ts @@ -57,7 +57,7 @@ function identitiesTokenDelete({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesTokenGet.ts b/src/client/service/identitiesTokenGet.ts index 193cf2553..5ca76f585 100644 --- a/src/client/service/identitiesTokenGet.ts +++ b/src/client/service/identitiesTokenGet.ts @@ -57,7 +57,7 @@ function identitiesTokenGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/identitiesTokenPut.ts b/src/client/service/identitiesTokenPut.ts index c06ad8106..261b88a12 100644 --- a/src/client/service/identitiesTokenPut.ts +++ b/src/client/service/identitiesTokenPut.ts @@ -67,7 +67,7 @@ function identitiesTokenPut({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysCertsChainGet.ts b/src/client/service/keysCertsChainGet.ts index 94418b7b6..fed99bf2a 100644 --- a/src/client/service/keysCertsChainGet.ts +++ b/src/client/service/keysCertsChainGet.ts @@ -34,7 +34,7 @@ function keysCertsChainGet({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysCertsGet.ts b/src/client/service/keysCertsGet.ts index da8792aa1..1b8222612 100644 --- a/src/client/service/keysCertsGet.ts +++ b/src/client/service/keysCertsGet.ts @@ -30,7 +30,7 @@ function keysCertsGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysDecrypt.ts b/src/client/service/keysDecrypt.ts index 092e7f67b..b1a0f6bad 100644 --- a/src/client/service/keysDecrypt.ts +++ b/src/client/service/keysDecrypt.ts @@ -31,7 +31,7 @@ function keysDecrypt({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysEncrypt.ts b/src/client/service/keysEncrypt.ts index df8f4ff62..b8c5c60bb 100644 --- a/src/client/service/keysEncrypt.ts +++ b/src/client/service/keysEncrypt.ts @@ -31,7 +31,7 @@ function keysEncrypt({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysKeyPairRenew.ts b/src/client/service/keysKeyPairRenew.ts index 3660c9bc5..ada854cad 100644 --- a/src/client/service/keysKeyPairRenew.ts +++ b/src/client/service/keysKeyPairRenew.ts @@ -31,7 +31,7 @@ function keysKeyPairRenew({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysKeyPairReset.ts b/src/client/service/keysKeyPairReset.ts index 3d04f12aa..af3b25426 100644 --- a/src/client/service/keysKeyPairReset.ts +++ b/src/client/service/keysKeyPairReset.ts @@ -31,7 +31,7 @@ function keysKeyPairReset({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysKeyPairRoot.ts b/src/client/service/keysKeyPairRoot.ts index ad1eb3e5a..14f543d9f 100644 --- a/src/client/service/keysKeyPairRoot.ts +++ b/src/client/service/keysKeyPairRoot.ts @@ -31,7 +31,7 @@ function keysKeyPairRoot({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysPasswordChange.ts b/src/client/service/keysPasswordChange.ts index b96a44ca1..b1d116db5 100644 --- a/src/client/service/keysPasswordChange.ts +++ b/src/client/service/keysPasswordChange.ts @@ -29,7 +29,7 @@ function keysPasswordChange({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysSign.ts b/src/client/service/keysSign.ts index bae99915f..9c3aa2ab3 100644 --- a/src/client/service/keysSign.ts +++ b/src/client/service/keysSign.ts @@ -32,7 +32,7 @@ function keysSign({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/keysVerify.ts b/src/client/service/keysVerify.ts index a7cfaae3a..1c53fff74 100644 --- a/src/client/service/keysVerify.ts +++ b/src/client/service/keysVerify.ts @@ -33,7 +33,7 @@ function keysVerify({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/nodesAdd.ts b/src/client/service/nodesAdd.ts index 8c089ff0b..079d2eee2 100644 --- a/src/client/service/nodesAdd.ts +++ b/src/client/service/nodesAdd.ts @@ -74,7 +74,7 @@ function nodesAdd({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/nodesClaim.ts b/src/client/service/nodesClaim.ts index 4022e10c7..c9e1d6db9 100644 --- a/src/client/service/nodesClaim.ts +++ b/src/client/service/nodesClaim.ts @@ -77,7 +77,7 @@ function nodesClaim({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ nodesErrors.ErrorNodeGraphNodeIdNotFound, ]) && logger.error(e); return; diff --git a/src/client/service/nodesFind.ts b/src/client/service/nodesFind.ts index 4826f9d96..6c2061719 100644 --- a/src/client/service/nodesFind.ts +++ b/src/client/service/nodesFind.ts @@ -59,7 +59,7 @@ function nodesFind({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ nodesErrors.ErrorNodeGraphNodeIdNotFound, ]) && logger.error(e); return; diff --git a/src/client/service/nodesPing.ts b/src/client/service/nodesPing.ts index f86c8c1fa..5adc83f54 100644 --- a/src/client/service/nodesPing.ts +++ b/src/client/service/nodesPing.ts @@ -53,7 +53,7 @@ function nodesPing({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ nodesErrors.ErrorNodeGraphNodeIdNotFound, ]) && logger.error(e); return; diff --git a/src/client/service/notificationsClear.ts b/src/client/service/notificationsClear.ts index 8d1d501c1..acc05724e 100644 --- a/src/client/service/notificationsClear.ts +++ b/src/client/service/notificationsClear.ts @@ -33,7 +33,7 @@ function notificationsClear({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/notificationsRead.ts b/src/client/service/notificationsRead.ts index 60d55b7c7..4e6cbb92d 100644 --- a/src/client/service/notificationsRead.ts +++ b/src/client/service/notificationsRead.ts @@ -75,7 +75,7 @@ function notificationsRead({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/notificationsSend.ts b/src/client/service/notificationsSend.ts index c592aa476..fcdb72606 100644 --- a/src/client/service/notificationsSend.ts +++ b/src/client/service/notificationsSend.ts @@ -56,7 +56,7 @@ function notificationsSend({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ nodesErrors.ErrorNodeGraphNodeIdNotFound, ]) && logger.error(e); return; diff --git a/src/client/service/vaultsClone.ts b/src/client/service/vaultsClone.ts index 86129010d..ec60df21a 100644 --- a/src/client/service/vaultsClone.ts +++ b/src/client/service/vaultsClone.ts @@ -6,6 +6,7 @@ import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; import * as grpcUtils from '../../grpc/utils'; +import * as grpcErrors from '../../grpc/errors'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import * as nodesErrors from '../../nodes/errors'; import { validateSync } from '../../validation'; @@ -63,9 +64,10 @@ function vaultsClone({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ nodesErrors.ErrorNodeGraphNodeIdNotFound, vaultsErrors.ErrorVaultsNameConflict, + [grpcErrors.ErrorPolykeyRemote, vaultsErrors.ErrorVaultsVaultUndefined], ]) && logger.error(e); return; } diff --git a/src/client/service/vaultsCreate.ts b/src/client/service/vaultsCreate.ts index 4175a7de0..c181b4b76 100644 --- a/src/client/service/vaultsCreate.ts +++ b/src/client/service/vaultsCreate.ts @@ -39,8 +39,9 @@ function vaultsCreate({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [vaultsErrors.ErrorVaultsVaultDefined]) && - logger.error(e); + !clientUtils.isClientClientError(e, [ + vaultsErrors.ErrorVaultsVaultDefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsDelete.ts b/src/client/service/vaultsDelete.ts index 6aea1c1c0..61fbfbc27 100644 --- a/src/client/service/vaultsDelete.ts +++ b/src/client/service/vaultsDelete.ts @@ -1,5 +1,5 @@ import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; import type { DB } from '@matrixai/db'; @@ -7,10 +7,8 @@ import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as vaultsErrors from '../../vaults/errors'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsDelete({ @@ -37,24 +35,12 @@ function vaultsDelete({ call.request.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } await vaultManager.destroyVault(vaultId, tran); }); response.setSuccess(true); @@ -62,8 +48,9 @@ function vaultsDelete({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [vaultsErrors.ErrorVaultsVaultUndefined]) && - logger.error(e); + !clientUtils.isClientClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsList.ts b/src/client/service/vaultsList.ts index 08646c59b..2e9f1a79a 100644 --- a/src/client/service/vaultsList.ts +++ b/src/client/service/vaultsList.ts @@ -40,7 +40,7 @@ function vaultsList({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsLog.ts b/src/client/service/vaultsLog.ts index 88873dca5..32d014b05 100644 --- a/src/client/service/vaultsLog.ts +++ b/src/client/service/vaultsLog.ts @@ -1,16 +1,14 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as vaultsErrors from '../../vaults/errors'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsLog({ @@ -36,24 +34,12 @@ function vaultsLog({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getVault()?.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } // Getting the log const depth = call.request.getLogDepth(); let commitId: string | undefined = call.request.getCommitId(); @@ -80,7 +66,7 @@ function vaultsLog({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorVaultReferenceInvalid, ]) && logger.error(e); diff --git a/src/client/service/vaultsPermissionGet.ts b/src/client/service/vaultsPermissionGet.ts index d612f5b8c..86377f531 100644 --- a/src/client/service/vaultsPermissionGet.ts +++ b/src/client/service/vaultsPermissionGet.ts @@ -2,7 +2,7 @@ import type * as grpc from '@grpc/grpc-js'; import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; -import type { VaultName, VaultId, VaultActions } from '../../vaults/types'; +import type { VaultName, VaultActions } from '../../vaults/types'; import type ACL from '../../acl/ACL'; import type { NodeId, NodeIdEncoded } from 'nodes/types'; import type Logger from '@matrixai/logger'; @@ -10,10 +10,9 @@ import { IdInternal } from '@matrixai/id'; import * as grpcUtils from '../../grpc/utils'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; +import * as vaultsUtils from '../../vaults/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as nodesUtils from '../../nodes/utils'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsPermissionGet({ @@ -43,24 +42,12 @@ function vaultsPermissionGet({ call.request.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } // Getting permissions return [await acl.getVaultPerm(vaultId, tran), vaultId]; }, @@ -86,7 +73,9 @@ function vaultsPermissionGet({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsPermissionSet.ts b/src/client/service/vaultsPermissionSet.ts index 335165ef7..9bc2a3b8d 100644 --- a/src/client/service/vaultsPermissionSet.ts +++ b/src/client/service/vaultsPermissionSet.ts @@ -1,12 +1,7 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { NodeId } from '../../nodes/types'; -import type { - VaultName, - VaultId, - VaultAction, - VaultActions, -} from '../../vaults/types'; +import type { VaultName, VaultAction, VaultActions } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type ACL from '../../acl/ACL'; @@ -55,29 +50,28 @@ function vaultsPermissionSet({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const { nodeId, - vaultId, actions, }: { nodeId: NodeId; - vaultId: VaultId; actions: Array; } = validateSync( (keyPath, value) => { return matchSync(keyPath)( [['nodeId'], () => validationUtils.parseNodeId(value)], - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], [['actions'], () => value.map(validationUtils.parseVaultAction)], () => value, ); }, { nodeId: call.request.getNode()?.getNodeId(), - vaultId: call.request.getVault()?.getNameOrId(), actions: call.request.getVaultPermissionsList(), }, ); @@ -105,7 +99,7 @@ function vaultsPermissionSet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, aclErrors.ErrorACLNodeIdMissing, nodesErrors.ErrorNodeGraphNodeIdNotFound, diff --git a/src/client/service/vaultsPermissionUnset.ts b/src/client/service/vaultsPermissionUnset.ts index 9b561b173..7906207a3 100644 --- a/src/client/service/vaultsPermissionUnset.ts +++ b/src/client/service/vaultsPermissionUnset.ts @@ -1,13 +1,14 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type { NodeId } from '../../nodes/types'; -import type { VaultName, VaultId, VaultAction } from '../../vaults/types'; +import type { VaultName, VaultAction } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type GestaltGraph from '../../gestalts/GestaltGraph'; import type ACL from '../../acl/ACL'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; +import * as vaultsUtils from '../../vaults/utils'; import * as vaultsErrors from '../../vaults/errors'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; @@ -45,29 +46,28 @@ function vaultsPermissionUnset({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const { nodeId, - vaultId, actions, }: { nodeId: NodeId; - vaultId: VaultId; actions: Array; } = validateSync( (keyPath, value) => { return matchSync(keyPath)( [['nodeId'], () => validationUtils.parseNodeId(value)], - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], [['actions'], () => value.map(validationUtils.parseVaultAction)], () => value, ); }, { nodeId: call.request.getNode()?.getNodeId(), - vaultId: call.request.getVault()?.getNameOrId(), actions: call.request.getVaultPermissionsList(), }, ); @@ -99,7 +99,7 @@ function vaultsPermissionUnset({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, ]) && logger.error(e); diff --git a/src/client/service/vaultsPull.ts b/src/client/service/vaultsPull.ts index 6f7d19106..00fa44880 100644 --- a/src/client/service/vaultsPull.ts +++ b/src/client/service/vaultsPull.ts @@ -1,16 +1,18 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; import type VaultManager from '../../vaults/VaultManager'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type { NodeId } from '../../nodes/types'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; import * as grpcUtils from '../../grpc/utils'; +import * as grpcErrors from '../../grpc/errors'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; import * as vaultsUtils from '../../vaults/utils'; +import * as vaultsErrors from '../../vaults/errors'; import * as nodesErrors from '../../nodes/errors'; import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; @@ -48,19 +50,19 @@ function vaultsPull({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const { - vaultId, nodeId, }: { - vaultId: VaultId; nodeId: NodeId | undefined; } = validateSync( (keyPath, value) => { return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], [ ['nodeId'], () => (value ? validationUtils.parseNodeId(value) : undefined), @@ -69,7 +71,6 @@ function vaultsPull({ ); }, { - vaultId: call.request.getVault()?.getNameOrId(), nodeId: call.request.getNode()?.getNodeId(), }, ); @@ -85,8 +86,10 @@ function vaultsPull({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, nodesErrors.ErrorNodeGraphNodeIdNotFound, + [grpcErrors.ErrorPolykeyRemote, vaultsErrors.ErrorVaultsVaultUndefined], ]) && logger.error(e); return; } diff --git a/src/client/service/vaultsRename.ts b/src/client/service/vaultsRename.ts index 9647d7ef1..29d2bb04b 100644 --- a/src/client/service/vaultsRename.ts +++ b/src/client/service/vaultsRename.ts @@ -1,16 +1,13 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsUtils from '../../vaults/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsRename({ @@ -37,24 +34,12 @@ function vaultsRename({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getVault()?.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const newName = call.request.getNewName() as VaultName; await vaultManager.renameVault(vaultId, newName, tran); response.setNameOrId(vaultsUtils.encodeVaultId(vaultId)); @@ -63,7 +48,7 @@ function vaultsRename({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorVaultsVaultDefined, ]) && logger.error(e); diff --git a/src/client/service/vaultsScan.ts b/src/client/service/vaultsScan.ts index 48556105e..c7a0def19 100644 --- a/src/client/service/vaultsScan.ts +++ b/src/client/service/vaultsScan.ts @@ -58,7 +58,7 @@ function vaultsScan({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ nodesErrors.ErrorNodeGraphNodeIdNotFound, ]) && logger.error(e); return; diff --git a/src/client/service/vaultsSecretsDelete.ts b/src/client/service/vaultsSecretsDelete.ts index 86a9a77b0..625c03cab 100644 --- a/src/client/service/vaultsSecretsDelete.ts +++ b/src/client/service/vaultsSecretsDelete.ts @@ -1,17 +1,15 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsSecretsDelete({ @@ -38,24 +36,12 @@ function vaultsSecretsDelete({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getVault()?.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const secretName = call.request.getSecretName(); await vaultManager.withVaults( [vaultId], @@ -70,7 +56,7 @@ function vaultsSecretsDelete({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, ]) && logger.error(e); diff --git a/src/client/service/vaultsSecretsEdit.ts b/src/client/service/vaultsSecretsEdit.ts index 374b5d9dd..a40ea71e9 100644 --- a/src/client/service/vaultsSecretsEdit.ts +++ b/src/client/service/vaultsSecretsEdit.ts @@ -1,17 +1,15 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsSecretsEdit({ @@ -38,24 +36,12 @@ function vaultsSecretsEdit({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getVault()?.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const secretName = call.request.getSecretName(); const secretContent = Buffer.from(call.request.getSecretContent()); await vaultManager.withVaults( @@ -71,7 +57,7 @@ function vaultsSecretsEdit({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, vaultsErrors.ErrorVaultRemoteDefined, diff --git a/src/client/service/vaultsSecretsGet.ts b/src/client/service/vaultsSecretsGet.ts index c5770db8e..4f826551f 100644 --- a/src/client/service/vaultsSecretsGet.ts +++ b/src/client/service/vaultsSecretsGet.ts @@ -1,17 +1,15 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsSecretsGet({ @@ -38,24 +36,12 @@ function vaultsSecretsGet({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getVault()?.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const secretName = call.request.getSecretName(); const secretContent = await vaultManager.withVaults( [vaultId], @@ -70,7 +56,7 @@ function vaultsSecretsGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, ]) && logger.error(e); diff --git a/src/client/service/vaultsSecretsList.ts b/src/client/service/vaultsSecretsList.ts index b7c103cc7..a0774565f 100644 --- a/src/client/service/vaultsSecretsList.ts +++ b/src/client/service/vaultsSecretsList.ts @@ -1,17 +1,15 @@ import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as grpc from '@grpc/grpc-js'; import type { DB } from '@matrixai/db'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsSecretsList({ @@ -37,24 +35,12 @@ function vaultsSecretsList({ call.request.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } return await vaultManager.withVaults( [vaultId], async (vault) => { @@ -73,8 +59,9 @@ function vaultsSecretsList({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientError(e, [vaultsErrors.ErrorVaultsVaultUndefined]) && - logger.error(e); + !clientUtils.isClientClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsMkdir.ts b/src/client/service/vaultsSecretsMkdir.ts index eaa4e8324..623a28ec9 100644 --- a/src/client/service/vaultsSecretsMkdir.ts +++ b/src/client/service/vaultsSecretsMkdir.ts @@ -1,17 +1,15 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsSecretsMkdir({ @@ -38,24 +36,12 @@ function vaultsSecretsMkdir({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getVault()?.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } await vaultManager.withVaults( [vaultId], async (vault) => { @@ -71,7 +57,7 @@ function vaultsSecretsMkdir({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorVaultsRecursive, ]) && logger.error(e); diff --git a/src/client/service/vaultsSecretsNew.ts b/src/client/service/vaultsSecretsNew.ts index d89064985..c481a4cda 100644 --- a/src/client/service/vaultsSecretsNew.ts +++ b/src/client/service/vaultsSecretsNew.ts @@ -1,17 +1,15 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsSecretsNew({ @@ -38,24 +36,12 @@ function vaultsSecretsNew({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getVault()?.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const secret = call.request.getSecretName(); const content = Buffer.from(call.request.getSecretContent()); await vaultManager.withVaults( @@ -71,7 +57,7 @@ function vaultsSecretsNew({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, ]) && logger.error(e); diff --git a/src/client/service/vaultsSecretsNewDir.ts b/src/client/service/vaultsSecretsNewDir.ts index 6cc7ad0f8..e9a0d0878 100644 --- a/src/client/service/vaultsSecretsNewDir.ts +++ b/src/client/service/vaultsSecretsNewDir.ts @@ -1,18 +1,16 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type { FileSystem } from '../../types'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsSecretsNewDir({ @@ -41,24 +39,12 @@ function vaultsSecretsNewDir({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getVault()?.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const secretsPath = call.request.getSecretDirectory(); await vaultManager.withVaults( [vaultId], @@ -73,8 +59,9 @@ function vaultsSecretsNewDir({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [vaultsErrors.ErrorVaultsVaultUndefined]) && - logger.error(e); + !clientUtils.isClientClientError(e, [ + vaultsErrors.ErrorVaultsVaultUndefined, + ]) && logger.error(e); return; } }; diff --git a/src/client/service/vaultsSecretsRename.ts b/src/client/service/vaultsSecretsRename.ts index 1b17420ff..9362c2b08 100644 --- a/src/client/service/vaultsSecretsRename.ts +++ b/src/client/service/vaultsSecretsRename.ts @@ -1,17 +1,15 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; -import * as grpcUtils from '../../grpc/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as vaultsErrors from '../../vaults/errors'; +import * as grpcUtils from '../../grpc/utils'; import * as vaultOps from '../../vaults/VaultOps'; import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsSecretsRename({ @@ -38,24 +36,14 @@ function vaultsSecretsRename({ call.request.getOldSecret()?.getVault()?.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getOldSecret()?.getVault()?.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId( + call.request.getOldSecret()?.getVault()?.getNameOrId(), + ); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const oldSecret = call.request.getOldSecret()?.getSecretName(); if (oldSecret == null) { throw new vaultsErrors.ErrorSecretsSecretUndefined(); @@ -74,7 +62,7 @@ function vaultsSecretsRename({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, ]) && logger.error(e); diff --git a/src/client/service/vaultsSecretsStat.ts b/src/client/service/vaultsSecretsStat.ts index fc173fe4b..78a7d2800 100644 --- a/src/client/service/vaultsSecretsStat.ts +++ b/src/client/service/vaultsSecretsStat.ts @@ -1,16 +1,14 @@ import type { DB } from '@matrixai/db'; import type VaultManager from '../../vaults/VaultManager'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type { Authenticate } from '../types'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; import * as grpcUtils from '../../grpc/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultOps from '../../vaults/VaultOps'; import * as secretsPB from '../../proto/js/polykey/v1/secrets/secrets_pb'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsSecretsStat({ @@ -37,24 +35,12 @@ function vaultsSecretsStat({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getVault()?.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } const secretName = call.request.getSecretName(); const stat = await vaultManager.withVaults( [vaultId], @@ -69,7 +55,7 @@ function vaultsSecretsStat({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, ]) && logger.error(e); diff --git a/src/client/service/vaultsVersion.ts b/src/client/service/vaultsVersion.ts index 7c755aa55..a3871b526 100644 --- a/src/client/service/vaultsVersion.ts +++ b/src/client/service/vaultsVersion.ts @@ -1,15 +1,13 @@ import type { DB } from '@matrixai/db'; import type { Authenticate } from '../types'; -import type { VaultName, VaultId } from '../../vaults/types'; +import type { VaultName } from '../../vaults/types'; import type VaultManager from '../../vaults/VaultManager'; import type Logger from '@matrixai/logger'; import type * as grpc from '@grpc/grpc-js'; -import { validateSync } from '../../validation'; -import * as validationUtils from '../../validation/utils'; +import * as vaultsUtils from '../../vaults/utils'; import * as grpcUtils from '../../grpc/utils'; import * as vaultsErrors from '../../vaults/errors'; import * as vaultsPB from '../../proto/js/polykey/v1/vaults/vaults_pb'; -import { matchSync } from '../../utils'; import * as clientUtils from '../utils'; function vaultsVersion({ @@ -37,24 +35,12 @@ function vaultsVersion({ call.request.getVault()?.getNameOrId() as VaultName, tran, ); - const { - vaultId, - }: { - vaultId: VaultId; - } = validateSync( - (keyPath, value) => { - return matchSync(keyPath)( - [ - ['vaultId'], - () => vaultIdFromName ?? validationUtils.parseVaultId(value), - ], - () => value, - ); - }, - { - vaultId: call.request.getVault()?.getNameOrId(), - }, - ); + const vaultId = + vaultIdFromName ?? + vaultsUtils.decodeVaultId(call.request.getVault()?.getNameOrId()); + if (vaultId == null) { + throw new vaultsErrors.ErrorVaultsVaultUndefined(); + } // Doing the deed const versionId = call.request.getVersionId(); const [latestOid, currentVersionId] = await vaultManager.withVaults( @@ -78,7 +64,7 @@ function vaultsVersion({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientError(e, [ + !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorVaultReferenceInvalid, vaultsErrors.ErrorVaultReferenceMissing, diff --git a/src/client/types.ts b/src/client/types.ts index dc642800f..d06cdb11e 100644 --- a/src/client/types.ts +++ b/src/client/types.ts @@ -1,8 +1,14 @@ import type * as grpc from '@grpc/grpc-js'; +import type { Class } from '@matrixai/errors'; +import type ErrorPolykey from '../ErrorPolykey'; type Authenticate = ( metadataClient: grpc.Metadata, metadataServer?: grpc.Metadata, ) => Promise; -export type { Authenticate }; +type ClientClientErrors = Array< + Class> | Array>> +>; + +export type { Authenticate, ClientClientErrors }; diff --git a/src/client/utils/utils.ts b/src/client/utils/utils.ts index b77ac0e76..21bfaab20 100644 --- a/src/client/utils/utils.ts +++ b/src/client/utils/utils.ts @@ -3,12 +3,12 @@ import type { Interceptor, InterceptorOptions, } from '@grpc/grpc-js/build/src/client-interceptors'; -import type { Class } from '@matrixai/errors'; +import type ErrorPolykey from '../../ErrorPolykey'; import type KeyManager from '../../keys/KeyManager'; import type Session from '../../sessions/Session'; import type SessionManager from '../../sessions/SessionManager'; import type { SessionToken } from '../../sessions/types'; -import type { Authenticate } from '../types'; +import type { Authenticate, ClientClientErrors } from '../types'; import * as base64 from 'multiformats/bases/base64'; import * as grpc from '@grpc/grpc-js'; import * as validationErrors from '../../validation/errors'; @@ -18,7 +18,7 @@ import * as clientErrors from '../errors'; * Array of errors that are always considered to be "client errors" * (4xx errors in HTTP) in the context of the client service */ -const defaultClientErrors: Array> = [ +const defaultClientErrors: ClientClientErrors = [ validationErrors.ErrorValidation, clientErrors.ErrorClientAuthMissing, clientErrors.ErrorClientAuthFormat, @@ -154,16 +154,50 @@ function decodeAuthToSession( * context of a given handler can be supplied in the `extraClientErrors` * argument */ -function isClientError( - e: Error, - extraClientErrors?: Array>, +function isClientClientError( + thrownError: ErrorPolykey, + extraClientErrors?: ClientClientErrors, ): boolean { for (const error of defaultClientErrors) { - if (e instanceof error) return true; + if (Array.isArray(error)) { + let e = thrownError; + let matches = true; + for (const eType of error) { + if (e == null) { + matches = false; + break; + } + if (!(e instanceof eType)) { + matches = false; + break; + } + e = e.cause; + } + if (matches) return true; + } else if (thrownError instanceof error) { + return true; + } } if (extraClientErrors) { for (const error of extraClientErrors) { - if (e instanceof error) return true; + if (Array.isArray(error)) { + let e = thrownError; + let matches = true; + for (const eType of error) { + if (e == null) { + matches = false; + break; + } + if (!(e instanceof eType)) { + matches = false; + break; + } + e = e.cause; + } + if (matches) return true; + } else if (thrownError instanceof error) { + return true; + } } } return false; @@ -175,5 +209,5 @@ export { encodeAuthFromPassword, encodeAuthFromSession, decodeAuthToSession, - isClientError, + isClientClientError, }; diff --git a/tests/bin/vaults/vaults.test.ts b/tests/bin/vaults/vaults.test.ts index a8e6fa3df..52b5f4e4c 100644 --- a/tests/bin/vaults/vaults.test.ts +++ b/tests/bin/vaults/vaults.test.ts @@ -342,8 +342,8 @@ describe('CLI vaults', () => { targetNodeIdEncoded, ]; result = await testBinUtils.pkStdio([...command], {}, dataDir); - expect(result.exitCode).toBe(sysexits.DATAERR); - expect(result.stderr).toContain('ErrorValidation'); + expect(result.exitCode).toBe(sysexits.USAGE); + expect(result.stderr).toContain('ErrorVaultsVaultUndefined'); command = [ 'vaults', diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index c62824b1d..e4ed618aa 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -23,7 +23,6 @@ import KeyManager from '@/keys/KeyManager'; import PolykeyAgent from '@/PolykeyAgent'; import VaultManager from '@/vaults/VaultManager'; import * as vaultsErrors from '@/vaults/errors'; -import * as validationErrors from '@/validation/errors'; import NodeGraph from '@/nodes/NodeGraph'; import * as nodesUtils from '@/nodes/utils'; import Proxy from '@/network/Proxy'; @@ -744,7 +743,7 @@ describe('VaultManager', () => { remoteKeynode1Id, 'not-existing' as VaultName, ), - validationErrors.ErrorValidation, + vaultsErrors.ErrorVaultsVaultUndefined, ); } finally { await vaultManager?.stop(); From 6185c231de38d2d8d28d7db14d4c0ce41aacdeca Mon Sep 17 00:00:00 2001 From: Joshua Karp Date: Fri, 18 Feb 2022 11:26:44 +1100 Subject: [PATCH 074/137] feat: added `nodesGetAll` bin command and service handler Retrieves all buckets from the NodeGraph --- src/bin/nodes/CommandGetAll.ts | 77 +++++++++ src/bin/nodes/CommandNodes.ts | 2 + src/client/GRPCClientClient.ts | 8 + src/client/service/index.ts | 2 + src/client/service/nodesGetAll.ts | 68 ++++++++ .../js/polykey/v1/client_service_grpc_pb.d.ts | 17 ++ .../js/polykey/v1/client_service_grpc_pb.js | 22 +++ src/proto/js/polykey/v1/nodes/nodes_pb.d.ts | 22 +++ src/proto/js/polykey/v1/nodes/nodes_pb.js | 155 ++++++++++++++++++ .../schemas/polykey/v1/client_service.proto | 1 + .../schemas/polykey/v1/nodes/nodes.proto | 5 + 11 files changed, 379 insertions(+) create mode 100644 src/bin/nodes/CommandGetAll.ts create mode 100644 src/client/service/nodesGetAll.ts diff --git a/src/bin/nodes/CommandGetAll.ts b/src/bin/nodes/CommandGetAll.ts new file mode 100644 index 000000000..91f69f681 --- /dev/null +++ b/src/bin/nodes/CommandGetAll.ts @@ -0,0 +1,77 @@ +import type PolykeyClient from '../../PolykeyClient'; +import type nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import CommandPolykey from '../CommandPolykey'; +import * as binUtils from '../utils'; +import * as binOptions from '../utils/options'; +import * as binProcessors from '../utils/processors'; + +class CommandGetAll extends CommandPolykey { + constructor(...args: ConstructorParameters) { + super(...args); + this.name('getall'); + this.description('Get all Nodes from Node Graph'); + this.addOption(binOptions.nodeId); + this.addOption(binOptions.clientHost); + this.addOption(binOptions.clientPort); + this.action(async (options) => { + const { default: PolykeyClient } = await import('../../PolykeyClient'); + const utilsPB = await import('../../proto/js/polykey/v1/utils/utils_pb'); + + const clientOptions = await binProcessors.processClientOptions( + options.nodePath, + options.nodeId, + options.clientHost, + options.clientPort, + this.fs, + this.logger.getChild(binProcessors.processClientOptions.name), + ); + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; + this.exitHandlers.handlers.push(async () => { + if (pkClient != null) await pkClient.stop(); + }); + let result: nodesPB.NodeBuckets; + try { + pkClient = await PolykeyClient.createPolykeyClient({ + nodePath: options.nodePath, + nodeId: clientOptions.nodeId, + host: clientOptions.clientHost, + port: clientOptions.clientPort, + logger: this.logger.getChild(PolykeyClient.name), + }); + const emptyMessage = new utilsPB.EmptyMessage(); + try { + result = await binUtils.retryAuthentication( + (auth) => pkClient.grpcClient.nodesGetAll(emptyMessage, auth), + meta, + ); + } catch (err) { + throw err; + } + let output: any = {}; + for (const [bucketIndex, bucket] of result.getBucketsMap().entries()) { + output[bucketIndex] = {}; + for (const [encodedId, address] of bucket.getNodeTableMap().entries()) { + output[bucketIndex][encodedId] = {}; + output[bucketIndex][encodedId].host = address.getHost(); + output[bucketIndex][encodedId].port = address.getPort(); + } + } + if (options.format === 'human') output = [result.getBucketsMap().getEntryList()]; + process.stdout.write( + binUtils.outputFormatter({ + type: options.format === 'json' ? 'json' : 'list', + data: output, + }), + ); + } finally { + if (pkClient! != null) await pkClient.stop(); + } + }); + } +} + +export default CommandGetAll; diff --git a/src/bin/nodes/CommandNodes.ts b/src/bin/nodes/CommandNodes.ts index 6827d01f3..0866a088f 100644 --- a/src/bin/nodes/CommandNodes.ts +++ b/src/bin/nodes/CommandNodes.ts @@ -2,6 +2,7 @@ import CommandAdd from './CommandAdd'; import CommandClaim from './CommandClaim'; import CommandFind from './CommandFind'; import CommandPing from './CommandPing'; +import CommandGetAll from './CommandGetAll'; import CommandPolykey from '../CommandPolykey'; class CommandNodes extends CommandPolykey { @@ -13,6 +14,7 @@ class CommandNodes extends CommandPolykey { this.addCommand(new CommandClaim(...args)); this.addCommand(new CommandFind(...args)); this.addCommand(new CommandPing(...args)); + this.addCommand(new CommandGetAll(...args)); } } diff --git a/src/client/GRPCClientClient.ts b/src/client/GRPCClientClient.ts index c69d58d89..78b13ec9d 100644 --- a/src/client/GRPCClientClient.ts +++ b/src/client/GRPCClientClient.ts @@ -901,6 +901,14 @@ class GRPCClientClient extends GRPCClient { )(...args); } + @ready(new clientErrors.ErrorClientClientDestroyed()) + public nodesGetAll(...args) { + return grpcUtils.promisifyUnaryCall( + this.client, + this.client.nodesGetAll, + )(...args); + } + @ready(new clientErrors.ErrorClientClientDestroyed()) public identitiesAuthenticate(...args) { return grpcUtils.promisifyReadableStreamCall( diff --git a/src/client/service/index.ts b/src/client/service/index.ts index 1e74eb9d8..d6b1dff6f 100644 --- a/src/client/service/index.ts +++ b/src/client/service/index.ts @@ -59,6 +59,7 @@ import nodesAdd from './nodesAdd'; import nodesClaim from './nodesClaim'; import nodesFind from './nodesFind'; import nodesPing from './nodesPing'; +import nodesGetAll from './nodesGetAll'; import notificationsClear from './notificationsClear'; import notificationsRead from './notificationsRead'; import notificationsSend from './notificationsSend'; @@ -165,6 +166,7 @@ function createService({ nodesClaim: nodesClaim(container), nodesFind: nodesFind(container), nodesPing: nodesPing(container), + nodesGetAll: nodesGetAll(container), notificationsClear: notificationsClear(container), notificationsRead: notificationsRead(container), notificationsSend: notificationsSend(container), diff --git a/src/client/service/nodesGetAll.ts b/src/client/service/nodesGetAll.ts new file mode 100644 index 000000000..09c354ff2 --- /dev/null +++ b/src/client/service/nodesGetAll.ts @@ -0,0 +1,68 @@ +import type * as grpc from '@grpc/grpc-js'; +import type { Authenticate } from '../types'; +import type { NodeGraph } from '../../nodes'; +import type { KeyManager } from '../../keys'; +import type { NodeId } from '../../nodes/types'; +import { IdInternal } from '@matrixai/id'; +import { utils as nodesUtils } from '../../nodes'; +import { utils as grpcUtils } from '../../grpc'; +import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; + +/** + * Retrieves all nodes from all buckets in the NodeGraph. + */ +function nodesGetAll({ + nodeGraph, + keyManager, + authenticate, +}: { + nodeGraph: NodeGraph; + keyManager: KeyManager; + authenticate: Authenticate; +}) { + return async ( + call: grpc.ServerUnaryCall, + callback: grpc.sendUnaryData, + ): Promise => { + try { + const response = new nodesPB.NodeBuckets(); + const metadata = await authenticate(call.metadata); + call.sendMetadata(metadata); + const buckets = await nodeGraph.getAllBuckets(); + for (const b of buckets) { + let index; + for (const id of Object.keys(b)) { + const encodedId = nodesUtils.encodeNodeId(IdInternal.fromString(id)); + const address = new nodesPB.Address() + .setHost(b[id].address.host) + .setPort(b[id].address.port); + // For every node in every bucket, add it to our message + if (!index) { + index = nodesUtils.calculateBucketIndex( + keyManager.getNodeId(), + IdInternal.fromString(id) + ); + } + // Need to either add node to an existing bucket, or create a new + // bucket (if doesn't exist) + let bucket = response.getBucketsMap().get(index); + if (bucket) { + bucket.getNodeTableMap().set(encodedId, address); + } else { + const newBucket = new nodesPB.NodeTable(); + newBucket.getNodeTableMap().set(encodedId, address); + response.getBucketsMap().set(index, newBucket); + } + } + } + callback(null, response); + return; + } catch (e) { + callback(grpcUtils.fromError(e)); + return; + } + }; +} + +export default nodesGetAll; diff --git a/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts b/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts index 023631a45..067688187 100644 --- a/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts +++ b/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts @@ -27,6 +27,7 @@ interface IClientServiceService extends grpc.ServiceDefinition; responseDeserialize: grpc.deserialize; } +interface IClientServiceService_INodesGetAll extends grpc.MethodDefinition { + path: "/polykey.v1.ClientService/NodesGetAll"; + requestStream: false; + responseStream: false; + requestSerialize: grpc.serialize; + requestDeserialize: grpc.deserialize; + responseSerialize: grpc.serialize; + responseDeserialize: grpc.deserialize; +} interface IClientServiceService_IKeysKeyPairRoot extends grpc.MethodDefinition { path: "/polykey.v1.ClientService/KeysKeyPairRoot"; requestStream: false; @@ -673,6 +683,7 @@ export interface IClientServiceServer extends grpc.UntypedServiceImplementation nodesPing: grpc.handleUnaryCall; nodesClaim: grpc.handleUnaryCall; nodesFind: grpc.handleUnaryCall; + nodesGetAll: grpc.handleUnaryCall; keysKeyPairRoot: grpc.handleUnaryCall; keysKeyPairReset: grpc.handleUnaryCall; keysKeyPairRenew: grpc.handleUnaryCall; @@ -756,6 +767,9 @@ export interface IClientServiceClient { nodesFind(request: polykey_v1_nodes_nodes_pb.Node, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeAddress) => void): grpc.ClientUnaryCall; nodesFind(request: polykey_v1_nodes_nodes_pb.Node, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeAddress) => void): grpc.ClientUnaryCall; nodesFind(request: polykey_v1_nodes_nodes_pb.Node, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeAddress) => void): grpc.ClientUnaryCall; + nodesGetAll(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeBuckets) => void): grpc.ClientUnaryCall; + nodesGetAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeBuckets) => void): grpc.ClientUnaryCall; + nodesGetAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeBuckets) => void): grpc.ClientUnaryCall; keysKeyPairRoot(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_keys_keys_pb.KeyPair) => void): grpc.ClientUnaryCall; keysKeyPairRoot(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_keys_keys_pb.KeyPair) => void): grpc.ClientUnaryCall; keysKeyPairRoot(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_keys_keys_pb.KeyPair) => void): grpc.ClientUnaryCall; @@ -941,6 +955,9 @@ export class ClientServiceClient extends grpc.Client implements IClientServiceCl public nodesFind(request: polykey_v1_nodes_nodes_pb.Node, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeAddress) => void): grpc.ClientUnaryCall; public nodesFind(request: polykey_v1_nodes_nodes_pb.Node, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeAddress) => void): grpc.ClientUnaryCall; public nodesFind(request: polykey_v1_nodes_nodes_pb.Node, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeAddress) => void): grpc.ClientUnaryCall; + public nodesGetAll(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeBuckets) => void): grpc.ClientUnaryCall; + public nodesGetAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeBuckets) => void): grpc.ClientUnaryCall; + public nodesGetAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_nodes_nodes_pb.NodeBuckets) => void): grpc.ClientUnaryCall; public keysKeyPairRoot(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_keys_keys_pb.KeyPair) => void): grpc.ClientUnaryCall; public keysKeyPairRoot(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_keys_keys_pb.KeyPair) => void): grpc.ClientUnaryCall; public keysKeyPairRoot(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_keys_keys_pb.KeyPair) => void): grpc.ClientUnaryCall; diff --git a/src/proto/js/polykey/v1/client_service_grpc_pb.js b/src/proto/js/polykey/v1/client_service_grpc_pb.js index ede2e9470..642127423 100644 --- a/src/proto/js/polykey/v1/client_service_grpc_pb.js +++ b/src/proto/js/polykey/v1/client_service_grpc_pb.js @@ -212,6 +212,17 @@ function deserialize_polykey_v1_nodes_NodeAddress(buffer_arg) { return polykey_v1_nodes_nodes_pb.NodeAddress.deserializeBinary(new Uint8Array(buffer_arg)); } +function serialize_polykey_v1_nodes_NodeBuckets(arg) { + if (!(arg instanceof polykey_v1_nodes_nodes_pb.NodeBuckets)) { + throw new Error('Expected argument of type polykey.v1.nodes.NodeBuckets'); + } + return Buffer.from(arg.serializeBinary()); +} + +function deserialize_polykey_v1_nodes_NodeBuckets(buffer_arg) { + return polykey_v1_nodes_nodes_pb.NodeBuckets.deserializeBinary(new Uint8Array(buffer_arg)); +} + function serialize_polykey_v1_notifications_List(arg) { if (!(arg instanceof polykey_v1_notifications_notifications_pb.List)) { throw new Error('Expected argument of type polykey.v1.notifications.List'); @@ -557,6 +568,17 @@ nodesAdd: { responseSerialize: serialize_polykey_v1_nodes_NodeAddress, responseDeserialize: deserialize_polykey_v1_nodes_NodeAddress, }, + nodesGetAll: { + path: '/polykey.v1.ClientService/NodesGetAll', + requestStream: false, + responseStream: false, + requestType: polykey_v1_utils_utils_pb.EmptyMessage, + responseType: polykey_v1_nodes_nodes_pb.NodeBuckets, + requestSerialize: serialize_polykey_v1_utils_EmptyMessage, + requestDeserialize: deserialize_polykey_v1_utils_EmptyMessage, + responseSerialize: serialize_polykey_v1_nodes_NodeBuckets, + responseDeserialize: deserialize_polykey_v1_nodes_NodeBuckets, + }, // Keys keysKeyPairRoot: { path: '/polykey.v1.ClientService/KeysKeyPairRoot', diff --git a/src/proto/js/polykey/v1/nodes/nodes_pb.d.ts b/src/proto/js/polykey/v1/nodes/nodes_pb.d.ts index 0da62ce43..79d0fbd58 100644 --- a/src/proto/js/polykey/v1/nodes/nodes_pb.d.ts +++ b/src/proto/js/polykey/v1/nodes/nodes_pb.d.ts @@ -98,6 +98,28 @@ export namespace Claim { } } +export class NodeBuckets extends jspb.Message { + + getBucketsMap(): jspb.Map; + clearBucketsMap(): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): NodeBuckets.AsObject; + static toObject(includeInstance: boolean, msg: NodeBuckets): NodeBuckets.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: NodeBuckets, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): NodeBuckets; + static deserializeBinaryFromReader(message: NodeBuckets, reader: jspb.BinaryReader): NodeBuckets; +} + +export namespace NodeBuckets { + export type AsObject = { + + bucketsMap: Array<[number, NodeTable.AsObject]>, + } +} + export class Connection extends jspb.Message { getAId(): string; setAId(value: string): Connection; diff --git a/src/proto/js/polykey/v1/nodes/nodes_pb.js b/src/proto/js/polykey/v1/nodes/nodes_pb.js index 01d29ce4f..8fe0c189f 100644 --- a/src/proto/js/polykey/v1/nodes/nodes_pb.js +++ b/src/proto/js/polykey/v1/nodes/nodes_pb.js @@ -25,6 +25,7 @@ goog.exportSymbol('proto.polykey.v1.nodes.Connection', null, global); goog.exportSymbol('proto.polykey.v1.nodes.CrossSign', null, global); goog.exportSymbol('proto.polykey.v1.nodes.Node', null, global); goog.exportSymbol('proto.polykey.v1.nodes.NodeAddress', null, global); +goog.exportSymbol('proto.polykey.v1.nodes.NodeBuckets', null, global); goog.exportSymbol('proto.polykey.v1.nodes.NodeTable', null, global); goog.exportSymbol('proto.polykey.v1.nodes.Relay', null, global); goog.exportSymbol('proto.polykey.v1.nodes.Signature', null, global); @@ -112,6 +113,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.polykey.v1.nodes.Claim.displayName = 'proto.polykey.v1.nodes.Claim'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.polykey.v1.nodes.NodeBuckets = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.polykey.v1.nodes.NodeBuckets, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.polykey.v1.nodes.NodeBuckets.displayName = 'proto.polykey.v1.nodes.NodeBuckets'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -956,6 +978,139 @@ proto.polykey.v1.nodes.Claim.prototype.setForceInvite = function(value) { +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.polykey.v1.nodes.NodeBuckets.prototype.toObject = function(opt_includeInstance) { + return proto.polykey.v1.nodes.NodeBuckets.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.polykey.v1.nodes.NodeBuckets} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.polykey.v1.nodes.NodeBuckets.toObject = function(includeInstance, msg) { + var f, obj = { + bucketsMap: (f = msg.getBucketsMap()) ? f.toObject(includeInstance, proto.polykey.v1.nodes.NodeTable.toObject) : [] + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.polykey.v1.nodes.NodeBuckets} + */ +proto.polykey.v1.nodes.NodeBuckets.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.polykey.v1.nodes.NodeBuckets; + return proto.polykey.v1.nodes.NodeBuckets.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.polykey.v1.nodes.NodeBuckets} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.polykey.v1.nodes.NodeBuckets} + */ +proto.polykey.v1.nodes.NodeBuckets.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = msg.getBucketsMap(); + reader.readMessage(value, function(message, reader) { + jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readInt32, jspb.BinaryReader.prototype.readMessage, proto.polykey.v1.nodes.NodeTable.deserializeBinaryFromReader, 0, new proto.polykey.v1.nodes.NodeTable()); + }); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.polykey.v1.nodes.NodeBuckets.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.polykey.v1.nodes.NodeBuckets.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.polykey.v1.nodes.NodeBuckets} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.polykey.v1.nodes.NodeBuckets.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getBucketsMap(true); + if (f && f.getLength() > 0) { + f.serializeBinary(1, writer, jspb.BinaryWriter.prototype.writeInt32, jspb.BinaryWriter.prototype.writeMessage, proto.polykey.v1.nodes.NodeTable.serializeBinaryToWriter); + } +}; + + +/** + * map buckets = 1; + * @param {boolean=} opt_noLazyCreate Do not create the map if + * empty, instead returning `undefined` + * @return {!jspb.Map} + */ +proto.polykey.v1.nodes.NodeBuckets.prototype.getBucketsMap = function(opt_noLazyCreate) { + return /** @type {!jspb.Map} */ ( + jspb.Message.getMapField(this, 1, opt_noLazyCreate, + proto.polykey.v1.nodes.NodeTable)); +}; + + +/** + * Clears values from the map. The map will be non-null. + * @return {!proto.polykey.v1.nodes.NodeBuckets} returns this + */ +proto.polykey.v1.nodes.NodeBuckets.prototype.clearBucketsMap = function() { + this.getBucketsMap().clear(); + return this;}; + + + + + if (jspb.Message.GENERATE_TO_OBJECT) { /** * Creates an object representation of this proto. diff --git a/src/proto/schemas/polykey/v1/client_service.proto b/src/proto/schemas/polykey/v1/client_service.proto index 57788c678..81782f13b 100644 --- a/src/proto/schemas/polykey/v1/client_service.proto +++ b/src/proto/schemas/polykey/v1/client_service.proto @@ -26,6 +26,7 @@ service ClientService { rpc NodesPing(polykey.v1.nodes.Node) returns (polykey.v1.utils.StatusMessage); rpc NodesClaim(polykey.v1.nodes.Claim) returns (polykey.v1.utils.StatusMessage); rpc NodesFind(polykey.v1.nodes.Node) returns (polykey.v1.nodes.NodeAddress); + rpc NodesGetAll(polykey.v1.utils.EmptyMessage) returns (polykey.v1.nodes.NodeBuckets); // Keys rpc KeysKeyPairRoot (polykey.v1.utils.EmptyMessage) returns (polykey.v1.keys.KeyPair); diff --git a/src/proto/schemas/polykey/v1/nodes/nodes.proto b/src/proto/schemas/polykey/v1/nodes/nodes.proto index 4c5d64a51..bd2b54f85 100644 --- a/src/proto/schemas/polykey/v1/nodes/nodes.proto +++ b/src/proto/schemas/polykey/v1/nodes/nodes.proto @@ -25,6 +25,11 @@ message Claim { bool force_invite = 2; } +// Bucket index -> a node bucket (from NodeGraph) +message NodeBuckets { + map buckets = 1; +} + // Agent specific. message Connection { From 9b53a0a55e7d77ef28883cf0aa3a276379cd22a2 Mon Sep 17 00:00:00 2001 From: Roger Qiu Date: Mon, 21 Feb 2022 17:07:49 +1100 Subject: [PATCH 075/137] fix: general fixes - added getBuckets test for distance and lastUpdated order - resetting buckets work - changing utility names --- src/bin/nodes/CommandGetAll.ts | 8 +- src/client/service/nodesGetAll.ts | 18 +- src/network/utils.ts | 4 +- src/nodes/NodeConnectionManager.ts | 50 +- src/nodes/NodeGraph.ts | 739 +++++++---- src/nodes/NodeManager.ts | 40 +- src/nodes/errors.ts | 6 + src/nodes/types.ts | 59 +- src/nodes/utils.ts | 293 +++- src/types.ts | 20 + src/utils/index.ts | 1 + src/utils/random.ts | 11 + src/utils/utils.ts | 63 + src/validation/utils.ts | 16 +- test-iterator.ts | 31 + test-lexi.ts | 4 + test-nodegraph.ts | 107 ++ test-nodeidgen.ts | 44 + test-order.ts | 98 ++ test-sorting.ts | 28 + test-split.ts | 37 + test-trie.ts | 29 + tests/acl/ACL.test.ts | 29 +- tests/agent/utils.ts | 5 +- tests/bin/nodes/add.test.ts | 3 +- tests/bin/vaults/vaults.test.ts | 8 +- tests/claims/utils.test.ts | 5 +- .../service/gestaltsDiscoveryByNode.test.ts | 3 +- .../client/service/notificationsRead.test.ts | 3 +- tests/discovery/Discovery.test.ts | 2 +- tests/gestalts/GestaltGraph.test.ts | 10 +- tests/grpc/GRPCClient.test.ts | 4 +- tests/identities/IdentitiesManager.test.ts | 4 +- tests/network/Proxy.test.ts | 7 +- tests/nodes/NodeConnection.test.ts | 11 +- .../NodeConnectionManager.general.test.ts | 15 +- tests/nodes/NodeGraph.test.ts | 1175 +++++++++-------- tests/nodes/NodeGraph.test.ts.old | 624 +++++++++ tests/nodes/utils.test.ts | 195 ++- tests/nodes/utils.ts | 22 +- tests/notifications/utils.test.ts | 7 +- tests/sigchain/Sigchain.test.ts | 23 +- tests/status/Status.test.ts | 8 +- tests/utils.ts | 208 +-- tests/vaults/VaultOps.test.ts | 3 +- 45 files changed, 2977 insertions(+), 1103 deletions(-) create mode 100644 src/utils/random.ts create mode 100644 test-iterator.ts create mode 100644 test-lexi.ts create mode 100644 test-nodegraph.ts create mode 100644 test-nodeidgen.ts create mode 100644 test-order.ts create mode 100644 test-sorting.ts create mode 100644 test-split.ts create mode 100644 test-trie.ts create mode 100644 tests/nodes/NodeGraph.test.ts.old diff --git a/src/bin/nodes/CommandGetAll.ts b/src/bin/nodes/CommandGetAll.ts index 91f69f681..5d1b5a8fc 100644 --- a/src/bin/nodes/CommandGetAll.ts +++ b/src/bin/nodes/CommandGetAll.ts @@ -54,13 +54,17 @@ class CommandGetAll extends CommandPolykey { let output: any = {}; for (const [bucketIndex, bucket] of result.getBucketsMap().entries()) { output[bucketIndex] = {}; - for (const [encodedId, address] of bucket.getNodeTableMap().entries()) { + for (const [encodedId, address] of bucket + .getNodeTableMap() + .entries()) { output[bucketIndex][encodedId] = {}; output[bucketIndex][encodedId].host = address.getHost(); output[bucketIndex][encodedId].port = address.getPort(); } } - if (options.format === 'human') output = [result.getBucketsMap().getEntryList()]; + if (options.format === 'human') { + output = [result.getBucketsMap().getEntryList()]; + } process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', diff --git a/src/client/service/nodesGetAll.ts b/src/client/service/nodesGetAll.ts index 09c354ff2..6a658fedd 100644 --- a/src/client/service/nodesGetAll.ts +++ b/src/client/service/nodesGetAll.ts @@ -3,11 +3,11 @@ import type { Authenticate } from '../types'; import type { NodeGraph } from '../../nodes'; import type { KeyManager } from '../../keys'; import type { NodeId } from '../../nodes/types'; +import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import { IdInternal } from '@matrixai/id'; import { utils as nodesUtils } from '../../nodes'; import { utils as grpcUtils } from '../../grpc'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; -import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; /** * Retrieves all nodes from all buckets in the NodeGraph. @@ -29,24 +29,28 @@ function nodesGetAll({ const response = new nodesPB.NodeBuckets(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const buckets = await nodeGraph.getAllBuckets(); + // FIXME: + // const buckets = await nodeGraph.getAllBuckets(); + const buckets: any = []; for (const b of buckets) { let index; for (const id of Object.keys(b)) { - const encodedId = nodesUtils.encodeNodeId(IdInternal.fromString(id)); + const encodedId = nodesUtils.encodeNodeId( + IdInternal.fromString(id), + ); const address = new nodesPB.Address() .setHost(b[id].address.host) .setPort(b[id].address.port); // For every node in every bucket, add it to our message if (!index) { - index = nodesUtils.calculateBucketIndex( + index = nodesUtils.bucketIndex( keyManager.getNodeId(), - IdInternal.fromString(id) + IdInternal.fromString(id), ); } - // Need to either add node to an existing bucket, or create a new + // Need to either add node to an existing bucket, or create a new // bucket (if doesn't exist) - let bucket = response.getBucketsMap().get(index); + const bucket = response.getBucketsMap().get(index); if (bucket) { bucket.getNodeTableMap().set(encodedId, address); } else { diff --git a/src/network/utils.ts b/src/network/utils.ts index 1df7faa7f..c5786a754 100644 --- a/src/network/utils.ts +++ b/src/network/utils.ts @@ -45,10 +45,12 @@ function isHostname(hostname: any): hostname is Hostname { /** * Ports must be numbers between 0 and 65535 inclusive + * If connect is true, then port must be a number between 1 and 65535 inclusive */ -function isPort(port: any): port is Port { +function isPort(port: any, connect: boolean = false): port is Port { if (typeof port !== 'number') return false; if (port < 0 || port > 65535) return false; + if (connect && port === 0) return false; return true; } diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index e51ccc803..5c1b34cb7 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -10,6 +10,7 @@ import type { NodeId, NodeIdString, SeedNodes, + NodeEntry, } from './types'; import type { DBTransaction } from '@matrixai/db'; import { withF } from '@matrixai/resources'; @@ -367,7 +368,7 @@ class NodeConnectionManager { public async findNode(targetNodeId: NodeId): Promise { // First check if we already have an existing ID -> address record - let address = await this.nodeGraph.getNode(targetNodeId); + let address = (await this.nodeGraph.getNode(targetNodeId))?.address; // Otherwise, attempt to locate it by contacting network if (address == null) { address = await this.getClosestGlobalNodes(targetNodeId); @@ -461,7 +462,7 @@ class NodeConnectionManager { // getClosestGlobalNodes()? const contacted: { [nodeId: string]: boolean } = {}; // Iterate until we've found and contacted k nodes - while (Object.keys(contacted).length <= this.nodeGraph.maxNodesPerBucket) { + while (Object.keys(contacted).length <= this.nodeGraph.nodeBucketLimit) { // While (!foundTarget) { // Remove the node from the front of the array const nextNode = shortlist.shift(); @@ -492,27 +493,31 @@ class NodeConnectionManager { ); // Check to see if any of these are the target node. At the same time, add // them to the shortlist - for (const nodeData of foundClosest) { + for (const [nodeId, nodeData] of foundClosest) { // Ignore any nodes that have been contacted - if (contacted[nodeData.id]) { + if (contacted[nodeId]) { continue; } - if (nodeData.id.equals(targetNodeId)) { - await this.nodeGraph.setNode(nodeData.id, nodeData.address); + if (nodeId.equals(targetNodeId)) { + await this.nodeGraph.setNode(nodeId, nodeData.address); foundAddress = nodeData.address; // We have found the target node, so we can stop trying to look for it // in the shortlist break; } - shortlist.push(nodeData); + shortlist.push([nodeId, nodeData]); } // To make the number of jumps relatively short, should connect to the nodes // closest to the target first, and ask if they know of any closer nodes // than we can simply unshift the first (closest) element from the shortlist - shortlist.sort(function (a: NodeData, b: NodeData) { - if (a.distance > b.distance) { + const distance = (nodeId: NodeId) => + nodesUtils.nodeDistance(targetNodeId, nodeId); + shortlist.sort(function ([nodeIdA], [nodeIdB]) { + const distanceA = distance(nodeIdA); + const distanceB = distance(nodeIdB); + if (distanceA > distanceB) { return 1; - } else if (a.distance < b.distance) { + } else if (distanceA < distanceB) { return -1; } else { return 0; @@ -533,7 +538,7 @@ class NodeConnectionManager { public async getRemoteNodeClosestNodes( nodeId: NodeId, targetNodeId: NodeId, - ): Promise> { + ): Promise> { // Construct the message const nodeIdMessage = new nodesPB.Node(); nodeIdMessage.setNodeId(nodesUtils.encodeNodeId(targetNodeId)); @@ -541,20 +546,22 @@ class NodeConnectionManager { return this.withConnF(nodeId, async (connection) => { const client = await connection.getClient(); const response = await client.nodesClosestLocalNodesGet(nodeIdMessage); - const nodes: Array = []; + const nodes: Array<[NodeId, NodeData]> = []; // Loop over each map element (from the returned response) and populate nodes response.getNodeTableMap().forEach((address, nodeIdString: string) => { const nodeId = nodesUtils.decodeNodeId(nodeIdString); // If the nodeId is not valid we don't add it to the list of nodes if (nodeId != null) { - nodes.push({ - id: nodeId, - address: { - host: address.getHost() as Host | Hostname, - port: address.getPort() as Port, + nodes.push([ + nodeId, + { + address: { + host: address.getHost() as Host | Hostname, + port: address.getPort() as Port, + }, + lastUpdated: 0, // FIXME? }, - distance: nodesUtils.calculateDistance(targetNodeId, nodeId), - }); + ]); } }); return nodes; @@ -588,8 +595,9 @@ class NodeConnectionManager { seedNodeId, this.keyManager.getNodeId(), ); - for (const n of nodes) { - await this.nodeGraph.setNode(n.id, n.address); + for (const [nodeId, nodeData] of nodes) { + // FIXME: this should be the `nodeManager.setNode` + await this.nodeGraph.setNode(nodeId, nodeData.address); } } } diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index 4d623dbce..9fa404896 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -1,21 +1,27 @@ -import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; -import type { NodeAddress, NodeBucket, NodeId } from './types'; +import type { DB, DBTransaction, LevelPath } from '@matrixai/db'; +import type { + NodeId, + NodeAddress, + NodeBucket, + NodeData, + NodeBucketMeta, + NodeBucketIndex, + NodeGraphSpace, +} from './types'; import type KeyManager from '../keys/KeyManager'; -import type { Host, Hostname, Port } from '../network/types'; -import lexi from 'lexicographic-integer'; import Logger from '@matrixai/logger'; import { CreateDestroyStartStop, ready, } from '@matrixai/async-init/dist/CreateDestroyStartStop'; import { IdInternal } from '@matrixai/id'; -import { withF } from '@matrixai/resources'; import * as nodesUtils from './utils'; import * as nodesErrors from './errors'; +import { getUnixtime, never } from '../utils'; /** * NodeGraph is an implementation of Kademlia for maintaining peer to peer information - * We maintain a map of buckets. Where each bucket has k number of node infos + * It is a database of fixed-size buckets, where each bucket contains NodeId -> NodeData */ interface NodeGraph extends CreateDestroyStartStop {} @CreateDestroyStartStop( @@ -26,11 +32,13 @@ class NodeGraph { public static async createNodeGraph({ db, keyManager, + nodeIdBits = 256, logger = new Logger(this.name), fresh = false, }: { db: DB; keyManager: KeyManager; + nodeIdBits?: number; logger?: Logger; fresh?: boolean; }): Promise { @@ -38,6 +46,7 @@ class NodeGraph { const nodeGraph = new NodeGraph({ db, keyManager, + nodeIdBits, logger, }); await nodeGraph.start({ fresh }); @@ -46,339 +55,565 @@ class NodeGraph { } /** - * Max number of nodes in each k-bucket (a.k.a. k) + * Bit size of the NodeIds + * This equals the number of buckets */ - public readonly maxNodesPerBucket: number = 20; + public readonly nodeIdBits: number; + /** + * Max number of nodes in each k-bucket + */ + public readonly nodeBucketLimit: number = 20; protected logger: Logger; protected db: DB; protected keyManager: KeyManager; + protected space: NodeGraphSpace; protected nodeGraphDbPath: LevelPath = [this.constructor.name]; - /** - * Buckets stores NodeBucketIndex -> NodeBucket - */ - protected nodeGraphBucketsDbPath: LevelPath = [ - this.constructor.name, - 'buckets', - ]; + protected nodeGraphMetaDbPath: LevelPath; + protected nodeGraphBucketsDbPath: LevelPath; + protected nodeGraphLastUpdatedDbPath: LevelPath; constructor({ db, keyManager, + nodeIdBits, logger, }: { db: DB; keyManager: KeyManager; + nodeIdBits: number; logger: Logger; }) { this.logger = logger; this.db = db; this.keyManager = keyManager; + this.nodeIdBits = nodeIdBits; } public async start({ fresh = false, - }: { - fresh?: boolean; - } = {}) { + }: { fresh?: boolean } = {}): Promise { this.logger.info(`Starting ${this.constructor.name}`); - if (fresh) { - await this.db.clear(this.nodeGraphDbPath); - } + const space = await this.db.withTransactionF(async (tran) => { + if (fresh) { + await tran.clear(this.nodeGraphDbPath); + } + // Space key is used to create a swappable sublevel + // when remapping the buckets during `this.refreshBuckets` + return await this.setupSpace(tran); + }); + // Bucket metadata sublevel: `!meta!! -> value` + this.nodeGraphMetaDbPath = [...this.nodeGraphDbPath, 'meta' + space]; + // Bucket sublevel: `!buckets!! -> NodeData` + // The BucketIndex can range from 0 to NodeId bitsize minus 1 + // So 256 bits means 256 buckets of 0 to 255 + this.nodeGraphBucketsDbPath = [...this.nodeGraphDbPath, 'buckets' + space]; + // Last updated sublevel: `!lastUpdated!!- -> NodeId` + // This is used as a sorted index of the NodeId by `lastUpdated` timestamp + // The `NodeId` must be appended in the key in order to disambiguate `NodeId` with same `lastUpdated` timestamp + this.nodeGraphLastUpdatedDbPath = [ + ...this.nodeGraphDbPath, + 'lastUpdated' + space, + ]; + this.space = space; this.logger.info(`Started ${this.constructor.name}`); } - public async stop() { + public async stop(): Promise { this.logger.info(`Stopping ${this.constructor.name}`); this.logger.info(`Stopped ${this.constructor.name}`); } - public async destroy() { + public async destroy(): Promise { this.logger.info(`Destroying ${this.constructor.name}`); + // If the DB was stopped, the existing sublevel `this.nodeGraphDb` will not be valid + // Therefore we recreate the sublevel here await this.db.clear(this.nodeGraphDbPath); this.logger.info(`Destroyed ${this.constructor.name}`); } - @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async withTransactionF( - f: (tran: DBTransaction) => Promise, - ): Promise { - return withF([this.db.transaction()], ([tran]) => f(tran)); - } - /** - * Retrieves the node Address - * @param nodeId node ID of the target node - * @param tran - * @returns Node Address of the target node + * Sets up the space key + * The space string is suffixed to the `buckets` and `meta` sublevels + * This is used to allow swapping of sublevels when remapping buckets + * during `this.refreshBuckets` */ - @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async getNode( - nodeId: NodeId, - tran?: DBTransaction, - ): Promise { - if (tran == null) { - return this.withTransactionF(async (tran) => this.getNode(nodeId, tran)); - } - const bucketIndex = this.getBucketIndex(nodeId); - const bucketPath = [ - ...this.nodeGraphBucketsDbPath, - bucketIndex, - ] as unknown as KeyPath; - const bucket = await tran.get(bucketPath); - if (bucket != null && nodeId in bucket) { - return bucket[nodeId].address; + protected async setupSpace(tran: DBTransaction): Promise { + let space = await tran.get([ + ...this.nodeGraphDbPath, + 'space', + ]); + if (space != null) { + return space; } - return; + space = '0'; + await tran.put([...this.nodeGraphDbPath, 'space'], space); + return space; } - /** - * Determines whether a node ID -> node address mapping exists in this node's - * node table. - * @param targetNodeId the node ID of the node to find - * @param tran - * @returns true if the node exists in the table, false otherwise - */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async knowsNode( - targetNodeId: NodeId, - tran?: DBTransaction, - ): Promise { - return !!(await this.getNode(targetNodeId, tran)); + public async getNode( + nodeId: NodeId, + tran: DBTransaction, + ): Promise { + const [bucketIndex] = this.bucketIndex(nodeId); + const bucketDomain = [ + ...this.nodeGraphBucketsDbPath, + nodesUtils.bucketKey(bucketIndex), + nodesUtils.bucketDbKey(nodeId), + ]; + return await tran.get(bucketDomain); } /** - * Returns the specified bucket if it exists - * @param bucketIndex - * @param tran + * Get all nodes + * Nodes are always sorted by `NodeBucketIndex` first + * Then secondly by the node IDs + * The `order` parameter applies to both, for example possible sorts: + * NodeBucketIndex asc, NodeID asc + * NodeBucketIndex desc, NodeId desc */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async getBucket( - bucketIndex: number, - tran?: DBTransaction, - ): Promise { - if (tran == null) { - return this.withTransactionF(async (tran) => - this.getBucket(bucketIndex, tran), - ); - } - const bucketPath = [ - ...this.nodeGraphBucketsDbPath, - lexi.pack(bucketIndex, 'hex'), - ] as unknown as KeyPath; - const bucket = await tran.get(bucketPath); - // Cast the non-primitive types correctly (ensures type safety when using them) - for (const nodeId in bucket) { - bucket[nodeId].address.host = bucket[nodeId].address.host as - | Host - | Hostname; - bucket[nodeId].address.port = bucket[nodeId].address.port as Port; - bucket[nodeId].lastUpdated = new Date(bucket[nodeId].lastUpdated); + public async *getNodes( + order: 'asc' | 'desc' = 'asc', + tran: DBTransaction, + ): AsyncGenerator<[NodeId, NodeData]> { + for await (const [key, nodeData] of tran.iterator( + { + reverse: order !== 'asc', + valueAsBuffer: false, + }, + this.nodeGraphBucketsDbPath, + )) { + const { nodeId } = nodesUtils.parseBucketsDbKey(key as unknown as Buffer); + yield [nodeId, nodeData]; } - return bucket; } - /** - * Sets a node to the bucket database - * This may delete an existing node if the bucket is filled up - */ + @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async setNode( nodeId: NodeId, nodeAddress: NodeAddress, - tran?: DBTransaction, + tran: DBTransaction, ): Promise { - if (tran == null) { - return this.withTransactionF(async (tran) => - this.setNode(nodeId, nodeAddress, tran), + const [bucketIndex, bucketKey] = this.bucketIndex(nodeId); + const lastUpdatedPath = [...this.nodeGraphLastUpdatedDbPath, bucketKey]; + const bucketPath = [...this.nodeGraphBucketsDbPath, bucketKey]; + const nodeData = await tran.get([ + ...bucketPath, + nodesUtils.bucketDbKey(nodeId), + ]); + // If this is a new entry, check the bucket limit + if (nodeData == null) { + const count = await this.getBucketMetaProp(bucketIndex, 'count', tran); + if (count < this.nodeBucketLimit) { + // Increment the bucket count + await this.setBucketMetaProp(bucketIndex, 'count', count + 1, tran); + } else { + // Remove the oldest entry in the bucket + let oldestLastUpdatedKey: Buffer; + let oldestNodeId: NodeId; + for await (const [key] of tran.iterator( + { + limit: 1, + values: false, + }, + this.nodeGraphLastUpdatedDbPath, + )) { + oldestLastUpdatedKey = key as unknown as Buffer; + ({ nodeId: oldestNodeId } = nodesUtils.parseLastUpdatedBucketDbKey( + key as unknown as Buffer, + )); + } + await tran.del([...bucketPath, oldestNodeId!.toBuffer()]); + await tran.del([...lastUpdatedPath, oldestLastUpdatedKey!]); + } + } else { + // This is an existing entry, so the index entry must be reset + const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( + nodeData.lastUpdated, + nodeId, ); + await tran.del([...lastUpdatedPath, lastUpdatedKey]); } - const bucketIndex = this.getBucketIndex(nodeId); - const bucketPath = [ - ...this.nodeGraphBucketsDbPath, - bucketIndex, - ] as unknown as KeyPath; - let bucket = await tran.get(bucketPath); - if (bucket == null) { - bucket = {}; - } - bucket[nodeId] = { + const lastUpdated = getUnixtime(); + await tran.put([...bucketPath, nodesUtils.bucketDbKey(nodeId)], { address: nodeAddress, - lastUpdated: new Date(), - }; - // Perform the check on size after we add/update the node. If it's an update, - // then we don't need to perform the deletion - let bucketEntries = Object.entries(bucket); - if (bucketEntries.length > this.maxNodesPerBucket) { - const leastActive = bucketEntries.reduce((prev, curr) => { - return new Date(prev[1].lastUpdated) < new Date(curr[1].lastUpdated) - ? prev - : curr; - }); - delete bucket[leastActive[0]]; - bucketEntries = Object.entries(bucket); - // For safety, make sure that the bucket is actually at maxNodesPerBucket - if (bucketEntries.length !== this.maxNodesPerBucket) { - throw new nodesErrors.ErrorNodeGraphOversizedBucket(); - } + lastUpdated, + }); + const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( + lastUpdated, + nodeId, + ); + await tran.put( + [...lastUpdatedPath, lastUpdatedKey], + nodesUtils.bucketDbKey(nodeId), + true, + ); + } + + @ready(new nodesErrors.ErrorNodeGraphNotRunning()) + public async unsetNode(nodeId: NodeId, tran: DBTransaction): Promise { + const [bucketIndex, bucketKey] = this.bucketIndex(nodeId); + const bucketPath = [...this.nodeGraphBucketsDbPath, bucketKey]; + const lastUpdatedPath = [...this.nodeGraphLastUpdatedDbPath, bucketKey]; + const nodeData = await tran.get([ + ...bucketPath, + nodesUtils.bucketDbKey(nodeId), + ]); + if (nodeData != null) { + const count = await this.getBucketMetaProp(bucketIndex, 'count', tran); + await this.setBucketMetaProp(bucketIndex, 'count', count - 1, tran); + await tran.del([...bucketPath, nodesUtils.bucketDbKey(nodeId)]); + const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( + nodeData.lastUpdated, + nodeId, + ); + await tran.del([...lastUpdatedPath, lastUpdatedKey]); } - await tran.put(bucketPath, bucket); } /** - * Updates an existing node - * It will update the lastUpdated time - * Optionally it can replace the NodeAddress + * Gets a bucket + * The bucket's node IDs is sorted lexicographically by default + * Alternatively you can acquire them sorted by lastUpdated timestamp + * or by distance to the own NodeId */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async updateNode( - nodeId: NodeId, - nodeAddress?: NodeAddress, - tran?: DBTransaction, - ): Promise { - if (tran == null) { - return this.withTransactionF(async (tran) => - this.updateNode(nodeId, nodeAddress, tran), + public async getBucket( + bucketIndex: NodeBucketIndex, + sort: 'nodeId' | 'distance' | 'lastUpdated' = 'nodeId', + order: 'asc' | 'desc' = 'asc', + tran: DBTransaction, + ): Promise { + if (bucketIndex < 0 || bucketIndex >= this.nodeIdBits) { + throw new nodesErrors.ErrorNodeGraphBucketIndex( + `bucketIndex must be between 0 and ${this.nodeIdBits - 1} inclusive`, ); } - const bucketIndex = this.getBucketIndex(nodeId); - const bucketPath = [ - ...this.nodeGraphBucketsDbPath, - bucketIndex, - ] as unknown as KeyPath; - const bucket = await tran.get(bucketPath); - if (bucket != null && nodeId in bucket) { - bucket[nodeId].lastUpdated = new Date(); - if (nodeAddress != null) { - bucket[nodeId].address = nodeAddress; + const bucketKey = nodesUtils.bucketKey(bucketIndex); + const bucket: NodeBucket = []; + if (sort === 'nodeId' || sort === 'distance') { + for await (const [key, nodeData] of tran.iterator( + { + reverse: order !== 'asc', + valueAsBuffer: false, + }, + [...this.nodeGraphBucketsDbPath, bucketKey], + )) { + const nodeId = nodesUtils.parseBucketDbKey(key as unknown as Buffer); + bucket.push([nodeId, nodeData]); + } + if (sort === 'distance') { + nodesUtils.bucketSortByDistance( + bucket, + this.keyManager.getNodeId(), + order, + ); + } + } else if (sort === 'lastUpdated') { + const bucketDbIterator = tran.iterator( + { valueAsBuffer: false }, + [...this.nodeGraphBucketsDbPath, bucketKey], + ); + try { + for await (const [, nodeIdBuffer] of tran.iterator( + { + reverse: order !== 'asc', + }, + [...this.nodeGraphLastUpdatedDbPath, bucketKey], + )) { + const nodeId = IdInternal.fromBuffer(nodeIdBuffer); + bucketDbIterator.seek(nodeIdBuffer); + // @ts-ignore + const iteratorResult = await bucketDbIterator.next(); + if (iteratorResult == null) never(); + const [, nodeData] = iteratorResult; + bucket.push([nodeId, nodeData]); + } + } finally { + // @ts-ignore + await bucketDbIterator.end(); } - await tran.put(bucketPath, bucket); - } else { - throw new nodesErrors.ErrorNodeGraphNodeIdNotFound(); } + return bucket; } /** - * Removes a node from the bucket database - * @param nodeId - * @param tran + * Gets all buckets + * Buckets are always sorted by `NodeBucketIndex` first + * Then secondly by the `sort` parameter + * The `order` parameter applies to both, for example possible sorts: + * NodeBucketIndex asc, NodeID asc + * NodeBucketIndex desc, NodeId desc + * NodeBucketIndex asc, distance asc + * NodeBucketIndex desc, distance desc + * NodeBucketIndex asc, lastUpdated asc + * NodeBucketIndex desc, lastUpdated desc */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async unsetNode(nodeId: NodeId, tran?: DBTransaction): Promise { - if (tran == null) { - return this.withTransactionF(async (tran) => - this.unsetNode(nodeId, tran), + public async *getBuckets( + sort: 'nodeId' | 'distance' | 'lastUpdated' = 'nodeId', + order: 'asc' | 'desc' = 'asc', + tran: DBTransaction, + ): AsyncGenerator<[NodeBucketIndex, NodeBucket]> { + let bucketIndex: NodeBucketIndex | undefined = undefined; + let bucket: NodeBucket = []; + if (sort === 'nodeId' || sort === 'distance') { + for await (const [key, nodeData] of tran.iterator( + { + reverse: order !== 'asc', + valueAsBuffer: false, + }, + this.nodeGraphBucketsDbPath, + )) { + const { bucketIndex: bucketIndex_, nodeId } = + nodesUtils.parseBucketsDbKey(key as unknown as Buffer); + if (bucketIndex == null) { + // First entry of the first bucket + bucketIndex = bucketIndex_; + bucket.push([nodeId, nodeData]); + } else if (bucketIndex === bucketIndex_) { + // Subsequent entries of the same bucket + bucket.push([nodeId, nodeData]); + } else if (bucketIndex !== bucketIndex_) { + // New bucket + if (sort === 'distance') { + nodesUtils.bucketSortByDistance( + bucket, + this.keyManager.getNodeId(), + order, + ); + } + yield [bucketIndex, bucket]; + bucketIndex = bucketIndex_; + bucket = [[nodeId, nodeData]]; + } + } + // Yield the last bucket if it exists + if (bucketIndex != null) { + if (sort === 'distance') { + nodesUtils.bucketSortByDistance( + bucket, + this.keyManager.getNodeId(), + order, + ); + } + yield [bucketIndex, bucket]; + } + } else if (sort === 'lastUpdated') { + const bucketsDbIterator = tran.iterator( + { valueAsBuffer: false }, + this.nodeGraphBucketsDbPath, ); + try { + for await (const [key] of tran.iterator( + { + reverse: order !== 'asc', + }, + this.nodeGraphLastUpdatedDbPath, + )) { + const { bucketIndex: bucketIndex_, nodeId } = + nodesUtils.parseLastUpdatedBucketsDbKey(key as unknown as Buffer); + bucketsDbIterator.seek(nodesUtils.bucketsDbKey(bucketIndex_, nodeId)); + // @ts-ignore + const iteratorResult = await bucketsDbIterator.next(); + if (iteratorResult == null) never(); + const [, nodeData] = iteratorResult; + if (bucketIndex == null) { + // First entry of the first bucket + bucketIndex = bucketIndex_; + bucket.push([nodeId, nodeData]); + } else if (bucketIndex === bucketIndex_) { + // Subsequent entries of the same bucket + bucket.push([nodeId, nodeData]); + } else if (bucketIndex !== bucketIndex_) { + // New bucket + yield [bucketIndex, bucket]; + bucketIndex = bucketIndex_; + bucket = [[nodeId, nodeData]]; + } + } + // Yield the last bucket if it exists + if (bucketIndex != null) { + yield [bucketIndex, bucket]; + } + } finally { + // @ts-ignore + await bucketsDbIterator.end(); + } } - const bucketIndex = this.getBucketIndex(nodeId); - const bucketPath = [ - ...this.nodeGraphBucketsDbPath, - bucketIndex, - ] as unknown as KeyPath; - const bucket = await tran.get(bucketPath); - if (bucket == null) { - return; - } - delete bucket[nodeId]; - if (Object.keys(bucket).length === 0) { - await tran.del(bucketPath); - } else { - await tran.put(bucketPath, bucket); + } + + @ready(new nodesErrors.ErrorNodeGraphNotRunning()) + public async resetBuckets( + nodeIdOwn: NodeId, + tran: DBTransaction, + ): Promise { + // Setup new space + const spaceNew = this.space === '0' ? '1' : '0'; + const nodeGraphMetaDbPathNew = [...this.nodeGraphDbPath, 'meta' + spaceNew]; + const nodeGraphBucketsDbPathNew = [ + ...this.nodeGraphDbPath, + 'buckets' + spaceNew, + ]; + const nodeGraphLastUpdatedDbPathNew = [ + ...this.nodeGraphDbPath, + 'index' + spaceNew, + ]; + // Clear the new space (in case it wasn't cleaned properly last time) + await tran.clear(nodeGraphMetaDbPathNew); + await tran.clear(nodeGraphBucketsDbPathNew); + await tran.clear(nodeGraphLastUpdatedDbPathNew); + // Iterating over all entries across all buckets + + for await (const [key, nodeData] of tran.iterator( + { valueAsBuffer: false }, + this.nodeGraphBucketsDbPath, + )) { + // The key is a combined bucket key and node ID + const { nodeId } = nodesUtils.parseBucketsDbKey(key as unknown as Buffer); + // If the new own node ID is one of the existing node IDs, it is just dropped + // We only map to the new bucket if it isn't one of the existing node IDs + if (nodeId.equals(nodeIdOwn)) { + continue; + } + const bucketIndexNew = nodesUtils.bucketIndex(nodeIdOwn, nodeId); + const bucketKeyNew = nodesUtils.bucketKey(bucketIndexNew); + const metaPathNew = [...nodeGraphMetaDbPathNew, bucketKeyNew]; + const bucketPathNew = [...nodeGraphBucketsDbPathNew, bucketKeyNew]; + const indexPathNew = [...nodeGraphLastUpdatedDbPathNew, bucketKeyNew]; + const countNew = (await tran.get([...metaPathNew, 'count'])) ?? 0; + if (countNew < this.nodeBucketLimit) { + await tran.put([...metaPathNew, 'count'], countNew + 1); + } else { + let oldestIndexKey: Buffer | undefined = undefined; + let oldestNodeId: NodeId | undefined = undefined; + for await (const [key] of tran.iterator( + { + limit: 1, + }, + indexPathNew, + )) { + oldestIndexKey = key as unknown as Buffer; + ({ nodeId: oldestNodeId } = nodesUtils.parseLastUpdatedBucketDbKey( + key as unknown as Buffer, + )); + } + await tran.del([ + ...bucketPathNew, + nodesUtils.bucketDbKey(oldestNodeId!), + ]); + await tran.del([...indexPathNew, oldestIndexKey!]); + } + await tran.put( + [...bucketPathNew, nodesUtils.bucketDbKey(nodeId)], + nodeData, + ); + const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( + nodeData.lastUpdated, + nodeId, + ); + await tran.put( + [...indexPathNew, lastUpdatedKey], + nodesUtils.bucketDbKey(nodeId), + true, + ); } + // Swap to the new space + await tran.put([...this.nodeGraphDbPath, 'space'], spaceNew); + // Clear old space + await tran.clear(this.nodeGraphMetaDbPath); + await tran.clear(this.nodeGraphBucketsDbPath); + await tran.clear(this.nodeGraphLastUpdatedDbPath); + // Swap the spaces + this.space = spaceNew; + this.nodeGraphMetaDbPath = nodeGraphMetaDbPathNew; + this.nodeGraphBucketsDbPath = nodeGraphBucketsDbPathNew; + this.nodeGraphLastUpdatedDbPath = nodeGraphLastUpdatedDbPathNew; } - /** - * Find the correct index of the k-bucket to add a new node to (for this node's - * bucket database). Packs it as a lexicographic integer, such that the order - * of buckets in leveldb is numerical order. - */ - protected getBucketIndex(nodeId: NodeId): string { - const index = nodesUtils.calculateBucketIndex( - this.keyManager.getNodeId(), - nodeId, - ); - return lexi.pack(index, 'hex') as string; + @ready(new nodesErrors.ErrorNodeGraphNotRunning()) + public async getBucketMeta( + bucketIndex: NodeBucketIndex, + tran: DBTransaction, + ): Promise { + if (bucketIndex < 0 || bucketIndex >= this.nodeIdBits) { + throw new nodesErrors.ErrorNodeGraphBucketIndex( + `bucketIndex must be between 0 and ${this.nodeIdBits - 1} inclusive`, + ); + } + const metaDomain = [ + ...this.nodeGraphMetaDbPath, + nodesUtils.bucketKey(bucketIndex), + ]; + const props = await Promise.all([ + tran.get([...metaDomain, 'count']), + ]); + const [count] = props; + // Bucket meta properties have defaults + return { + count: count ?? 0, + }; } - /** - * Returns all of the buckets in an array - */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async getAllBuckets(tran?: DBTransaction): Promise> { - if (tran == null) { - return this.withTransactionF(async (tran) => this.getAllBuckets(tran)); + public async getBucketMetaProp( + bucketIndex: NodeBucketIndex, + key: Key, + tran: DBTransaction, + ): Promise { + if (bucketIndex < 0 || bucketIndex >= this.nodeIdBits) { + throw new nodesErrors.ErrorNodeGraphBucketIndex( + `bucketIndex must be between 0 and ${this.nodeIdBits - 1} inclusive`, + ); } - const buckets: Array = []; - for await (const [, bucket] of tran.iterator( - { keys: false, valueAsBuffer: false }, - [...this.nodeGraphBucketsDbPath], - )) { - buckets.push(bucket); + const metaDomain = [ + ...this.nodeGraphMetaDbPath, + nodesUtils.bucketKey(bucketIndex), + ]; + // Bucket meta properties have defaults + let value; + switch (key) { + case 'count': + value = (await tran.get([...metaDomain, key])) ?? 0; + break; } - return buckets; + return value; } /** - * To be called on key renewal. Re-orders all nodes in all buckets with respect - * to the new node ID. - * NOTE: original nodes may be lost in this process. If they're redistributed - * to a newly full bucket, the least active nodes in the newly full bucket - * will be removed. + * Sets a bucket meta property + * This is protected because users cannot directly manipulate bucket meta */ - @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async refreshBuckets(tran?: DBTransaction): Promise { - if (tran == null) { - return this.withTransactionF(async (tran) => this.refreshBuckets(tran)); - } - // Get a local copy of all the buckets - const buckets = await this.getAllBuckets(tran); - // Wrap as a batch operation. We want to rollback if we encounter any - // errors (such that we don't clear the DB without re-adding the nodes) - // 1. Delete every bucket - for await (const [keyPath] of tran.iterator({ values: false }, [ - ...this.nodeGraphBucketsDbPath, - ])) { - const key = keyPath[0].toString(); - const hexBucketPath = [...this.nodeGraphBucketsDbPath, key]; - await tran.del(hexBucketPath); - } - const tempBuckets: Record = {}; - // 2. Re-add all the nodes from all buckets - for (const b of buckets) { - for (const n of Object.keys(b)) { - const nodeId = IdInternal.fromString(n); - const newIndex = this.getBucketIndex(nodeId); - let expectedBucket = tempBuckets[newIndex]; - // The following is more or less copied from setNodeOps - if (expectedBucket == null) { - expectedBucket = {}; - } - const bucketEntries = Object.entries(expectedBucket); - // Add the old node - expectedBucket[nodeId] = { - address: b[nodeId].address, - lastUpdated: b[nodeId].lastUpdated, - }; - // If, with the old node added, we exceed the limit - if (bucketEntries.length > this.maxNodesPerBucket) { - // Then, with the old node added, find the least active and remove - const leastActive = bucketEntries.reduce((prev, curr) => { - return prev[1].lastUpdated < curr[1].lastUpdated ? prev : curr; - }); - delete expectedBucket[leastActive[0]]; - } - // Add this reconstructed bucket (with old node) into the temp storage - tempBuckets[newIndex] = expectedBucket; - } - } - // Now that we've reconstructed all the buckets, perform batch operations - // on a bucket level (i.e. per bucket, instead of per node) - for (const bucketIndex in tempBuckets) { - const bucketPath = [ - ...this.nodeGraphBucketsDbPath, - bucketIndex, - ] as unknown as KeyPath; - await tran.put(bucketPath, tempBuckets[bucketIndex]); + protected async setBucketMetaProp( + bucketIndex: NodeBucketIndex, + key: Key, + value: NodeBucketMeta[Key], + tran: DBTransaction, + ): Promise { + const metaKey = [ + ...this.nodeGraphMetaDbPath, + nodesUtils.bucketKey(bucketIndex), + key, + ]; + await tran.put(metaKey, value); + return; + } + + /** + * Derive the bucket index of the k-buckets from the new `NodeId` + * The bucket key is the string encoded version of bucket index + * that preserves lexicographic order + */ + protected bucketIndex(nodeId: NodeId): [NodeBucketIndex, string] { + const nodeIdOwn = this.keyManager.getNodeId(); + if (nodeId.equals(nodeIdOwn)) { + throw new nodesErrors.ErrorNodeGraphSameNodeId(); } + const bucketIndex = nodesUtils.bucketIndex(nodeIdOwn, nodeId); + const bucketKey = nodesUtils.bucketKey(bucketIndex); + return [bucketIndex, bucketKey]; } } diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 6adf77867..ac9d3a4a4 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -313,7 +313,7 @@ class NodeManager { nodeId: NodeId, tran?: DBTransaction, ): Promise { - return await this.nodeGraph.getNode(nodeId, tran); + return (await this.nodeGraph.getNode(nodeId, tran))?.address; } /** @@ -326,7 +326,7 @@ class NodeManager { targetNodeId: NodeId, tran?: DBTransaction, ): Promise { - return await this.nodeGraph.knowsNode(targetNodeId, tran); + return (await this.nodeGraph.getNode(targetNodeId, tran)) != null; } /** @@ -350,16 +350,16 @@ class NodeManager { return await this.nodeGraph.setNode(nodeId, nodeAddress, tran); } - /** - * Updates the node in the NodeGraph - */ - public async updateNode( - nodeId: NodeId, - nodeAddress?: NodeAddress, - tran?: DBTransaction, - ): Promise { - return await this.nodeGraph.updateNode(nodeId, nodeAddress, tran); - } + // /** + // * Updates the node in the NodeGraph + // */ + // public async updateNode( + // nodeId: NodeId, + // nodeAddress?: NodeAddress, + // tran?: DBTransaction, + // ): Promise { + // return await this.nodeGraph.updateNode(nodeId, nodeAddress, tran); + // } /** * Removes a node from the NodeGraph @@ -368,19 +368,21 @@ class NodeManager { return await this.nodeGraph.unsetNode(nodeId, tran); } - /** - * Gets all buckets from the NodeGraph - */ - public async getAllBuckets(tran?: DBTransaction): Promise> { - return await this.nodeGraph.getAllBuckets(tran); - } + // /** + // * Gets all buckets from the NodeGraph + // */ + // public async getAllBuckets(tran?: DBTransaction): Promise> { + // return await this.nodeGraph.getAllBuckets(tran); + // } + // FIXME /** * To be called on key renewal. Re-orders all nodes in all buckets with respect * to the new node ID. */ public async refreshBuckets(tran?: DBTransaction): Promise { - return await this.nodeGraph.refreshBuckets(tran); + throw Error('fixme'); + // Return await this.nodeGraph.refreshBuckets(tran); } } diff --git a/src/nodes/errors.ts b/src/nodes/errors.ts index 1c491bde4..83a5597d4 100644 --- a/src/nodes/errors.ts +++ b/src/nodes/errors.ts @@ -37,6 +37,11 @@ class ErrorNodeGraphSameNodeId extends ErrorNodes { exitCode = sysexits.USAGE; } +class ErrorNodeGraphBucketIndex extends ErrorNodes { + static description: 'Bucket index is out of range'; + exitCode = sysexits.USAGE; +} + class ErrorNodeConnectionDestroyed extends ErrorNodes { static description = 'NodeConnection is destroyed'; exitCode = sysexits.USAGE; @@ -76,6 +81,7 @@ export { ErrorNodeGraphEmptyDatabase, ErrorNodeGraphOversizedBucket, ErrorNodeGraphSameNodeId, + ErrorNodeGraphBucketIndex, ErrorNodeConnectionDestroyed, ErrorNodeConnectionTimeout, ErrorNodeConnectionInfoNotExist, diff --git a/src/nodes/types.ts b/src/nodes/types.ts index ffb916851..683143e83 100644 --- a/src/nodes/types.ts +++ b/src/nodes/types.ts @@ -1,9 +1,13 @@ import type { Id } from '@matrixai/id'; -import type { Opaque } from '../types'; +import type { Opaque, NonFunctionProperties } from '../types'; import type { Host, Hostname, Port } from '../network/types'; import type { Claim, ClaimId } from '../claims/types'; import type { ChainData } from '../sigchain/types'; +// This should be a string +// actually cause it is a domain +type NodeGraphSpace = '0' | '1'; + type NodeId = Opaque<'NodeId', Id>; type NodeIdString = Opaque<'NodeIdString', string>; type NodeIdEncoded = Opaque<'NodeIdEncoded', string>; @@ -13,9 +17,43 @@ type NodeAddress = { port: Port; }; -type SeedNodes = Record; +type NodeBucketIndex = number; +// Type NodeBucket = Record; + +// TODO: +// No longer need to use NodeIdString +// It's an array, if you want to lookup +// It's ordered by the last updated date +// On the other hand, does this matter +// Not really? +// USE THIS TYPE INSTEAD +type NodeBucket = Array<[NodeId, NodeData]>; + +type NodeBucketMeta = { + count: number; +}; + +type NodeBucketMetaProps = NonFunctionProperties; + +// Just make the bucket entries also +// bucketIndex anot as a key +// but as the domain +// !!NodeGraph!!meta!!ff!!count type NodeData = { + address: NodeAddress; + lastUpdated: number; +}; + +// Type NodeBucketEntry = { +// address: NodeAddress; +// lastUpdated: Date; +// }; + +type SeedNodes = Record; + +// FIXME: should have a proper name +type NodeEntry = { id: NodeId; address: NodeAddress; distance: BigInt; @@ -41,16 +79,6 @@ type NodeInfo = { chain: ChainData; }; -type NodeBucketIndex = number; - -// The data type to be stored in each leveldb entry for the node table -type NodeBucket = { - [key: string]: { - address: NodeAddress; - lastUpdated: Date; - }; -}; - // Only 1 domain, so don't need a 'domain' value (like /gestalts/types.ts) type NodeGraphOp_ = { // Bucket index @@ -72,10 +100,15 @@ export type { NodeIdEncoded, NodeAddress, SeedNodes, - NodeData, NodeClaim, NodeInfo, NodeBucketIndex, + NodeBucketMeta, NodeBucket, + NodeData, + NodeEntry, + // NodeBucketEntry, + NodeGraphOp, + NodeGraphSpace, }; diff --git a/src/nodes/utils.ts b/src/nodes/utils.ts index 696e31d43..1db803381 100644 --- a/src/nodes/utils.ts +++ b/src/nodes/utils.ts @@ -1,29 +1,77 @@ -import type { NodeData, NodeId, NodeIdEncoded } from './types'; +import type { + NodeData, + NodeId, + NodeIdEncoded, + NodeBucket, + NodeIdString, + NodeBucketIndex, +} from './types'; +import { utils as dbUtils } from '@matrixai/db'; import { IdInternal } from '@matrixai/id'; -import { bytes2BigInt } from '../utils'; +import lexi from 'lexicographic-integer'; +import { bytes2BigInt, bufferSplit } from '../utils'; + +// FIXME: +const prefixBuffer = Buffer.from([33]); +// Const prefixBuffer = Buffer.from(dbUtils.prefix); /** - * Compute the distance between two nodes. - * distance = nodeId1 ^ nodeId2 - * where ^ = bitwise XOR operator + * Encodes the NodeId as a `base32hex` string */ -function calculateDistance(nodeId1: NodeId, nodeId2: NodeId): bigint { - const distance = nodeId1.map((byte, i) => byte ^ nodeId2[i]); - return bytes2BigInt(distance); +function encodeNodeId(nodeId: NodeId): NodeIdEncoded { + return nodeId.toMultibase('base32hex') as NodeIdEncoded; } /** - * Find the correct index of the k-bucket to add a new node to. + * Decodes an encoded NodeId string into a NodeId + */ +function decodeNodeId(nodeIdEncoded: any): NodeId | undefined { + if (typeof nodeIdEncoded !== 'string') { + return; + } + const nodeId = IdInternal.fromMultibase(nodeIdEncoded); + if (nodeId == null) { + return; + } + // All NodeIds are 32 bytes long + // The NodeGraph requires a fixed size for Node Ids + if (nodeId.length !== 32) { + return; + } + return nodeId; +} + +/** + * Calculate the bucket index that the target node should be located in * A node's k-buckets are organised such that for the ith k-bucket where * 0 <= i < nodeIdBits, the contacts in this ith bucket are known to adhere to * the following inequality: * 2^i <= distance (from current node) < 2^(i+1) + * This means lower buckets will have less nodes then the upper buckets. + * The highest bucket will contain half of all possible nodes. + * The lowest bucket will only contain 1 node. * * NOTE: because XOR is a commutative operation (i.e. a XOR b = b XOR a), the * order of the passed parameters is actually irrelevant. These variables are * purely named for communicating function purpose. + * + * NOTE: Kademlia literature generally talks about buckets with 1-based indexing + * and that the buckets are ordered from largest to smallest. This means the first + * 1th-bucket is far & large bucket, and the last 255th-bucket is the close bucket. + * This is reversed in our `NodeBucketIndex` encoding. This is so that lexicographic + * sort orders our buckets from closest bucket to farthest bucket. + * + * To convert from `NodeBucketIndex` to nth-bucket in Kademlia literature: + * + * | NodeBucketIndex | Nth-Bucket | + * | --------------- | ---------- | + * | 255 | 1 | farthest & largest + * | 254 | 2 | + * | ... | ... | + * | 1 | 254 | + * | 0 | 256 | closest & smallest */ -function calculateBucketIndex(sourceNode: NodeId, targetNode: NodeId): number { +function bucketIndex(sourceNode: NodeId, targetNode: NodeId): NodeBucketIndex { const distance = sourceNode.map((byte, i) => byte ^ targetNode[i]); const MSByteIndex = distance.findIndex((byte) => byte !== 0); if (MSByteIndex === -1) { @@ -37,48 +85,221 @@ function calculateBucketIndex(sourceNode: NodeId, targetNode: NodeId): number { } /** - * A sorting compareFn to sort an array of NodeData by increasing distance. + * Encodes bucket index to bucket sublevel key */ -function sortByDistance(a: NodeData, b: NodeData) { - if (a.distance > b.distance) { - return 1; - } else if (a.distance < b.distance) { - return -1; - } else { - return 0; +function bucketKey(bucketIndex: NodeBucketIndex): string { + return lexi.pack(bucketIndex, 'hex'); +} + +/** + * Creates key for buckets sublevel + */ +function bucketsDbKey(bucketIndex: NodeBucketIndex, nodeId: NodeId): Buffer { + return Buffer.concat([ + prefixBuffer, + Buffer.from(bucketKey(bucketIndex)), + prefixBuffer, + bucketDbKey(nodeId), + ]); +} + +/** + * Creates key for single bucket sublevel + */ +function bucketDbKey(nodeId: NodeId): Buffer { + return nodeId.toBuffer(); +} + +/** + * Creates key for buckets indexed by lastUpdated sublevel + */ +function lastUpdatedBucketsDbKey( + bucketIndex: NodeBucketIndex, + lastUpdated: number, + nodeId: NodeId, +): Buffer { + return Buffer.concat([ + prefixBuffer, + Buffer.from(bucketKey(bucketIndex)), + prefixBuffer, + lastUpdatedBucketDbKey(lastUpdated, nodeId), + ]); +} + +/** + * Creates key for single bucket indexed by lastUpdated sublevel + */ +function lastUpdatedBucketDbKey(lastUpdated: number, nodeId: NodeId): Buffer { + return Buffer.concat([ + Buffer.from(lexi.pack(lastUpdated, 'hex')), + Buffer.from('-'), + nodeId.toBuffer(), + ]); +} + +/** + * Parse the NodeGraph buckets sublevel key + * The keys look like `!!` + * It is assumed that the `!` is the sublevel prefix. + */ +function parseBucketsDbKey(keyBuffer: Buffer): { + bucketIndex: NodeBucketIndex; + bucketKey: string; + nodeId: NodeId; +} { + const [, bucketKeyBuffer, nodeIdBuffer] = bufferSplit( + keyBuffer, + prefixBuffer, + 3, + true, + ); + if (bucketKeyBuffer == null || nodeIdBuffer == null) { + throw new TypeError('Buffer is not an NodeGraph buckets key'); } + const bucketKey = bucketKeyBuffer.toString(); + const bucketIndex = lexi.unpack(bucketKey); + const nodeId = IdInternal.fromBuffer(nodeIdBuffer); + return { + bucketIndex, + bucketKey, + nodeId, + }; } /** - * Encodes the NodeId as a `base32hex` string + * Parse the NodeGraph bucket key + * The keys look like `` */ -function encodeNodeId(nodeId: NodeId): NodeIdEncoded { - return nodeId.toMultibase('base32hex') as NodeIdEncoded; +function parseBucketDbKey(keyBuffer: Buffer): NodeId { + const nodeId = IdInternal.fromBuffer(keyBuffer); + return nodeId; } /** - * Decodes an encoded NodeId string into a NodeId + * Parse the NodeGraph index sublevel key + * The keys look like `!!-` + * It is assumed that the `!` is the sublevel prefix. */ -function decodeNodeId(nodeIdEncoded: any): NodeId | undefined { - if (typeof nodeIdEncoded !== 'string') { - return; +function parseLastUpdatedBucketsDbKey(keyBuffer: Buffer): { + bucketIndex: NodeBucketIndex; + bucketKey: string; + lastUpdated: number; + nodeId: NodeId; +} { + const [, bucketKeyBuffer, lastUpdatedBuffer] = bufferSplit( + keyBuffer, + prefixBuffer, + 3, + true, + ); + if (bucketKeyBuffer == null || lastUpdatedBuffer == null) { + throw new TypeError('Buffer is not an NodeGraph index key'); } - const nodeId = IdInternal.fromMultibase(nodeIdEncoded); - if (nodeId == null) { - return; + const bucketKey = bucketKeyBuffer.toString(); + const bucketIndex = lexi.unpack(bucketKey); + if (bucketIndex == null) { + throw new TypeError('Buffer is not an NodeGraph index key'); } - // All NodeIds are 32 bytes long - // The NodeGraph requires a fixed size for Node Ids - if (nodeId.length !== 32) { - return; + const { lastUpdated, nodeId } = + parseLastUpdatedBucketDbKey(lastUpdatedBuffer); + return { + bucketIndex, + bucketKey, + lastUpdated, + nodeId, + }; +} + +/** + * Parse the NodeGraph index bucket sublevel key + * The keys look like `-` + * It is assumed that the `!` is the sublevel prefix. + */ +function parseLastUpdatedBucketDbKey(keyBuffer: Buffer): { + lastUpdated: number; + nodeId: NodeId; +} { + const [lastUpdatedBuffer, nodeIdBuffer] = bufferSplit( + keyBuffer, + Buffer.from('-'), + 2, + true, + ); + if (lastUpdatedBuffer == null || nodeIdBuffer == null) { + throw new TypeError('Buffer is not an NodeGraph index bucket key'); + } + const lastUpdated = lexi.unpack(lastUpdatedBuffer.toString()); + if (lastUpdated == null) { + throw new TypeError('Buffer is not an NodeGraph index bucket key'); + } + const nodeId = IdInternal.fromBuffer(nodeIdBuffer); + return { + lastUpdated, + nodeId, + }; +} + +/** + * Compute the distance between two nodes. + * distance = nodeId1 ^ nodeId2 + * where ^ = bitwise XOR operator + */ +function nodeDistance(nodeId1: NodeId, nodeId2: NodeId): bigint { + const distance = nodeId1.map((byte, i) => byte ^ nodeId2[i]); + return bytes2BigInt(distance); +} + +function bucketSortByDistance( + bucket: NodeBucket, + nodeId: NodeId, + order: 'asc' | 'desc' = 'asc', +): void { + const distances = {}; + if (order === 'asc') { + bucket.sort(([nodeId1], [nodeId2]) => { + const d1 = (distances[nodeId1] = + distances[nodeId1] ?? nodeDistance(nodeId, nodeId1)); + const d2 = (distances[nodeId2] = + distances[nodeId2] ?? nodeDistance(nodeId, nodeId2)); + if (d1 < d2) { + return -1; + } else if (d1 > d2) { + return 1; + } else { + return 0; + } + }); + } else { + bucket.sort(([nodeId1], [nodeId2]) => { + const d1 = (distances[nodeId1] = + distances[nodeId1] ?? nodeDistance(nodeId, nodeId1)); + const d2 = (distances[nodeId2] = + distances[nodeId2] ?? nodeDistance(nodeId, nodeId2)); + if (d1 > d2) { + return -1; + } else if (d1 < d2) { + return 1; + } else { + return 0; + } + }); } - return nodeId; } export { - calculateDistance, - calculateBucketIndex, - sortByDistance, + prefixBuffer, encodeNodeId, decodeNodeId, + bucketIndex, + bucketKey, + bucketsDbKey, + bucketDbKey, + lastUpdatedBucketsDbKey, + lastUpdatedBucketDbKey, + parseBucketsDbKey, + parseBucketDbKey, + parseLastUpdatedBucketsDbKey, + parseLastUpdatedBucketDbKey, + nodeDistance, + bucketSortByDistance, }; diff --git a/src/types.ts b/src/types.ts index 161181b8d..fae58ae01 100644 --- a/src/types.ts +++ b/src/types.ts @@ -86,6 +86,24 @@ interface FileSystem { type FileHandle = fs.promises.FileHandle; +type FunctionPropertyNames = { + [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never; +}[keyof T]; + +/** + * Functional properties of an object + */ +type FunctionProperties = Pick>; + +type NonFunctionPropertyNames = { + [K in keyof T]: T[K] extends (...args: any[]) => any ? never : K; +}[keyof T]; + +/** + * Non-functional properties of an object + */ +type NonFunctionProperties = Pick>; + export type { POJO, Opaque, @@ -99,4 +117,6 @@ export type { Timer, FileSystem, FileHandle, + FunctionProperties, + NonFunctionProperties, }; diff --git a/src/utils/index.ts b/src/utils/index.ts index f50908aca..2ee8414ff 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -2,4 +2,5 @@ export { default as sysexits } from './sysexits'; export * from './utils'; export * from './matchers'; export * from './binary'; +export * from './random'; export * as errors from './errors'; diff --git a/src/utils/random.ts b/src/utils/random.ts new file mode 100644 index 000000000..fa0c3ecda --- /dev/null +++ b/src/utils/random.ts @@ -0,0 +1,11 @@ +/** + * Gets a random number between min (inc) and max (exc) + * This is not cryptographically-secure + */ +function getRandomInt(min: number, max: number) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +export { getRandomInt }; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 4d837ecbf..7c623e8dd 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -236,6 +236,67 @@ function arrayZipWithPadding( ]); } +async function asyncIterableArray( + iterable: AsyncIterable, +): Promise> { + const arr: Array = []; + for await (const item of iterable) { + arr.push(item); + } + return arr; +} + +function bufferSplit( + input: Buffer, + delimiter?: Buffer, + limit?: number, + remaining: boolean = false, +): Array { + const output: Array = []; + let delimiterOffset = 0; + let delimiterIndex = 0; + let i = 0; + if (delimiter != null) { + while (true) { + if (i === limit) break; + delimiterIndex = input.indexOf(delimiter, delimiterOffset); + if (delimiterIndex > -1) { + output.push(input.subarray(delimiterOffset, delimiterIndex)); + delimiterOffset = delimiterIndex + delimiter.byteLength; + } else { + const chunk = input.subarray(delimiterOffset); + output.push(chunk); + delimiterOffset += chunk.byteLength; + break; + } + i++; + } + } else { + for (; delimiterIndex < input.byteLength; ) { + if (i === limit) break; + delimiterIndex++; + const chunk = input.subarray(delimiterOffset, delimiterIndex); + output.push(chunk); + delimiterOffset += chunk.byteLength; + i++; + } + } + // If remaining, then the rest of the input including delimiters is extracted + if ( + remaining && + limit != null && + output.length > 0 && + delimiterIndex > -1 && + delimiterIndex <= input.byteLength + ) { + const inputRemaining = input.subarray( + delimiterIndex - output[output.length - 1].byteLength, + ); + output[output.length - 1] = inputRemaining; + } + return output; +} + function debounce

( f: (...params: P) => any, timeout: number = 0, @@ -266,5 +327,7 @@ export { arrayUnset, arrayZip, arrayZipWithPadding, + asyncIterableArray, + bufferSplit, debounce, }; diff --git a/src/validation/utils.ts b/src/validation/utils.ts index 3ce13f258..020c1f51a 100644 --- a/src/validation/utils.ts +++ b/src/validation/utils.ts @@ -165,7 +165,7 @@ function parseHostOrHostname(data: any): Host | Hostname { * Parses number into a Port * Data can be a string-number */ -function parsePort(data: any): Port { +function parsePort(data: any, connect: boolean = false): Port { if (typeof data === 'string') { try { data = parseInteger(data); @@ -176,10 +176,16 @@ function parsePort(data: any): Port { throw e; } } - if (!networkUtils.isPort(data)) { - throw new validationErrors.ErrorParse( - 'Port must be a number between 0 and 65535 inclusive', - ); + if (!networkUtils.isPort(data, connect)) { + if (!connect) { + throw new validationErrors.ErrorParse( + 'Port must be a number between 0 and 65535 inclusive', + ); + } else { + throw new validationErrors.ErrorParse( + 'Port must be a number between 1 and 65535 inclusive', + ); + } } return data; } diff --git a/test-iterator.ts b/test-iterator.ts new file mode 100644 index 000000000..82a21762c --- /dev/null +++ b/test-iterator.ts @@ -0,0 +1,31 @@ + + +function getYouG () { + console.log('ALREADY EXECUTED'); + return abc(); +} + +async function *abc() { + console.log('START'); + yield 1; + yield 2; + yield 3; +} + +async function main () { + + // we would want that you don't iterate it + + const g = getYouG(); + + await g.next(); + + // console.log('SUP'); + + // for await (const r of abc()) { + // console.log(r); + // } + +} + +main(); diff --git a/test-lexi.ts b/test-lexi.ts new file mode 100644 index 000000000..b48f9cea1 --- /dev/null +++ b/test-lexi.ts @@ -0,0 +1,4 @@ +import lexi from 'lexicographic-integer'; + + +console.log(lexi.pack(1646203779)); diff --git a/test-nodegraph.ts b/test-nodegraph.ts new file mode 100644 index 000000000..33bd58bb7 --- /dev/null +++ b/test-nodegraph.ts @@ -0,0 +1,107 @@ +import type { NodeId, NodeAddress } from './src/nodes/types'; +import { DB } from '@matrixai/db'; +import { IdInternal } from '@matrixai/id'; +import * as keysUtils from './src/keys/utils'; +import * as nodesUtils from './src/nodes/utils'; +import NodeGraph from './src/nodes/NodeGraph'; +import KeyManager from './src/keys/KeyManager'; + +function generateRandomNodeId(readable: boolean = false): NodeId { + if (readable) { + const random = keysUtils.getRandomBytesSync(16).toString('hex'); + return IdInternal.fromString(random); + } else { + const random = keysUtils.getRandomBytesSync(32); + return IdInternal.fromBuffer(random); + } +} + +async function main () { + + const db = await DB.createDB({ + dbPath: './tmp/db' + }); + + const keyManager = await KeyManager.createKeyManager({ + keysPath: './tmp/keys', + password: 'abc123', + // fresh: true + }); + + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + fresh: true + }); + + for (let i = 0; i < 10; i++) { + await nodeGraph.setNode( + generateRandomNodeId(), + { + host: '127.0.0.1', + port: 55555 + } as NodeAddress + ); + } + + for await (const [bucketIndex, bucket] of nodeGraph.getBuckets()) { + + // the bucket lengths are wrong + console.log( + 'BucketIndex', + bucketIndex, + 'Bucket Count', + bucket.length, + ); + + // console.log(bucket); + for (const [nodeId, nodeData] of bucket) { + // console.log('NODEID', nodeId); + // console.log('NODEDATA', nodeData); + // console.log(nodeData.address); + } + } + + for await (const [nodeId, nodeData] of nodeGraph.getNodes()) { + // console.log(nodeId, nodeData); + } + + const bucket = await nodeGraph.getBucket(255, 'lastUpdated'); + console.log(bucket.length); + + // console.log('OLD NODE ID', keyManager.getNodeId()); + // const newNodeId = generateRandomNodeId(); + // console.log('NEW NODE ID', newNodeId); + + // console.log('---------FIRST RESET--------'); + + // await nodeGraph.resetBuckets(newNodeId); + // for await (const [bucketIndex, bucket] of nodeGraph.getBuckets()) { + // console.log( + // 'BucketIndex', + // bucketIndex, + // 'Bucket Count', + // Object.keys(bucket).length + // ); + // } + + + // console.log('---------SECOND RESET--------'); + // const newNodeId2 = generateRandomNodeId(); + // await nodeGraph.resetBuckets(newNodeId2); + + // for await (const [bucketIndex, bucket] of nodeGraph.getBuckets()) { + // console.log( + // 'BucketIndex', + // bucketIndex, + // 'Bucket Count', + // Object.keys(bucket).length + // ); + // } + + await nodeGraph.stop(); + await keyManager.stop(); + await db.stop(); +} + +main(); diff --git a/test-nodeidgen.ts b/test-nodeidgen.ts new file mode 100644 index 000000000..2f79bddda --- /dev/null +++ b/test-nodeidgen.ts @@ -0,0 +1,44 @@ +import type { NodeId } from './src/nodes/types'; +import { IdInternal } from '@matrixai/id'; +import * as keysUtils from './src/keys/utils'; +import * as nodesUtils from './src/nodes/utils'; + +function generateRandomNodeId(readable: boolean = false): NodeId { + if (readable) { + const random = keysUtils.getRandomBytesSync(16).toString('hex'); + return IdInternal.fromString(random); + } else { + const random = keysUtils.getRandomBytesSync(32); + return IdInternal.fromBuffer(random); + } +} + +async function main () { + + const firstNodeId = generateRandomNodeId(); + + + let lastBucket = 0; + let penultimateBucket = 0; + let lowerBuckets = 0; + + for (let i = 0; i < 1000; i++) { + const nodeId = generateRandomNodeId(); + const bucketIndex = nodesUtils.bucketIndex(firstNodeId, nodeId); + if (bucketIndex === 255) { + lastBucket++; + } else if (bucketIndex === 254) { + penultimateBucket++; + } else { + lowerBuckets++; + } + } + + console.log(lastBucket); + console.log(penultimateBucket); + console.log(lowerBuckets); + + +} + +main(); diff --git a/test-order.ts b/test-order.ts new file mode 100644 index 000000000..f6046d6da --- /dev/null +++ b/test-order.ts @@ -0,0 +1,98 @@ +import { DB } from '@matrixai/db'; +import lexi from 'lexicographic-integer'; +import { getUnixtime, hex2Bytes } from './src/utils'; + +async function main () { + + const db = await DB.createDB({ + dbPath: './tmp/orderdb', + fresh: true + }); + + await db.put([], 'node1', 'value'); + await db.put([], 'node2', 'value'); + await db.put([], 'node3', 'value'); + await db.put([], 'node4', 'value'); + await db.put([], 'node5', 'value'); + await db.put([], 'node6', 'value'); + await db.put([], 'node7', 'value'); + + const now = new Date; + const t1 = new Date(now.getTime() + 1000 * 1); + const t2 = new Date(now.getTime() + 1000 * 2); + const t3 = new Date(now.getTime() + 1000 * 3); + const t4 = new Date(now.getTime() + 1000 * 4); + const t5 = new Date(now.getTime() + 1000 * 5); + const t6 = new Date(now.getTime() + 1000 * 6); + const t7 = new Date(now.getTime() + 1000 * 7); + + // so unix time is only what we really need to know + // further precision is unlikely + // and hex-packed time is shorter keys + // so it is likely faster + // the only issue is that unpacking requires + // converting hex into bytes, then into strings + + // console.log(t1.getTime()); + // console.log(getUnixtime(t1)); + // console.log(lexi.pack(getUnixtime(t1), 'hex')); + // console.log(lexi.pack(t1.getTime(), 'hex')); + // console.log(t1.toISOString()); + + + // buckets0!BUCKETINDEX!NODEID + // buckets0!BUCKETINDEX!date + + // Duplicate times that are put here + // But differentiate by the node1, node2 + await db.put([], lexi.pack(getUnixtime(t6), 'hex') + '-node1', 'value'); + await db.put([], lexi.pack(getUnixtime(t6), 'hex') + '-node2', 'value'); + + await db.put([], lexi.pack(getUnixtime(t1), 'hex') + '-node3', 'value'); + await db.put([], lexi.pack(getUnixtime(t4), 'hex') + '-node4', 'value'); + await db.put([], lexi.pack(getUnixtime(t3), 'hex') + '-node5', 'value'); + await db.put([], lexi.pack(getUnixtime(t2), 'hex') + '-node6', 'value'); + await db.put([], lexi.pack(getUnixtime(t5), 'hex') + '-node7', 'value'); + + // await db.put([], t6.toISOString() + '-node1', 'value'); + // await db.put([], t6.toISOString() + '-node2', 'value'); + + // await db.put([], t1.toISOString() + '-node3', 'value'); + // await db.put([], t4.toISOString() + '-node4', 'value'); + // await db.put([], t3.toISOString() + '-node5', 'value'); + // await db.put([], t2.toISOString() + '-node6', 'value'); + // await db.put([], t5.toISOString() + '-node7', 'value'); + + // Why did this require `-node3` + + // this will awlays get one or the other + + // ok so we if we want to say get a time + // or order it by time + // we are goingto have to create read stream over the bucket right? + // yea so we would have another sublevel, or at least a sublevel formed by the bucket + // one that is the bucket index + // so that would be the correct way to do it + + for await (const o of db.db.createReadStream({ + gte: lexi.pack(getUnixtime(t1), 'hex'), + limit: 1, + // keys: true, + // values: true, + // lte: lexi.pack(getUnixtime(t6)) + })) { + + console.log(o.key.toString()); + + } + + await db.stop(); + + + // so it works + // now if you give it something liek + + +} + +main(); diff --git a/test-sorting.ts b/test-sorting.ts new file mode 100644 index 000000000..1692fa83f --- /dev/null +++ b/test-sorting.ts @@ -0,0 +1,28 @@ +import * as testNodesUtils from './tests/nodes/utils'; + +const arr = [ + { a: 'abc', b: 3}, + { a: 'abc', b: 1}, + { a: 'abc', b: 0}, +]; + +arr.sort((a, b): number => { + if (a.b > b.b) { + return 1; + } else if (a.b < b.b) { + return -1; + } else { + return 0; + } +}); + +console.log(arr); + +const arr2 = [3, 1, 0]; + +arr2.sort(); + +console.log(arr2); + + +console.log(testNodesUtils.generateRandomNodeId()); diff --git a/test-split.ts b/test-split.ts new file mode 100644 index 000000000..ee06d75d6 --- /dev/null +++ b/test-split.ts @@ -0,0 +1,37 @@ + +function bufferSplit(input: Buffer, delimiter?: Buffer): Array { + const output: Array = []; + let delimiterIndex = 0; + let chunkIndex = 0; + if (delimiter != null) { + while (true) { + const i = input.indexOf( + delimiter, + delimiterIndex + ); + if (i > -1) { + output.push(input.subarray(chunkIndex, i)); + delimiterIndex = i + delimiter.byteLength; + chunkIndex = i + delimiter.byteLength; + } else { + output.push(input.subarray(chunkIndex)); + break; + } + } + } else { + for (let i = 0; i < input.byteLength; i++) { + output.push(input.subarray(i, i + 1)); + } + } + return output; +} + + +const b = Buffer.from('!a!!b!'); + +console.log(bufferSplit(b, Buffer.from('!!'))); +console.log(bufferSplit(b)); + +const s = '!a!!b!'; + +console.log(s.split('!!')); diff --git a/test-trie.ts b/test-trie.ts new file mode 100644 index 000000000..a17c4165d --- /dev/null +++ b/test-trie.ts @@ -0,0 +1,29 @@ +import * as utils from './src/utils'; +import * as nodesUtils from './src/nodes/utils'; + +// 110 +const ownNodeId = Buffer.from([6]); + +const i = 2; + +const maxDistance = utils.bigInt2Bytes(BigInt(2 ** i)); +const minDistance = utils.bigInt2Bytes(BigInt(2 ** (i - 1))); + +console.log('max distance', maxDistance, utils.bytes2Bits(maxDistance)); +console.log('min distance', minDistance, utils.bytes2Bits(minDistance)); + +// ownNodeId XOR maxdistance = GTE node id +const gte = ownNodeId.map((byte, i) => byte ^ maxDistance[i]); + +// ownNodeId XOR mindistance = LT node id +const lt = ownNodeId.map((byte, i) => byte ^ minDistance[i]); + +console.log('Lowest Distance Node (inc)', gte, utils.bytes2Bits(gte)); +console.log('Greatest Distance Node (exc)', lt, utils.bytes2Bits(lt)); + +// function nodeDistance(nodeId1: Buffer, nodeId2: Buffer): bigint { +// const distance = nodeId1.map((byte, i) => byte ^ nodeId2[i]); +// return utils.bytes2BigInt(distance); +// } + +// console.log(nodeDistance(ownNodeId, Buffer.from([0]))); diff --git a/tests/acl/ACL.test.ts b/tests/acl/ACL.test.ts index a671caf10..cd0658560 100644 --- a/tests/acl/ACL.test.ts +++ b/tests/acl/ACL.test.ts @@ -12,6 +12,7 @@ import * as aclErrors from '@/acl/errors'; import * as keysUtils from '@/keys/utils'; import * as vaultsUtils from '@/vaults/utils'; import * as testUtils from '../utils'; +import * as testNodesUtils from '../nodes/utils'; describe(ACL.name, () => { const logger = new Logger(`${ACL.name} test`, LogLevel.WARN, [ @@ -19,14 +20,14 @@ describe(ACL.name, () => { ]); // Node Ids - const nodeIdX = testUtils.generateRandomNodeId(); - const nodeIdY = testUtils.generateRandomNodeId(); - const nodeIdG1First = testUtils.generateRandomNodeId(); - const nodeIdG1Second = testUtils.generateRandomNodeId(); - const nodeIdG1Third = testUtils.generateRandomNodeId(); - const nodeIdG1Fourth = testUtils.generateRandomNodeId(); - const nodeIdG2First = testUtils.generateRandomNodeId(); - const nodeIdG2Second = testUtils.generateRandomNodeId(); + const nodeIdX = testNodesUtils.generateRandomNodeId(); + const nodeIdY = testNodesUtils.generateRandomNodeId(); + const nodeIdG1First = testNodesUtils.generateRandomNodeId(); + const nodeIdG1Second = testNodesUtils.generateRandomNodeId(); + const nodeIdG1Third = testNodesUtils.generateRandomNodeId(); + const nodeIdG1Fourth = testNodesUtils.generateRandomNodeId(); + const nodeIdG2First = testNodesUtils.generateRandomNodeId(); + const nodeIdG2Second = testNodesUtils.generateRandomNodeId(); let dataDir: string; let db: DB; @@ -108,18 +109,30 @@ describe(ACL.name, () => { await expect(acl.setNodesPerm([], {} as Permission)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); + await expect(acl.setNodesPermOps([], {} as Permission)).rejects.toThrow( + aclErrors.ErrorACLNotRunning, + ); await expect(acl.setNodePerm(nodeIdX, {} as Permission)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); + await expect(acl.setNodePermOps(nodeIdX, {} as Permission)).rejects.toThrow( + aclErrors.ErrorACLNotRunning, + ); await expect(acl.unsetNodePerm(nodeIdX)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); + await expect(acl.unsetNodePermOps(nodeIdX)).rejects.toThrow( + aclErrors.ErrorACLNotRunning, + ); await expect(acl.unsetVaultPerms(1 as VaultId)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); await expect(acl.joinNodePerm(nodeIdX, [])).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); + await expect(acl.joinNodePermOps(nodeIdX, [])).rejects.toThrow( + aclErrors.ErrorACLNotRunning, + ); await expect(acl.joinVaultPerms(1 as VaultId, [])).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); diff --git a/tests/agent/utils.ts b/tests/agent/utils.ts index f2b896024..7712d0fa8 100644 --- a/tests/agent/utils.ts +++ b/tests/agent/utils.ts @@ -1,5 +1,4 @@ import type { Host, Port, ProxyConfig } from '@/network/types'; - import type { IAgentServiceServer } from '@/proto/js/polykey/v1/agent_service_grpc_pb'; import type { KeyManager } from '@/keys'; import type { VaultManager } from '@/vaults'; @@ -20,7 +19,7 @@ import { createAgentService, GRPCClientAgent, } from '@/agent'; -import * as testUtils from '../utils'; +import * as testNodesUtils from '../nodes/utils'; async function openTestAgentServer({ keyManager, @@ -89,7 +88,7 @@ async function openTestAgentClient( new StreamHandler(), ]); return await GRPCClientAgent.createGRPCClientAgent({ - nodeId: nodeId ?? testUtils.generateRandomNodeId(), + nodeId: nodeId ?? testNodesUtils.generateRandomNodeId(), host: '127.0.0.1' as Host, port: port as Port, logger: logger, diff --git a/tests/bin/nodes/add.test.ts b/tests/bin/nodes/add.test.ts index 062cf6cdf..85b598786 100644 --- a/tests/bin/nodes/add.test.ts +++ b/tests/bin/nodes/add.test.ts @@ -11,11 +11,12 @@ import * as nodesUtils from '@/nodes/utils'; import * as keysUtils from '@/keys/utils'; import * as testBinUtils from '../utils'; import * as testUtils from '../../utils'; +import * as testNodesUtils from '../../nodes/utils'; describe('add', () => { const logger = new Logger('add test', LogLevel.WARN, [new StreamHandler()]); const password = 'helloworld'; - const validNodeId = testUtils.generateRandomNodeId(); + const validNodeId = testNodesUtils.generateRandomNodeId(); const invalidNodeId = IdInternal.fromString('INVALIDID'); const validHost = '0.0.0.0'; const invalidHost = 'INVALIDHOST'; diff --git a/tests/bin/vaults/vaults.test.ts b/tests/bin/vaults/vaults.test.ts index 52b5f4e4c..949f208ee 100644 --- a/tests/bin/vaults/vaults.test.ts +++ b/tests/bin/vaults/vaults.test.ts @@ -11,7 +11,7 @@ import * as vaultsUtils from '@/vaults/utils'; import sysexits from '@/utils/sysexits'; import NotificationsManager from '@/notifications/NotificationsManager'; import * as testBinUtils from '../utils'; -import * as testUtils from '../../utils'; +import * as testNodesUtils from '../../nodes/utils'; jest.mock('@/keys/utils', () => ({ ...jest.requireActual('@/keys/utils'), @@ -378,7 +378,7 @@ describe('CLI vaults', () => { mockedSendNotification.mockImplementation(async (_) => {}); const vaultId = await polykeyAgent.vaultManager.createVault(vaultName); const vaultIdEncoded = vaultsUtils.encodeVaultId(vaultId); - const targetNodeId = testUtils.generateRandomNodeId(); + const targetNodeId = testNodesUtils.generateRandomNodeId(); const targetNodeIdEncoded = nodesUtils.encodeNodeId(targetNodeId); await polykeyAgent.gestaltGraph.setNode({ id: nodesUtils.encodeNodeId(targetNodeId), @@ -418,7 +418,7 @@ describe('CLI vaults', () => { ); const vaultIdEncoded1 = vaultsUtils.encodeVaultId(vaultId1); const vaultIdEncoded2 = vaultsUtils.encodeVaultId(vaultId2); - const targetNodeId = testUtils.generateRandomNodeId(); + const targetNodeId = testNodesUtils.generateRandomNodeId(); const targetNodeIdEncoded = nodesUtils.encodeNodeId(targetNodeId); await polykeyAgent.gestaltGraph.setNode({ id: nodesUtils.encodeNodeId(targetNodeId), @@ -489,7 +489,7 @@ describe('CLI vaults', () => { ); const vaultIdEncoded1 = vaultsUtils.encodeVaultId(vaultId1); const vaultIdEncoded2 = vaultsUtils.encodeVaultId(vaultId2); - const targetNodeId = testUtils.generateRandomNodeId(); + const targetNodeId = testNodesUtils.generateRandomNodeId(); const targetNodeIdEncoded = nodesUtils.encodeNodeId(targetNodeId); await polykeyAgent.gestaltGraph.setNode({ id: nodesUtils.encodeNodeId(targetNodeId), diff --git a/tests/claims/utils.test.ts b/tests/claims/utils.test.ts index f7c6e6410..069a6dcef 100644 --- a/tests/claims/utils.test.ts +++ b/tests/claims/utils.test.ts @@ -11,12 +11,13 @@ import * as claimsErrors from '@/claims/errors'; import { utils as keysUtils } from '@/keys'; import { utils as nodesUtils } from '@/nodes'; import * as testUtils from '../utils'; +import * as testNodesUtils from '../nodes/utils'; describe('claims/utils', () => { // Node Ids - const nodeId1 = testUtils.generateRandomNodeId(); + const nodeId1 = testNodesUtils.generateRandomNodeId(); const nodeId1Encoded = nodesUtils.encodeNodeId(nodeId1); - const nodeId2 = testUtils.generateRandomNodeId(); + const nodeId2 = testNodesUtils.generateRandomNodeId(); const nodeId2Encoded = nodesUtils.encodeNodeId(nodeId2); let publicKey: PublicKeyPem; diff --git a/tests/client/service/gestaltsDiscoveryByNode.test.ts b/tests/client/service/gestaltsDiscoveryByNode.test.ts index 7071428e6..e553a0693 100644 --- a/tests/client/service/gestaltsDiscoveryByNode.test.ts +++ b/tests/client/service/gestaltsDiscoveryByNode.test.ts @@ -26,6 +26,7 @@ import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import * as testUtils from '../../utils'; +import * as testNodesUtils from '../../nodes/utils'; describe('gestaltsDiscoveryByNode', () => { const logger = new Logger('gestaltsDiscoveryByNode test', LogLevel.WARN, [ @@ -35,7 +36,7 @@ describe('gestaltsDiscoveryByNode', () => { const authenticate = async (metaClient, metaServer = new Metadata()) => metaServer; const node: NodeInfo = { - id: nodesUtils.encodeNodeId(testUtils.generateRandomNodeId()), + id: nodesUtils.encodeNodeId(testNodesUtils.generateRandomNodeId()), chain: {}, }; let mockedGenerateKeyPair: jest.SpyInstance; diff --git a/tests/client/service/notificationsRead.test.ts b/tests/client/service/notificationsRead.test.ts index 73690a54d..d78bb5eaa 100644 --- a/tests/client/service/notificationsRead.test.ts +++ b/tests/client/service/notificationsRead.test.ts @@ -24,12 +24,13 @@ import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import * as clientUtils from '@/client/utils'; import * as testUtils from '../../utils'; +import * as testNodesUtils from '../../nodes/utils'; describe('notificationsRead', () => { const logger = new Logger('notificationsRead test', LogLevel.WARN, [ new StreamHandler(), ]); - const nodeIdSender = testUtils.generateRandomNodeId(); + const nodeIdSender = testNodesUtils.generateRandomNodeId(); const nodeIdSenderEncoded = nodesUtils.encodeNodeId(nodeIdSender); const password = 'helloworld'; const authenticate = async (metaClient, metaServer = new Metadata()) => diff --git a/tests/discovery/Discovery.test.ts b/tests/discovery/Discovery.test.ts index c11c8d000..1b6e0e120 100644 --- a/tests/discovery/Discovery.test.ts +++ b/tests/discovery/Discovery.test.ts @@ -237,7 +237,7 @@ describe('Discovery', () => { discovery.queueDiscoveryByIdentity('' as ProviderId, '' as IdentityId), ).rejects.toThrow(discoveryErrors.ErrorDiscoveryNotRunning); await expect( - discovery.queueDiscoveryByNode(testUtils.generateRandomNodeId()), + discovery.queueDiscoveryByNode(testNodesUtils.generateRandomNodeId()), ).rejects.toThrow(discoveryErrors.ErrorDiscoveryNotRunning); }); test('discovery by node', async () => { diff --git a/tests/gestalts/GestaltGraph.test.ts b/tests/gestalts/GestaltGraph.test.ts index 4b69761ce..0953a2b4a 100644 --- a/tests/gestalts/GestaltGraph.test.ts +++ b/tests/gestalts/GestaltGraph.test.ts @@ -20,19 +20,19 @@ import * as gestaltsErrors from '@/gestalts/errors'; import * as gestaltsUtils from '@/gestalts/utils'; import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; -import * as testUtils from '../utils'; +import * as testNodesUtils from '../nodes/utils'; describe('GestaltGraph', () => { const logger = new Logger('GestaltGraph Test', LogLevel.WARN, [ new StreamHandler(), ]); - const nodeIdABC = testUtils.generateRandomNodeId(); + const nodeIdABC = testNodesUtils.generateRandomNodeId(); const nodeIdABCEncoded = nodesUtils.encodeNodeId(nodeIdABC); - const nodeIdDEE = testUtils.generateRandomNodeId(); + const nodeIdDEE = testNodesUtils.generateRandomNodeId(); const nodeIdDEEEncoded = nodesUtils.encodeNodeId(nodeIdDEE); - const nodeIdDEF = testUtils.generateRandomNodeId(); + const nodeIdDEF = testNodesUtils.generateRandomNodeId(); const nodeIdDEFEncoded = nodesUtils.encodeNodeId(nodeIdDEF); - const nodeIdZZZ = testUtils.generateRandomNodeId(); + const nodeIdZZZ = testNodesUtils.generateRandomNodeId(); const nodeIdZZZEncoded = nodesUtils.encodeNodeId(nodeIdZZZ); let dataDir: string; diff --git a/tests/grpc/GRPCClient.test.ts b/tests/grpc/GRPCClient.test.ts index 31028187e..e18f301e6 100644 --- a/tests/grpc/GRPCClient.test.ts +++ b/tests/grpc/GRPCClient.test.ts @@ -17,7 +17,7 @@ import * as grpcErrors from '@/grpc/errors'; import * as clientUtils from '@/client/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as utils from './utils'; -import * as testUtils from '../utils'; +import * as testNodesUtils from '../nodes/utils'; import { expectRemoteError } from '../utils'; describe('GRPCClient', () => { @@ -62,7 +62,7 @@ describe('GRPCClient', () => { }, }); const keyManager = { - getNodeId: () => testUtils.generateRandomNodeId(), + getNodeId: () => testNodesUtils.generateRandomNodeId(), } as KeyManager; // Cheeky mocking. sessionManager = await SessionManager.createSessionManager({ db, diff --git a/tests/identities/IdentitiesManager.test.ts b/tests/identities/IdentitiesManager.test.ts index b7ca969b0..23000440b 100644 --- a/tests/identities/IdentitiesManager.test.ts +++ b/tests/identities/IdentitiesManager.test.ts @@ -17,7 +17,7 @@ import * as identitiesErrors from '@/identities/errors'; import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import TestProvider from './TestProvider'; -import * as testUtils from '../utils'; +import * as testNodesUtils from '../nodes/utils'; describe('IdentitiesManager', () => { const logger = new Logger('IdentitiesManager Test', LogLevel.WARN, [ @@ -219,7 +219,7 @@ describe('IdentitiesManager', () => { expect(identityDatas).toHaveLength(1); expect(identityDatas).not.toContainEqual(identityData); // Now publish a claim - const nodeIdSome = testUtils.generateRandomNodeId(); + const nodeIdSome = testNodesUtils.generateRandomNodeId(); const nodeIdSomeEncoded = nodesUtils.encodeNodeId(nodeIdSome); const signatures: Record = {}; signatures[nodeIdSome] = { diff --git a/tests/network/Proxy.test.ts b/tests/network/Proxy.test.ts index f199f7a0b..fc8055ea7 100644 --- a/tests/network/Proxy.test.ts +++ b/tests/network/Proxy.test.ts @@ -13,6 +13,7 @@ import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import { poll, promise, promisify, timerStart, timerStop } from '@/utils'; import * as testUtils from '../utils'; +import * as testNodesUtils from '../nodes/utils'; /** * Mock HTTP Connect Request @@ -110,11 +111,11 @@ describe(Proxy.name, () => { const logger = new Logger(`${Proxy.name} test`, LogLevel.WARN, [ new StreamHandler(), ]); - const nodeIdABC = testUtils.generateRandomNodeId(); + const nodeIdABC = testNodesUtils.generateRandomNodeId(); const nodeIdABCEncoded = nodesUtils.encodeNodeId(nodeIdABC); - const nodeIdSome = testUtils.generateRandomNodeId(); + const nodeIdSome = testNodesUtils.generateRandomNodeId(); const nodeIdSomeEncoded = nodesUtils.encodeNodeId(nodeIdSome); - const nodeIdRandom = testUtils.generateRandomNodeId(); + const nodeIdRandom = testNodesUtils.generateRandomNodeId(); const authToken = 'abc123'; let keyPairPem: KeyPairPem; let certPem: string; diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index ed80ab06a..c22475912 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -33,6 +33,7 @@ import * as GRPCErrors from '@/grpc/errors'; import * as nodesUtils from '@/nodes/utils'; import * as agentErrors from '@/agent/errors'; import * as grpcUtils from '@/grpc/utils'; +import * as testNodesUtils from './utils'; import * as testUtils from '../utils'; import * as grpcTestUtils from '../grpc/utils'; import * as agentTestUtils from '../agent/utils'; @@ -72,7 +73,7 @@ describe('${NodeConnection.name} test', () => { const password = 'password'; const node: NodeInfo = { - id: nodesUtils.encodeNodeId(testUtils.generateRandomNodeId()), + id: nodesUtils.encodeNodeId(testNodesUtils.generateRandomNodeId()), chain: {}, }; @@ -703,7 +704,7 @@ describe('${NodeConnection.name} test', () => { "should call `killSelf and throw if the server %s's during testUnaryFail", async (option) => { let nodeConnection: - | NodeConnection + | NodeConnection | undefined; let testProxy: Proxy | undefined; let testProcess: child_process.ChildProcessWithoutNullStreams | undefined; @@ -748,7 +749,7 @@ describe('${NodeConnection.name} test', () => { targetHost: testProxy.getProxyHost(), targetPort: testProxy.getProxyPort(), clientFactory: (args) => - grpcTestUtils.GRPCClientTest.createGRPCClientTest(args), + testGrpcUtils.GRPCClientTest.createGRPCClientTest(args), }); const client = nodeConnection.getClient(); @@ -773,7 +774,7 @@ describe('${NodeConnection.name} test', () => { "should call `killSelf and throw if the server %s's during testStreamFail", async (option) => { let nodeConnection: - | NodeConnection + | NodeConnection | undefined; let testProxy: Proxy | undefined; let testProcess: child_process.ChildProcessWithoutNullStreams | undefined; @@ -818,7 +819,7 @@ describe('${NodeConnection.name} test', () => { targetHost: testProxy.getProxyHost(), targetPort: testProxy.getProxyPort(), clientFactory: (args) => - grpcTestUtils.GRPCClientTest.createGRPCClientTest(args), + testGrpcUtils.GRPCClientTest.createGRPCClientTest(args), }); const client = nodeConnection.getClient(); diff --git a/tests/nodes/NodeConnectionManager.general.test.ts b/tests/nodes/NodeConnectionManager.general.test.ts index a6c3638cb..d21be106b 100644 --- a/tests/nodes/NodeConnectionManager.general.test.ts +++ b/tests/nodes/NodeConnectionManager.general.test.ts @@ -19,8 +19,7 @@ import * as keysUtils from '@/keys/utils'; import * as grpcUtils from '@/grpc/utils'; import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; -import * as nodesTestUtils from './utils'; -import * as testUtils from '../utils'; +import * as testNodesUtils from './utils'; describe(`${NodeConnectionManager.name} general test`, () => { const logger = new Logger( @@ -419,11 +418,11 @@ describe(`${NodeConnectionManager.name} general test`, () => { try { // Generate the node ID to find the closest nodes to (in bucket 100) const nodeId = keyManager.getNodeId(); - const nodeIdToFind = nodesTestUtils.generateNodeIdForBucket(nodeId, 100); + const nodeIdToFind = testNodesUtils.generateNodeIdForBucket(nodeId, 100); // Now generate and add 20 nodes that will be close to this node ID const addedClosestNodes: NodeData[] = []; for (let i = 1; i < 101; i += 5) { - const closeNodeId = nodesTestUtils.generateNodeIdForBucket( + const closeNodeId = testNodesUtils.generateNodeIdForBucket( nodeIdToFind, i, ); @@ -489,7 +488,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { // Now generate and add 20 nodes that will be close to this node ID const addedClosestNodes: NodeData[] = []; for (let i = 1; i < 101; i += 5) { - const closeNodeId = nodesTestUtils.generateNodeIdForBucket( + const closeNodeId = testNodesUtils.generateNodeIdForBucket( targetNodeId, i, ); @@ -551,8 +550,8 @@ describe(`${NodeConnectionManager.name} general test`, () => { // To test this we need to... // 2. call relayHolePunchMessage // 3. check that the relevant call was made. - const sourceNodeId = testUtils.generateRandomNodeId(); - const targetNodeId = testUtils.generateRandomNodeId(); + const sourceNodeId = testNodesUtils.generateRandomNodeId(); + const targetNodeId = testNodesUtils.generateRandomNodeId(); await nodeConnectionManager.sendHolePunchMessage( remoteNodeId1, sourceNodeId, @@ -588,7 +587,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { // To test this we need to... // 2. call relayHolePunchMessage // 3. check that the relevant call was made. - const sourceNodeId = testUtils.generateRandomNodeId(); + const sourceNodeId = testNodesUtils.generateRandomNodeId(); const relayMessage = new nodesPB.Relay(); relayMessage.setSrcId(nodesUtils.encodeNodeId(sourceNodeId)); relayMessage.setTargetId(nodesUtils.encodeNodeId(remoteNodeId1)); diff --git a/tests/nodes/NodeGraph.test.ts b/tests/nodes/NodeGraph.test.ts index 6b9eec700..6ea350cad 100644 --- a/tests/nodes/NodeGraph.test.ts +++ b/tests/nodes/NodeGraph.test.ts @@ -1,59 +1,46 @@ -import type { Host, Port } from '@/network/types'; -import type { NodeAddress, NodeData, NodeId } from '@/nodes/types'; +import type { + NodeId, + NodeData, + NodeAddress, + NodeBucket, + NodeBucketIndex, +} from '@/nodes/types'; import os from 'os'; import path from 'path'; import fs from 'fs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { IdInternal } from '@matrixai/id'; -import NodeConnectionManager from '@/nodes/NodeConnectionManager'; import NodeGraph from '@/nodes/NodeGraph'; -import * as nodesErrors from '@/nodes/errors'; import KeyManager from '@/keys/KeyManager'; import * as keysUtils from '@/keys/utils'; -import Proxy from '@/network/Proxy'; import * as nodesUtils from '@/nodes/utils'; -import Sigchain from '@/sigchain/Sigchain'; -import * as nodesTestUtils from './utils'; +import * as nodesErrors from '@/nodes/errors'; +import * as utils from '@/utils'; +import * as testNodesUtils from './utils'; +import * as testUtils from '../utils'; describe(`${NodeGraph.name} test`, () => { - const localHost = '127.0.0.1' as Host; - const port = 0 as Port; const password = 'password'; - let nodeGraph: NodeGraph; - let nodeId: NodeId; - - const nodeId1 = IdInternal.create([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, - ]); - const dummyNode = nodesUtils.decodeNodeId( - 'vi3et1hrpv2m2lrplcm7cu913kr45v51cak54vm68anlbvuf83ra0', - )!; - - const logger = new Logger(`${NodeGraph.name} test`, LogLevel.ERROR, [ + const logger = new Logger(`${NodeGraph.name} test`, LogLevel.WARN, [ new StreamHandler(), ]); - let proxy: Proxy; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; let dataDir: string; let keyManager: KeyManager; + let dbKey: Buffer; + let dbPath: string; let db: DB; - let nodeConnectionManager: NodeConnectionManager; - let sigchain: Sigchain; - - const hostGen = (i: number) => `${i}.${i}.${i}.${i}` as Host; - - const mockedGenerateDeterministicKeyPair = jest.spyOn( - keysUtils, - 'generateDeterministicKeyPair', - ); - - beforeEach(async () => { - mockedGenerateDeterministicKeyPair.mockImplementation((bits, _) => { - return keysUtils.generateKeyPair(bits); - }); - + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValue(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValue(globalKeyPair); dataDir = await fs.promises.mkdtemp( path.join(os.tmpdir(), 'polykey-test-'), ); @@ -63,559 +50,669 @@ describe(`${NodeGraph.name} test`, () => { keysPath, logger, }); - proxy = new Proxy({ - authToken: 'auth', - logger: logger, - }); - await proxy.start({ - serverHost: localHost, - serverPort: port, - tlsConfig: { - keyPrivatePem: keyManager.getRootKeyPairPem().privateKey, - certChainPem: await keyManager.getRootCertChainPem(), - }, + dbKey = await keysUtils.generateKey(); + dbPath = `${dataDir}/db`; + }); + afterAll(async () => { + await keyManager.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, }); - const dbPath = `${dataDir}/db`; + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + beforeEach(async () => { db = await DB.createDB({ dbPath, logger, crypto: { - key: keyManager.dbKey, + key: dbKey, ops: { encrypt: keysUtils.encryptWithKey, decrypt: keysUtils.decryptWithKey, }, }, }); - sigchain = await Sigchain.createSigchain({ - keyManager: keyManager, - db: db, - logger: logger, - }); - nodeGraph = await NodeGraph.createNodeGraph({ + }); + afterEach(async () => { + await db.stop(); + await db.destroy(); + }); + test('get, set and unset node IDs', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ db, keyManager, logger, }); - nodeConnectionManager = new NodeConnectionManager({ - keyManager: keyManager, - nodeGraph: nodeGraph, - proxy: proxy, - logger: logger, + let nodeId1: NodeId; + do { + nodeId1 = testNodesUtils.generateRandomNodeId(); + } while (nodeId1.equals(keyManager.getNodeId())); + let nodeId2: NodeId; + do { + nodeId2 = testNodesUtils.generateRandomNodeId(); + } while (nodeId2.equals(keyManager.getNodeId())); + + await nodeGraph.setNode(nodeId1, { + host: '10.0.0.1', + port: 1234, + } as NodeAddress); + const nodeData1 = await nodeGraph.getNode(nodeId1); + expect(nodeData1).toStrictEqual({ + address: { + host: '10.0.0.1', + port: 1234, + }, + lastUpdated: expect.any(Number), }); - await nodeConnectionManager.start(); - // Retrieve the NodeGraph reference from NodeManager - nodeId = keyManager.getNodeId(); - }); - - afterEach(async () => { - await db.stop(); - await sigchain.stop(); - await nodeConnectionManager.stop(); - await nodeGraph.stop(); - await keyManager.stop(); - await proxy.stop(); - await fs.promises.rm(dataDir, { - force: true, - recursive: true, + await utils.sleep(1000); + await nodeGraph.setNode(nodeId2, { + host: 'abc.com', + port: 8978, + } as NodeAddress); + const nodeData2 = await nodeGraph.getNode(nodeId2); + expect(nodeData2).toStrictEqual({ + address: { + host: 'abc.com', + port: 8978, + }, + lastUpdated: expect.any(Number), }); + expect(nodeData2!.lastUpdated > nodeData1!.lastUpdated).toBe(true); + const nodes = await utils.asyncIterableArray(nodeGraph.getNodes()); + expect(nodes).toHaveLength(2); + expect(nodes).toContainEqual([ + nodeId1, + { + address: { + host: '10.0.0.1', + port: 1234, + }, + lastUpdated: expect.any(Number), + }, + ]); + expect(nodes).toContainEqual([ + nodeId2, + { + address: { + host: 'abc.com', + port: 8978, + }, + lastUpdated: expect.any(Number), + }, + ]); + await nodeGraph.unsetNode(nodeId1); + expect(await nodeGraph.getNode(nodeId1)).toBeUndefined(); + expect(await utils.asyncIterableArray(nodeGraph.getNodes())).toStrictEqual([ + [ + nodeId2, + { + address: { + host: 'abc.com', + port: 8978, + }, + lastUpdated: expect.any(Number), + }, + ], + ]); + await nodeGraph.unsetNode(nodeId2); + await nodeGraph.stop(); }); - - test('NodeGraph readiness', async () => { - const nodeGraph2 = await NodeGraph.createNodeGraph({ + test('get all nodes', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ db, keyManager, logger, }); - // @ts-ignore - await expect(nodeGraph2.destroy()).rejects.toThrow( - nodesErrors.ErrorNodeGraphRunning, - ); - // Should be a noop - await nodeGraph2.start(); - await nodeGraph2.stop(); - await nodeGraph2.destroy(); - await expect(async () => { - await nodeGraph2.start(); - }).rejects.toThrow(nodesErrors.ErrorNodeGraphDestroyed); - await expect(async () => { - await nodeGraph2.getBucket(0); - }).rejects.toThrow(nodesErrors.ErrorNodeGraphNotRunning); - await expect(async () => { - await nodeGraph2.getBucket(0); - }).rejects.toThrow(nodesErrors.ErrorNodeGraphNotRunning); - }); - test('knows node (true and false case)', async () => { - // Known node - const nodeAddress1: NodeAddress = { - host: '127.0.0.1' as Host, - port: 11111 as Port, - }; - await nodeGraph.setNode(nodeId1, nodeAddress1); - expect(await nodeGraph.knowsNode(nodeId1)).toBeTruthy(); - - // Unknown node - expect(await nodeGraph.knowsNode(dummyNode)).toBeFalsy(); - }); - test('finds correct node address', async () => { - // New node added - const newNode2Id = nodeId1; - const newNode2Address = { host: '227.1.1.1', port: 4567 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - // Get node address - const foundAddress = await nodeGraph.getNode(newNode2Id); - expect(foundAddress).toEqual({ host: '227.1.1.1', port: 4567 }); - }); - test('unable to find node address', async () => { - // New node added - const newNode2Id = nodeId1; - const newNode2Address = { host: '227.1.1.1', port: 4567 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - // Get node address (of non-existent node) - const foundAddress = await nodeGraph.getNode(dummyNode); - expect(foundAddress).toBeUndefined(); - }); - test('adds a single node into a bucket', async () => { - // New node added - const newNode2Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 1); - const newNode2Address = { host: '227.1.1.1', port: 4567 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - // Check new node is in retrieved bucket from database - // bucketIndex = 1 as "NODEID1" XOR "NODEID2" = 3 - const bucket = await nodeGraph.getBucket(1); - expect(bucket).toBeDefined(); - expect(bucket![newNode2Id]).toEqual({ - address: { host: '227.1.1.1', port: 4567 }, - lastUpdated: expect.any(Date), + let nodeIds = Array.from({ length: 25 }, () => { + return testNodesUtils.generateRandomNodeId(); }); - }); - test('adds multiple nodes into the same bucket', async () => { - // Add 3 new nodes into bucket 4 - const bucketIndex = 4; - const newNode1Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 0, + nodeIds = nodeIds.filter( + (nodeId) => !nodeId.equals(keyManager.getNodeId()), ); - const newNode1Address = { host: '4.4.4.4', port: 4444 } as NodeAddress; - await nodeGraph.setNode(newNode1Id, newNode1Address); - - const newNode2Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 1, + let bucketIndexes: Array; + let nodes: Array<[NodeId, NodeData]>; + nodes = await utils.asyncIterableArray(nodeGraph.getNodes()); + expect(nodes).toHaveLength(0); + for (const nodeId of nodeIds) { + await utils.sleep(100); + await nodeGraph.setNode(nodeId, { + host: '127.0.0.1', + port: 55555, + } as NodeAddress); + } + nodes = await utils.asyncIterableArray(nodeGraph.getNodes()); + expect(nodes).toHaveLength(25); + // Sorted by bucket indexes ascending + bucketIndexes = nodes.map(([nodeId]) => + nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId), ); - const newNode2Address = { host: '5.5.5.5', port: 5555 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - const newNode3Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 2, + expect( + bucketIndexes.slice(1).every((bucketIndex, i) => { + return bucketIndexes[i] <= bucketIndex; + }), + ).toBe(true); + // Sorted by bucket indexes ascending explicitly + nodes = await utils.asyncIterableArray(nodeGraph.getNodes('asc')); + bucketIndexes = nodes.map(([nodeId]) => + nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId), ); - const newNode3Address = { host: '6.6.6.6', port: 6666 } as NodeAddress; - await nodeGraph.setNode(newNode3Id, newNode3Address); - // Based on XOR values, all 3 nodes should appear in bucket 4 - const bucket = await nodeGraph.getBucket(4); - expect(bucket).toBeDefined(); - if (!bucket) fail('bucket should be defined, letting TS know'); - expect(bucket[newNode1Id]).toEqual({ - address: { host: '4.4.4.4', port: 4444 }, - lastUpdated: expect.any(Date), + expect( + bucketIndexes.slice(1).every((bucketIndex, i) => { + return bucketIndexes[i] <= bucketIndex; + }), + ).toBe(true); + nodes = await utils.asyncIterableArray(nodeGraph.getNodes('desc')); + expect(nodes).toHaveLength(25); + // Sorted by bucket indexes descending + bucketIndexes = nodes.map(([nodeId]) => + nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId), + ); + expect( + bucketIndexes.slice(1).every((bucketIndex, i) => { + return bucketIndexes[i] >= bucketIndex; + }), + ).toBe(true); + await nodeGraph.stop(); + }); + test('setting same node ID throws error', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, }); - expect(bucket[newNode2Id]).toEqual({ - address: { host: '5.5.5.5', port: 5555 }, - lastUpdated: expect.any(Date), + await expect( + nodeGraph.setNode(keyManager.getNodeId(), { + host: '127.0.0.1', + port: 55555, + } as NodeAddress), + ).rejects.toThrow(nodesErrors.ErrorNodeGraphSameNodeId); + await nodeGraph.stop(); + }); + test('get bucket with 1 node', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, }); - expect(bucket[newNode3Id]).toEqual({ - address: { host: '6.6.6.6', port: 6666 }, - lastUpdated: expect.any(Date), + let nodeId: NodeId; + do { + nodeId = testNodesUtils.generateRandomNodeId(); + } while (nodeId.equals(keyManager.getNodeId())); + // Set one node + await nodeGraph.setNode(nodeId, { + host: '127.0.0.1', + port: 55555, + } as NodeAddress); + const bucketIndex = nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId); + const bucket = await nodeGraph.getBucket(bucketIndex); + expect(bucket).toHaveLength(1); + expect(bucket[0]).toStrictEqual([ + nodeId, + { + address: { + host: '127.0.0.1', + port: 55555, + }, + lastUpdated: expect.any(Number), + }, + ]); + expect(await nodeGraph.getBucketMeta(bucketIndex)).toStrictEqual({ + count: 1, }); - }); - test('adds a single node into different buckets', async () => { - // New node for bucket 3 - const newNode1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 3); - const newNode1Address = { host: '1.1.1.1', port: 1111 } as NodeAddress; - await nodeGraph.setNode(newNode1Id, newNode1Address); - // New node for bucket 255 (the highest possible bucket) - const newNode2Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 255); - const newNode2Address = { host: '2.2.2.2', port: 2222 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - const bucket3 = await nodeGraph.getBucket(3); - const bucket351 = await nodeGraph.getBucket(255); - if (bucket3 && bucket351) { - expect(bucket3[newNode1Id]).toEqual({ - address: { host: '1.1.1.1', port: 1111 }, - lastUpdated: expect.any(Date), - }); - expect(bucket351[newNode2Id]).toEqual({ - address: { host: '2.2.2.2', port: 2222 }, - lastUpdated: expect.any(Date), - }); - } else { - // Should be unreachable - fail('Bucket undefined'); - } - }); - test('deletes a single node (and removes bucket)', async () => { - // New node for bucket 2 - const newNode1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 2); - const newNode1Address = { host: '4.4.4.4', port: 4444 } as NodeAddress; - await nodeGraph.setNode(newNode1Id, newNode1Address); - - // Check the bucket is there first - const bucket = await nodeGraph.getBucket(2); - if (bucket) { - expect(bucket[newNode1Id]).toEqual({ - address: { host: '4.4.4.4', port: 4444 }, - lastUpdated: expect.any(Date), - }); + // Adjacent bucket should be empty + let bucketIndex_: number; + if (bucketIndex >= nodeId.length * 8 - 1) { + bucketIndex_ = bucketIndex - 1; + } else if (bucketIndex === 0) { + bucketIndex_ = bucketIndex + 1; } else { - // Should be unreachable - fail('Bucket undefined'); + bucketIndex_ = bucketIndex + 1; } - - // Delete the node - await nodeGraph.unsetNode(newNode1Id); - // Check bucket no longer exists - const newBucket = await nodeGraph.getBucket(2); - expect(newBucket).toBeUndefined(); + expect(await nodeGraph.getBucket(bucketIndex_)).toHaveLength(0); + expect(await nodeGraph.getBucketMeta(bucketIndex_)).toStrictEqual({ + count: 0, + }); + await nodeGraph.stop(); }); - test('deletes a single node (and retains remainder of bucket)', async () => { - // Add 3 new nodes into bucket 4 - const bucketIndex = 4; - const newNode1Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 0, - ); - const newNode1Address = { host: '4.4.4.4', port: 4444 } as NodeAddress; - await nodeGraph.setNode(newNode1Id, newNode1Address); - - const newNode2Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 1, + test('get bucket with multiple nodes', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + // Contiguous node IDs starting from 0 + let nodeIds = Array.from({ length: 25 }, (_, i) => + IdInternal.create( + utils.bigInt2Bytes(BigInt(i), keyManager.getNodeId().byteLength), + ), ); - const newNode2Address = { host: '5.5.5.5', port: 5555 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - const newNode3Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 2, + nodeIds = nodeIds.filter( + (nodeId) => !nodeId.equals(keyManager.getNodeId()), ); - const newNode3Address = { host: '6.6.6.6', port: 6666 } as NodeAddress; - await nodeGraph.setNode(newNode3Id, newNode3Address); - // Based on XOR values, all 3 nodes should appear in bucket 4 - const bucket = await nodeGraph.getBucket(bucketIndex); - if (bucket) { - expect(bucket[newNode1Id]).toEqual({ - address: { host: '4.4.4.4', port: 4444 }, - lastUpdated: expect.any(Date), - }); - expect(bucket[newNode2Id]).toEqual({ - address: { host: '5.5.5.5', port: 5555 }, - lastUpdated: expect.any(Date), - }); - expect(bucket[newNode3Id]).toEqual({ - address: { host: '6.6.6.6', port: 6666 }, - lastUpdated: expect.any(Date), - }); - } else { - // Should be unreachable - fail('Bucket undefined'); + for (const nodeId of nodeIds) { + await utils.sleep(100); + await nodeGraph.setNode(nodeId, { + host: '127.0.0.1', + port: 55555, + } as NodeAddress); } - - // Delete the node - await nodeGraph.unsetNode(newNode1Id); - // Check node no longer exists in the bucket - const newBucket = await nodeGraph.getBucket(bucketIndex); - if (newBucket) { - expect(newBucket[newNode1Id]).toBeUndefined(); - expect(bucket[newNode2Id]).toEqual({ - address: { host: '5.5.5.5', port: 5555 }, - lastUpdated: expect.any(Date), - }); - expect(bucket[newNode3Id]).toEqual({ - address: { host: '6.6.6.6', port: 6666 }, - lastUpdated: expect.any(Date), - }); + // Use first and last buckets because node IDs may be split between buckets + const bucketIndexFirst = nodesUtils.bucketIndex( + keyManager.getNodeId(), + nodeIds[0], + ); + const bucketIndexLast = nodesUtils.bucketIndex( + keyManager.getNodeId(), + nodeIds[nodeIds.length - 1], + ); + const bucketFirst = await nodeGraph.getBucket(bucketIndexFirst); + const bucketLast = await nodeGraph.getBucket(bucketIndexLast); + let bucket: NodeBucket; + let bucketIndex: NodeBucketIndex; + if (bucketFirst.length >= bucketLast.length) { + bucket = bucketFirst; + bucketIndex = bucketIndexFirst; } else { - // Should be unreachable - fail('New bucket undefined'); + bucket = bucketLast; + bucketIndex = bucketIndexLast; } - }); - test('enforces k-bucket size, removing least active node when a new node is discovered', async () => { - // Add k nodes to the database (importantly, they all go into the same bucket) - const bucketIndex = 59; - // Keep a record of the first node ID that we added - const firstNodeId = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, + expect(bucket.length > 1).toBe(true); + let bucketNodeIds = bucket.map(([nodeId]) => nodeId); + // The node IDs must be sorted lexicographically + expect( + bucketNodeIds.slice(1).every((nodeId, i) => { + return Buffer.compare(bucketNodeIds[i], nodeId) < 1; + }), + ).toBe(true); + // Sort by node ID asc + bucket = await nodeGraph.getBucket(bucketIndex, 'nodeId', 'asc'); + bucketNodeIds = bucket.map(([nodeId]) => nodeId); + expect( + bucketNodeIds.slice(1).every((nodeId, i) => { + return Buffer.compare(bucketNodeIds[i], nodeId) < 0; + }), + ).toBe(true); + // Sort by node ID desc + bucket = await nodeGraph.getBucket(bucketIndex, 'nodeId', 'desc'); + bucketNodeIds = bucket.map(([nodeId]) => nodeId); + expect( + bucketNodeIds.slice(1).every((nodeId, i) => { + return Buffer.compare(bucketNodeIds[i], nodeId) > 0; + }), + ).toBe(true); + // Sort by distance asc + bucket = await nodeGraph.getBucket(bucketIndex, 'distance', 'asc'); + let bucketDistances = bucket.map(([nodeId]) => + nodesUtils.nodeDistance(keyManager.getNodeId(), nodeId), ); - for (let i = 1; i <= nodeGraph.maxNodesPerBucket; i++) { - // Add the current node ID - const nodeAddress = { - host: hostGen(i), - port: i as Port, - }; - await nodeGraph.setNode( - nodesTestUtils.generateNodeIdForBucket(nodeId, bucketIndex, i), - nodeAddress, - ); - // Increment the current node ID + expect( + bucketDistances.slice(1).every((distance, i) => { + return bucketDistances[i] <= distance; + }), + ).toBe(true); + // Sort by distance desc + bucket = await nodeGraph.getBucket(bucketIndex, 'distance', 'desc'); + bucketDistances = bucket.map(([nodeId]) => + nodesUtils.nodeDistance(keyManager.getNodeId(), nodeId), + ); + expect( + bucketDistances.slice(1).every((distance, i) => { + return bucketDistances[i] >= distance; + }), + ).toBe(true); + // Sort by lastUpdated asc + bucket = await nodeGraph.getBucket(bucketIndex, 'lastUpdated', 'asc'); + let bucketLastUpdateds = bucket.map(([, nodeData]) => nodeData.lastUpdated); + expect( + bucketLastUpdateds.slice(1).every((lastUpdated, i) => { + return bucketLastUpdateds[i] <= lastUpdated; + }), + ).toBe(true); + bucket = await nodeGraph.getBucket(bucketIndex, 'lastUpdated', 'desc'); + bucketLastUpdateds = bucket.map(([, nodeData]) => nodeData.lastUpdated); + expect( + bucketLastUpdateds.slice(1).every((lastUpdated, i) => { + return bucketLastUpdateds[i] >= lastUpdated; + }), + ).toBe(true); + await nodeGraph.stop(); + }); + test('get all buckets', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + const now = utils.getUnixtime(); + for (let i = 0; i < 50; i++) { + await utils.sleep(50); + await nodeGraph.setNode(testNodesUtils.generateRandomNodeId(), { + host: '127.0.0.1', + port: utils.getRandomInt(0, 2 ** 16), + } as NodeAddress); } - // All of these nodes are in bucket 59 - const originalBucket = await nodeGraph.getBucket(bucketIndex); - if (originalBucket) { - expect(Object.keys(originalBucket).length).toBe( - nodeGraph.maxNodesPerBucket, - ); - } else { - // Should be unreachable - fail('Bucket undefined'); + let bucketIndex_ = -1; + // Ascending order + for await (const [bucketIndex, bucket] of nodeGraph.getBuckets( + 'nodeId', + 'asc', + )) { + expect(bucketIndex > bucketIndex_).toBe(true); + bucketIndex_ = bucketIndex; + expect(bucket.length > 0).toBe(true); + expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); + for (const [nodeId, nodeData] of bucket) { + expect(nodeId.byteLength).toBe(32); + expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( + bucketIndex, + ); + expect(nodeData.address.host).toBe('127.0.0.1'); + // Port of 0 is not allowed + expect(nodeData.address.port > 0).toBe(true); + expect(nodeData.address.port < 2 ** 16).toBe(true); + expect(nodeData.lastUpdated >= now).toBe(true); + } + const bucketNodeIds = bucket.map(([nodeId]) => nodeId); + expect( + bucketNodeIds.slice(1).every((nodeId, i) => { + return Buffer.compare(bucketNodeIds[i], nodeId) < 0; + }), + ).toBe(true); } - - // Attempt to add a new node into this full bucket (increment the last node - // ID that was added) - const newNodeId = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - nodeGraph.maxNodesPerBucket + 1, - ); - const newNodeAddress = { host: '0.0.0.1' as Host, port: 1234 as Port }; - await nodeGraph.setNode(newNodeId, newNodeAddress); - - const finalBucket = await nodeGraph.getBucket(bucketIndex); - if (finalBucket) { - // We should still have a full bucket (but no more) - expect(Object.keys(finalBucket).length).toEqual( - nodeGraph.maxNodesPerBucket, - ); - // Ensure that this new node is in the bucket - expect(finalBucket[newNodeId]).toEqual({ - address: newNodeAddress, - lastUpdated: expect.any(Date), - }); - // NODEID1 should have been removed from this bucket (as this was the least active) - // The first node added should have been removed from this bucket (as this - // was the least active, purely because it was inserted first) - expect(finalBucket[firstNodeId]).toBeUndefined(); - } else { - // Should be unreachable - fail('Bucket undefined'); + // There must have been at least 1 bucket + expect(bucketIndex_).not.toBe(-1); + // Descending order + bucketIndex_ = keyManager.getNodeId().length * 8; + for await (const [bucketIndex, bucket] of nodeGraph.getBuckets( + 'nodeId', + 'desc', + )) { + expect(bucketIndex < bucketIndex_).toBe(true); + bucketIndex_ = bucketIndex; + expect(bucket.length > 0).toBe(true); + expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); + for (const [nodeId, nodeData] of bucket) { + expect(nodeId.byteLength).toBe(32); + expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( + bucketIndex, + ); + expect(nodeData.address.host).toBe('127.0.0.1'); + // Port of 0 is not allowed + expect(nodeData.address.port > 0).toBe(true); + expect(nodeData.address.port < 2 ** 16).toBe(true); + expect(nodeData.lastUpdated >= now).toBe(true); + } + const bucketNodeIds = bucket.map(([nodeId]) => nodeId); + expect( + bucketNodeIds.slice(1).every((nodeId, i) => { + return Buffer.compare(bucketNodeIds[i], nodeId) > 0; + }), + ).toBe(true); } - }); - test('enforces k-bucket size, retaining all nodes if adding a pre-existing node', async () => { - // Add k nodes to the database (importantly, they all go into the same bucket) - const bucketIndex = 59; - const currNodeId = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - ); - // Keep a record of the first node ID that we added - // const firstNodeId = currNodeId; - let increment = 1; - for (let i = 1; i <= nodeGraph.maxNodesPerBucket; i++) { - // Add the current node ID - const nodeAddress = { - host: hostGen(i), - port: i as Port, - }; - await nodeGraph.setNode( - nodesTestUtils.generateNodeIdForBucket(nodeId, bucketIndex, increment), - nodeAddress, + expect(bucketIndex_).not.toBe(keyManager.getNodeId().length * 8); + // Distance ascending order + // Lower distance buckets first + bucketIndex_ = -1; + for await (const [bucketIndex, bucket] of nodeGraph.getBuckets( + 'distance', + 'asc', + )) { + expect(bucketIndex > bucketIndex_).toBe(true); + bucketIndex_ = bucketIndex; + expect(bucket.length > 0).toBe(true); + expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); + for (const [nodeId, nodeData] of bucket) { + expect(nodeId.byteLength).toBe(32); + expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( + bucketIndex, + ); + expect(nodeData.address.host).toBe('127.0.0.1'); + // Port of 0 is not allowed + expect(nodeData.address.port > 0).toBe(true); + expect(nodeData.address.port < 2 ** 16).toBe(true); + expect(nodeData.lastUpdated >= now).toBe(true); + } + const bucketDistances = bucket.map(([nodeId]) => + nodesUtils.nodeDistance(keyManager.getNodeId(), nodeId), ); - // Increment the current node ID - skip for the last one to keep currNodeId - // as the last added node ID - if (i !== nodeGraph.maxNodesPerBucket) { - increment++; + // It's the LAST bucket that fails this + expect( + bucketDistances.slice(1).every((distance, i) => { + return bucketDistances[i] <= distance; + }), + ).toBe(true); + } + // Distance descending order + // Higher distance buckets first + bucketIndex_ = keyManager.getNodeId().length * 8; + for await (const [bucketIndex, bucket] of nodeGraph.getBuckets( + 'distance', + 'desc', + )) { + expect(bucketIndex < bucketIndex_).toBe(true); + bucketIndex_ = bucketIndex; + expect(bucket.length > 0).toBe(true); + expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); + for (const [nodeId, nodeData] of bucket) { + expect(nodeId.byteLength).toBe(32); + expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( + bucketIndex, + ); + expect(nodeData.address.host).toBe('127.0.0.1'); + // Port of 0 is not allowed + expect(nodeData.address.port > 0).toBe(true); + expect(nodeData.address.port < 2 ** 16).toBe(true); + expect(nodeData.lastUpdated >= now).toBe(true); } + const bucketDistances = bucket.map(([nodeId]) => + nodesUtils.nodeDistance(keyManager.getNodeId(), nodeId), + ); + expect( + bucketDistances.slice(1).every((distance, i) => { + return bucketDistances[i] >= distance; + }), + ).toBe(true); } - // All of these nodes are in bucket 59 - const originalBucket = await nodeGraph.getBucket(bucketIndex); - if (originalBucket) { - expect(Object.keys(originalBucket).length).toBe( - nodeGraph.maxNodesPerBucket, + // Last updated ascending order + // Bucket index is ascending + bucketIndex_ = -1; + for await (const [bucketIndex, bucket] of nodeGraph.getBuckets( + 'lastUpdated', + 'asc', + )) { + expect(bucketIndex > bucketIndex_).toBe(true); + bucketIndex_ = bucketIndex; + expect(bucket.length > 0).toBe(true); + expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); + for (const [nodeId, nodeData] of bucket) { + expect(nodeId.byteLength).toBe(32); + expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( + bucketIndex, + ); + expect(nodeData.address.host).toBe('127.0.0.1'); + // Port of 0 is not allowed + expect(nodeData.address.port > 0).toBe(true); + expect(nodeData.address.port < 2 ** 16).toBe(true); + expect(nodeData.lastUpdated >= now).toBe(true); + } + const bucketLastUpdateds = bucket.map( + ([, nodeData]) => nodeData.lastUpdated, ); - } else { - // Should be unreachable - fail('Bucket undefined'); + expect( + bucketLastUpdateds.slice(1).every((lastUpdated, i) => { + return bucketLastUpdateds[i] <= lastUpdated; + }), + ).toBe(true); } - - // If we tried to re-add the first node, it would simply remove the original - // first node, as this is the "least active" - // We instead want to check that we don't mistakenly delete a node if we're - // updating an existing one - // So, re-add the last node - const newLastAddress: NodeAddress = { - host: '30.30.30.30' as Host, - port: 30 as Port, - }; - await nodeGraph.setNode(currNodeId, newLastAddress); - - const finalBucket = await nodeGraph.getBucket(bucketIndex); - if (finalBucket) { - // We should still have a full bucket - expect(Object.keys(finalBucket).length).toEqual( - nodeGraph.maxNodesPerBucket, + // Last updated descending order + // Bucket index is descending + bucketIndex_ = keyManager.getNodeId().length * 8; + for await (const [bucketIndex, bucket] of nodeGraph.getBuckets( + 'lastUpdated', + 'desc', + )) { + expect(bucketIndex < bucketIndex_).toBe(true); + bucketIndex_ = bucketIndex; + expect(bucket.length > 0).toBe(true); + expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); + for (const [nodeId, nodeData] of bucket) { + expect(nodeId.byteLength).toBe(32); + expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( + bucketIndex, + ); + expect(nodeData.address.host).toBe('127.0.0.1'); + // Port of 0 is not allowed + expect(nodeData.address.port > 0).toBe(true); + expect(nodeData.address.port < 2 ** 16).toBe(true); + expect(nodeData.lastUpdated >= now).toBe(true); + } + const bucketLastUpdateds = bucket.map( + ([, nodeData]) => nodeData.lastUpdated, ); - // Ensure that this new node is in the bucket - expect(finalBucket[currNodeId]).toEqual({ - address: newLastAddress, - lastUpdated: expect.any(Date), - }); - } else { - // Should be unreachable - fail('Bucket undefined'); + expect( + bucketLastUpdateds.slice(1).every((lastUpdated, i) => { + return bucketLastUpdateds[i] >= lastUpdated; + }), + ).toBe(true); } + await nodeGraph.stop(); }); - test('retrieves all buckets (in expected lexicographic order)', async () => { - // Bucket 0 is expected to never have any nodes (as nodeId XOR 0 = nodeId) - // Bucket 1 (minimum): - - const node1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 1); - const node1Address = { host: '1.1.1.1', port: 1111 } as NodeAddress; - await nodeGraph.setNode(node1Id, node1Address); - - // Bucket 4 (multiple nodes in 1 bucket): - const node41Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 4); - const node41Address = { host: '41.41.41.41', port: 4141 } as NodeAddress; - await nodeGraph.setNode(node41Id, node41Address); - const node42Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 4, 1); - const node42Address = { host: '42.42.42.42', port: 4242 } as NodeAddress; - await nodeGraph.setNode(node42Id, node42Address); - - // Bucket 10 (lexicographic ordering - should appear after 2): - const node10Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 10); - const node10Address = { host: '10.10.10.10', port: 1010 } as NodeAddress; - await nodeGraph.setNode(node10Id, node10Address); - - // Bucket 255 (maximum): - const node255Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 255); - const node255Address = { - host: '255.255.255.255', - port: 255, - } as NodeAddress; - await nodeGraph.setNode(node255Id, node255Address); - - const buckets = await nodeGraph.getAllBuckets(); - expect(buckets.length).toBe(4); - // Buckets should be returned in lexicographic ordering (using hex keys to - // ensure the bucket indexes are in numberical order) - expect(buckets).toEqual([ - { - [node1Id]: { - address: { host: '1.1.1.1', port: 1111 }, - lastUpdated: expect.any(String), - }, - }, - { - [node41Id]: { - address: { host: '41.41.41.41', port: 4141 }, - lastUpdated: expect.any(String), - }, - [node42Id]: { - address: { host: '42.42.42.42', port: 4242 }, - lastUpdated: expect.any(String), - }, - }, - { - [node10Id]: { - address: { host: '10.10.10.10', port: 1010 }, - lastUpdated: expect.any(String), - }, - }, - { - [node255Id]: { - address: { host: '255.255.255.255', port: 255 }, - lastUpdated: expect.any(String), - }, - }, - ]); - }); - test( - 'refreshes buckets', - async () => { - const initialNodes: Record = {}; - // Generate and add some nodes - for (let i = 1; i < 255; i += 20) { - const newNodeId = nodesTestUtils.generateNodeIdForBucket( - keyManager.getNodeId(), - i, - ); - const nodeAddress = { - host: hostGen(i), - port: i as Port, - }; - await nodeGraph.setNode(newNodeId, nodeAddress); - initialNodes[newNodeId] = { - id: newNodeId, - address: nodeAddress, - distance: nodesUtils.calculateDistance( - keyManager.getNodeId(), - newNodeId, - ), - }; + test('reset buckets', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + const now = utils.getUnixtime(); + for (let i = 0; i < 100; i++) { + await nodeGraph.setNode(testNodesUtils.generateRandomNodeId(), { + host: '127.0.0.1', + port: utils.getRandomInt(0, 2 ** 16), + } as NodeAddress); + } + const buckets0 = await utils.asyncIterableArray(nodeGraph.getBuckets()); + // Reset the buckets according to the new node ID + // Note that this should normally be only executed when the key manager NodeID changes + // This means methods that use the KeyManager's node ID cannot be used here in this test + const nodeIdNew1 = testNodesUtils.generateRandomNodeId(); + await nodeGraph.resetBuckets(nodeIdNew1); + const buckets1 = await utils.asyncIterableArray(nodeGraph.getBuckets()); + expect(buckets1.length > 0).toBe(true); + for (const [bucketIndex, bucket] of buckets1) { + expect(bucket.length > 0).toBe(true); + for (const [nodeId, nodeData] of bucket) { + expect(nodeId.byteLength).toBe(32); + expect(nodesUtils.bucketIndex(nodeIdNew1, nodeId)).toBe(bucketIndex); + expect(nodeData.address.host).toBe('127.0.0.1'); + // Port of 0 is not allowed + expect(nodeData.address.port > 0).toBe(true); + expect(nodeData.address.port < 2 ** 16).toBe(true); + expect(nodeData.lastUpdated >= now).toBe(true); } - - // Renew the keypair - await keyManager.renewRootKeyPair('newPassword'); - // Reset the test's node ID state - nodeId = keyManager.getNodeId(); - // Refresh the buckets - await nodeGraph.refreshBuckets(); - - // Get all the new buckets, and expect that each node is in the correct bucket - const newBuckets = await nodeGraph.getAllBuckets(); - let nodeCount = 0; - for (const b of newBuckets) { - for (const n of Object.keys(b)) { - const nodeId = IdInternal.fromString(n); - // Check that it was a node in the original DB - expect(initialNodes[nodeId]).toBeDefined(); - // Check it's in the correct bucket - const expectedIndex = nodesUtils.calculateBucketIndex( - keyManager.getNodeId(), - nodeId, - ); - const expectedBucket = await nodeGraph.getBucket(expectedIndex); - expect(expectedBucket).toBeDefined(); - expect(expectedBucket![nodeId]).toBeDefined(); - // Check it has the correct address - expect(b[nodeId].address).toEqual(initialNodes[nodeId].address); - nodeCount++; + } + expect(buckets1).not.toStrictEqual(buckets0); + // Resetting again should change the space + const nodeIdNew2 = testNodesUtils.generateRandomNodeId(); + await nodeGraph.resetBuckets(nodeIdNew2); + const buckets2 = await utils.asyncIterableArray(nodeGraph.getBuckets()); + expect(buckets2.length > 0).toBe(true); + for (const [bucketIndex, bucket] of buckets2) { + expect(bucket.length > 0).toBe(true); + for (const [nodeId, nodeData] of bucket) { + expect(nodeId.byteLength).toBe(32); + expect(nodesUtils.bucketIndex(nodeIdNew2, nodeId)).toBe(bucketIndex); + expect(nodeData.address.host).toBe('127.0.0.1'); + // Port of 0 is not allowed + expect(nodeData.address.port > 0).toBe(true); + expect(nodeData.address.port < 2 ** 16).toBe(true); + expect(nodeData.lastUpdated >= now).toBe(true); + } + } + expect(buckets2).not.toStrictEqual(buckets1); + // Resetting to the same NodeId results in the same bucket structure + await nodeGraph.resetBuckets(nodeIdNew2); + const buckets3 = await utils.asyncIterableArray(nodeGraph.getBuckets()); + expect(buckets3).toStrictEqual(buckets2); + // Resetting to an existing NodeId + const nodeIdExisting = buckets3[0][1][0][0]; + let nodeIdExistingFound = false; + await nodeGraph.resetBuckets(nodeIdExisting); + const buckets4 = await utils.asyncIterableArray(nodeGraph.getBuckets()); + expect(buckets4.length > 0).toBe(true); + for (const [bucketIndex, bucket] of buckets4) { + expect(bucket.length > 0).toBe(true); + for (const [nodeId, nodeData] of bucket) { + if (nodeId.equals(nodeIdExisting)) { + nodeIdExistingFound = true; } + expect(nodeId.byteLength).toBe(32); + expect(nodesUtils.bucketIndex(nodeIdExisting, nodeId)).toBe( + bucketIndex, + ); + expect(nodeData.address.host).toBe('127.0.0.1'); + // Port of 0 is not allowed + expect(nodeData.address.port > 0).toBe(true); + expect(nodeData.address.port < 2 ** 16).toBe(true); + expect(nodeData.lastUpdated >= now).toBe(true); } - // We had less than k (20) nodes, so we expect that all nodes will be re-added - // If we had more than k nodes, we may lose some of them (because the nodes - // may be re-added to newly full buckets) - expect(Object.keys(initialNodes).length).toEqual(nodeCount); - }, - global.defaultTimeout * 4, - ); - test('updates node', async () => { - // New node added - const node1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 2); - const node1Address = { host: '1.1.1.1', port: 1 } as NodeAddress; - await nodeGraph.setNode(node1Id, node1Address); - - // Check new node is in retrieved bucket from database - const bucket = await nodeGraph.getBucket(2); - const time1 = bucket![node1Id].lastUpdated; - - // Update node and check that time is later - const newNode1Address = { host: '2.2.2.2', port: 2 } as NodeAddress; - await nodeGraph.updateNode(node1Id, newNode1Address); - - const bucket2 = await nodeGraph.getBucket(2); - const time2 = bucket2![node1Id].lastUpdated; - expect(bucket2![node1Id].address).toEqual(newNode1Address); - expect(time1 < time2).toBeTruthy(); + } + expect(buckets4).not.toStrictEqual(buckets3); + // The existing node ID should not be put into the NodeGraph + expect(nodeIdExistingFound).toBe(false); + await nodeGraph.stop(); + }); + test('reset buckets is persistent', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + const now = utils.getUnixtime(); + for (let i = 0; i < 100; i++) { + await nodeGraph.setNode(testNodesUtils.generateRandomNodeId(), { + host: '127.0.0.1', + port: utils.getRandomInt(0, 2 ** 16), + } as NodeAddress); + } + const nodeIdNew1 = testNodesUtils.generateRandomNodeId(); + await nodeGraph.resetBuckets(nodeIdNew1); + await nodeGraph.stop(); + await nodeGraph.start(); + const buckets1 = await utils.asyncIterableArray(nodeGraph.getBuckets()); + expect(buckets1.length > 0).toBe(true); + for (const [bucketIndex, bucket] of buckets1) { + expect(bucket.length > 0).toBe(true); + for (const [nodeId, nodeData] of bucket) { + expect(nodeId.byteLength).toBe(32); + expect(nodesUtils.bucketIndex(nodeIdNew1, nodeId)).toBe(bucketIndex); + expect(nodeData.address.host).toBe('127.0.0.1'); + // Port of 0 is not allowed + expect(nodeData.address.port > 0).toBe(true); + expect(nodeData.address.port < 2 ** 16).toBe(true); + expect(nodeData.lastUpdated >= now).toBe(true); + } + } + const nodeIdNew2 = testNodesUtils.generateRandomNodeId(); + await nodeGraph.resetBuckets(nodeIdNew2); + await nodeGraph.stop(); + await nodeGraph.start(); + const buckets2 = await utils.asyncIterableArray(nodeGraph.getBuckets()); + expect(buckets2.length > 0).toBe(true); + for (const [bucketIndex, bucket] of buckets2) { + expect(bucket.length > 0).toBe(true); + for (const [nodeId, nodeData] of bucket) { + expect(nodeId.byteLength).toBe(32); + expect(nodesUtils.bucketIndex(nodeIdNew2, nodeId)).toBe(bucketIndex); + expect(nodeData.address.host).toBe('127.0.0.1'); + // Port of 0 is not allowed + expect(nodeData.address.port > 0).toBe(true); + expect(nodeData.address.port < 2 ** 16).toBe(true); + expect(nodeData.lastUpdated >= now).toBe(true); + } + } + expect(buckets2).not.toStrictEqual(buckets1); + await nodeGraph.stop(); }); }); diff --git a/tests/nodes/NodeGraph.test.ts.old b/tests/nodes/NodeGraph.test.ts.old new file mode 100644 index 000000000..1960c02d3 --- /dev/null +++ b/tests/nodes/NodeGraph.test.ts.old @@ -0,0 +1,624 @@ +import type { Host, Port } from '@/network/types'; +import type { NodeAddress, NodeData, NodeId } from '@/nodes/types'; +import os from 'os'; +import path from 'path'; +import fs from 'fs'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { DB } from '@matrixai/db'; +import { IdInternal } from '@matrixai/id'; +import NodeConnectionManager from '@/nodes/NodeConnectionManager'; +import NodeGraph from '@/nodes/NodeGraph'; +import * as nodesErrors from '@/nodes/errors'; +import KeyManager from '@/keys/KeyManager'; +import * as keysUtils from '@/keys/utils'; +import ForwardProxy from '@/network/ForwardProxy'; +import ReverseProxy from '@/network/ReverseProxy'; +import * as nodesUtils from '@/nodes/utils'; +import Sigchain from '@/sigchain/Sigchain'; +import * as nodesTestUtils from './utils'; + +describe(`${NodeGraph.name} test`, () => { + const password = 'password'; + let nodeGraph: NodeGraph; + let nodeId: NodeId; + + const nodeId1 = IdInternal.create([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, + ]); + const dummyNode = nodesUtils.decodeNodeId( + 'vi3et1hrpv2m2lrplcm7cu913kr45v51cak54vm68anlbvuf83ra0', + )!; + + const logger = new Logger(`${NodeGraph.name} test`, LogLevel.ERROR, [ + new StreamHandler(), + ]); + let fwdProxy: ForwardProxy; + let revProxy: ReverseProxy; + let dataDir: string; + let keyManager: KeyManager; + let db: DB; + let nodeConnectionManager: NodeConnectionManager; + let sigchain: Sigchain; + + const hostGen = (i: number) => `${i}.${i}.${i}.${i}` as Host; + + const mockedGenerateDeterministicKeyPair = jest.spyOn( + keysUtils, + 'generateDeterministicKeyPair', + ); + + beforeEach(async () => { + mockedGenerateDeterministicKeyPair.mockImplementation((bits, _) => { + return keysUtils.generateKeyPair(bits); + }); + + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const keysPath = `${dataDir}/keys`; + keyManager = await KeyManager.createKeyManager({ + password, + keysPath, + logger, + }); + fwdProxy = new ForwardProxy({ + authToken: 'auth', + logger: logger, + }); + + revProxy = new ReverseProxy({ + logger: logger, + }); + + await fwdProxy.start({ + tlsConfig: { + keyPrivatePem: keyManager.getRootKeyPairPem().privateKey, + certChainPem: await keyManager.getRootCertChainPem(), + }, + }); + const dbPath = `${dataDir}/db`; + db = await DB.createDB({ + dbPath, + logger, + crypto: { + key: keyManager.dbKey, + ops: { + encrypt: keysUtils.encryptWithKey, + decrypt: keysUtils.decryptWithKey, + }, + }, + }); + sigchain = await Sigchain.createSigchain({ + keyManager: keyManager, + db: db, + logger: logger, + }); + nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + nodeConnectionManager = new NodeConnectionManager({ + keyManager: keyManager, + nodeGraph: nodeGraph, + fwdProxy: fwdProxy, + revProxy: revProxy, + logger: logger, + }); + await nodeConnectionManager.start(); + // Retrieve the NodeGraph reference from NodeManager + nodeId = keyManager.getNodeId(); + }); + + afterEach(async () => { + await db.stop(); + await sigchain.stop(); + await nodeConnectionManager.stop(); + await nodeGraph.stop(); + await keyManager.stop(); + await fwdProxy.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + + test('NodeGraph readiness', async () => { + const nodeGraph2 = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + // @ts-ignore + await expect(nodeGraph2.destroy()).rejects.toThrow( + nodesErrors.ErrorNodeGraphRunning, + ); + // Should be a noop + await nodeGraph2.start(); + await nodeGraph2.stop(); + await nodeGraph2.destroy(); + await expect(async () => { + await nodeGraph2.start(); + }).rejects.toThrow(nodesErrors.ErrorNodeGraphDestroyed); + await expect(async () => { + await nodeGraph2.getBucket(0); + }).rejects.toThrow(nodesErrors.ErrorNodeGraphNotRunning); + await expect(async () => { + await nodeGraph2.getBucket(0); + }).rejects.toThrow(nodesErrors.ErrorNodeGraphNotRunning); + }); + test('knows node (true and false case)', async () => { + // Known node + const nodeAddress1: NodeAddress = { + host: '127.0.0.1' as Host, + port: 11111 as Port, + }; + await nodeGraph.setNode(nodeId1, nodeAddress1); + expect(await nodeGraph.knowsNode(nodeId1)).toBeTruthy(); + + // Unknown node + expect(await nodeGraph.knowsNode(dummyNode)).toBeFalsy(); + }); + test('finds correct node address', async () => { + // New node added + const newNode2Id = nodeId1; + const newNode2Address = { host: '227.1.1.1', port: 4567 } as NodeAddress; + await nodeGraph.setNode(newNode2Id, newNode2Address); + + // Get node address + const foundAddress = await nodeGraph.getNode(newNode2Id); + expect(foundAddress).toEqual({ host: '227.1.1.1', port: 4567 }); + }); + test('unable to find node address', async () => { + // New node added + const newNode2Id = nodeId1; + const newNode2Address = { host: '227.1.1.1', port: 4567 } as NodeAddress; + await nodeGraph.setNode(newNode2Id, newNode2Address); + + // Get node address (of non-existent node) + const foundAddress = await nodeGraph.getNode(dummyNode); + expect(foundAddress).toBeUndefined(); + }); + test('adds a single node into a bucket', async () => { + // New node added + const newNode2Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 1); + const newNode2Address = { host: '227.1.1.1', port: 4567 } as NodeAddress; + await nodeGraph.setNode(newNode2Id, newNode2Address); + + // Check new node is in retrieved bucket from database + // bucketIndex = 1 as "NODEID1" XOR "NODEID2" = 3 + const bucket = await nodeGraph.getBucket(1); + expect(bucket).toBeDefined(); + expect(bucket![newNode2Id]).toEqual({ + address: { host: '227.1.1.1', port: 4567 }, + lastUpdated: expect.any(Date), + }); + }); + test('adds multiple nodes into the same bucket', async () => { + // Add 3 new nodes into bucket 4 + const bucketIndex = 4; + const newNode1Id = nodesTestUtils.generateNodeIdForBucket( + nodeId, + bucketIndex, + 0, + ); + const newNode1Address = { host: '4.4.4.4', port: 4444 } as NodeAddress; + await nodeGraph.setNode(newNode1Id, newNode1Address); + + const newNode2Id = nodesTestUtils.generateNodeIdForBucket( + nodeId, + bucketIndex, + 1, + ); + const newNode2Address = { host: '5.5.5.5', port: 5555 } as NodeAddress; + await nodeGraph.setNode(newNode2Id, newNode2Address); + + const newNode3Id = nodesTestUtils.generateNodeIdForBucket( + nodeId, + bucketIndex, + 2, + ); + const newNode3Address = { host: '6.6.6.6', port: 6666 } as NodeAddress; + await nodeGraph.setNode(newNode3Id, newNode3Address); + // Based on XOR values, all 3 nodes should appear in bucket 4 + const bucket = await nodeGraph.getBucket(4); + expect(bucket).toBeDefined(); + if (!bucket) fail('bucket should be defined, letting TS know'); + expect(bucket[newNode1Id]).toEqual({ + address: { host: '4.4.4.4', port: 4444 }, + lastUpdated: expect.any(Date), + }); + expect(bucket[newNode2Id]).toEqual({ + address: { host: '5.5.5.5', port: 5555 }, + lastUpdated: expect.any(Date), + }); + expect(bucket[newNode3Id]).toEqual({ + address: { host: '6.6.6.6', port: 6666 }, + lastUpdated: expect.any(Date), + }); + }); + test('adds a single node into different buckets', async () => { + // New node for bucket 3 + const newNode1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 3); + const newNode1Address = { host: '1.1.1.1', port: 1111 } as NodeAddress; + await nodeGraph.setNode(newNode1Id, newNode1Address); + // New node for bucket 255 (the highest possible bucket) + const newNode2Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 255); + const newNode2Address = { host: '2.2.2.2', port: 2222 } as NodeAddress; + await nodeGraph.setNode(newNode2Id, newNode2Address); + + const bucket3 = await nodeGraph.getBucket(3); + const bucket351 = await nodeGraph.getBucket(255); + if (bucket3 && bucket351) { + expect(bucket3[newNode1Id]).toEqual({ + address: { host: '1.1.1.1', port: 1111 }, + lastUpdated: expect.any(Date), + }); + expect(bucket351[newNode2Id]).toEqual({ + address: { host: '2.2.2.2', port: 2222 }, + lastUpdated: expect.any(Date), + }); + } else { + // Should be unreachable + fail('Bucket undefined'); + } + }); + test('deletes a single node (and removes bucket)', async () => { + // New node for bucket 2 + const newNode1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 2); + const newNode1Address = { host: '4.4.4.4', port: 4444 } as NodeAddress; + await nodeGraph.setNode(newNode1Id, newNode1Address); + + // Check the bucket is there first + const bucket = await nodeGraph.getBucket(2); + if (bucket) { + expect(bucket[newNode1Id]).toEqual({ + address: { host: '4.4.4.4', port: 4444 }, + lastUpdated: expect.any(Date), + }); + } else { + // Should be unreachable + fail('Bucket undefined'); + } + + // Delete the node + await nodeGraph.unsetNode(newNode1Id); + // Check bucket no longer exists + const newBucket = await nodeGraph.getBucket(2); + expect(newBucket).toBeUndefined(); + }); + test('deletes a single node (and retains remainder of bucket)', async () => { + // Add 3 new nodes into bucket 4 + const bucketIndex = 4; + const newNode1Id = nodesTestUtils.generateNodeIdForBucket( + nodeId, + bucketIndex, + 0, + ); + const newNode1Address = { host: '4.4.4.4', port: 4444 } as NodeAddress; + await nodeGraph.setNode(newNode1Id, newNode1Address); + + const newNode2Id = nodesTestUtils.generateNodeIdForBucket( + nodeId, + bucketIndex, + 1, + ); + const newNode2Address = { host: '5.5.5.5', port: 5555 } as NodeAddress; + await nodeGraph.setNode(newNode2Id, newNode2Address); + + const newNode3Id = nodesTestUtils.generateNodeIdForBucket( + nodeId, + bucketIndex, + 2, + ); + const newNode3Address = { host: '6.6.6.6', port: 6666 } as NodeAddress; + await nodeGraph.setNode(newNode3Id, newNode3Address); + // Based on XOR values, all 3 nodes should appear in bucket 4 + const bucket = await nodeGraph.getBucket(bucketIndex); + if (bucket) { + expect(bucket[newNode1Id]).toEqual({ + address: { host: '4.4.4.4', port: 4444 }, + lastUpdated: expect.any(Date), + }); + expect(bucket[newNode2Id]).toEqual({ + address: { host: '5.5.5.5', port: 5555 }, + lastUpdated: expect.any(Date), + }); + expect(bucket[newNode3Id]).toEqual({ + address: { host: '6.6.6.6', port: 6666 }, + lastUpdated: expect.any(Date), + }); + } else { + // Should be unreachable + fail('Bucket undefined'); + } + + // Delete the node + await nodeGraph.unsetNode(newNode1Id); + // Check node no longer exists in the bucket + const newBucket = await nodeGraph.getBucket(bucketIndex); + if (newBucket) { + expect(newBucket[newNode1Id]).toBeUndefined(); + expect(bucket[newNode2Id]).toEqual({ + address: { host: '5.5.5.5', port: 5555 }, + lastUpdated: expect.any(Date), + }); + expect(bucket[newNode3Id]).toEqual({ + address: { host: '6.6.6.6', port: 6666 }, + lastUpdated: expect.any(Date), + }); + } else { + // Should be unreachable + fail('New bucket undefined'); + } + }); + test('enforces k-bucket size, removing least active node when a new node is discovered', async () => { + // Add k nodes to the database (importantly, they all go into the same bucket) + const bucketIndex = 59; + // Keep a record of the first node ID that we added + const firstNodeId = nodesTestUtils.generateNodeIdForBucket( + nodeId, + bucketIndex, + ); + for (let i = 1; i <= nodeGraph.maxNodesPerBucket; i++) { + // Add the current node ID + const nodeAddress = { + host: hostGen(i), + port: i as Port, + }; + await nodeGraph.setNode( + nodesTestUtils.generateNodeIdForBucket(nodeId, bucketIndex, i), + nodeAddress, + ); + // Increment the current node ID + } + // All of these nodes are in bucket 59 + const originalBucket = await nodeGraph.getBucket(bucketIndex); + if (originalBucket) { + expect(Object.keys(originalBucket).length).toBe( + nodeGraph.maxNodesPerBucket, + ); + } else { + // Should be unreachable + fail('Bucket undefined'); + } + + // Attempt to add a new node into this full bucket (increment the last node + // ID that was added) + const newNodeId = nodesTestUtils.generateNodeIdForBucket( + nodeId, + bucketIndex, + nodeGraph.maxNodesPerBucket + 1, + ); + const newNodeAddress = { host: '0.0.0.1' as Host, port: 1234 as Port }; + await nodeGraph.setNode(newNodeId, newNodeAddress); + + const finalBucket = await nodeGraph.getBucket(bucketIndex); + if (finalBucket) { + // We should still have a full bucket (but no more) + expect(Object.keys(finalBucket).length).toEqual( + nodeGraph.maxNodesPerBucket, + ); + // Ensure that this new node is in the bucket + expect(finalBucket[newNodeId]).toEqual({ + address: newNodeAddress, + lastUpdated: expect.any(Date), + }); + // NODEID1 should have been removed from this bucket (as this was the least active) + // The first node added should have been removed from this bucket (as this + // was the least active, purely because it was inserted first) + expect(finalBucket[firstNodeId]).toBeUndefined(); + } else { + // Should be unreachable + fail('Bucket undefined'); + } + }); + test('enforces k-bucket size, retaining all nodes if adding a pre-existing node', async () => { + // Add k nodes to the database (importantly, they all go into the same bucket) + const bucketIndex = 59; + const currNodeId = nodesTestUtils.generateNodeIdForBucket( + nodeId, + bucketIndex, + ); + // Keep a record of the first node ID that we added + // const firstNodeId = currNodeId; + let increment = 1; + for (let i = 1; i <= nodeGraph.maxNodesPerBucket; i++) { + // Add the current node ID + const nodeAddress = { + host: hostGen(i), + port: i as Port, + }; + await nodeGraph.setNode( + nodesTestUtils.generateNodeIdForBucket(nodeId, bucketIndex, increment), + nodeAddress, + ); + // Increment the current node ID - skip for the last one to keep currNodeId + // as the last added node ID + if (i !== nodeGraph.maxNodesPerBucket) { + increment++; + } + } + // All of these nodes are in bucket 59 + const originalBucket = await nodeGraph.getBucket(bucketIndex); + if (originalBucket) { + expect(Object.keys(originalBucket).length).toBe( + nodeGraph.maxNodesPerBucket, + ); + } else { + // Should be unreachable + fail('Bucket undefined'); + } + + // If we tried to re-add the first node, it would simply remove the original + // first node, as this is the "least active" + // We instead want to check that we don't mistakenly delete a node if we're + // updating an existing one + // So, re-add the last node + const newLastAddress: NodeAddress = { + host: '30.30.30.30' as Host, + port: 30 as Port, + }; + await nodeGraph.setNode(currNodeId, newLastAddress); + + const finalBucket = await nodeGraph.getBucket(bucketIndex); + if (finalBucket) { + // We should still have a full bucket + expect(Object.keys(finalBucket).length).toEqual( + nodeGraph.maxNodesPerBucket, + ); + // Ensure that this new node is in the bucket + expect(finalBucket[currNodeId]).toEqual({ + address: newLastAddress, + lastUpdated: expect.any(Date), + }); + } else { + // Should be unreachable + fail('Bucket undefined'); + } + }); + test('retrieves all buckets (in expected lexicographic order)', async () => { + // Bucket 0 is expected to never have any nodes (as nodeId XOR 0 = nodeId) + // Bucket 1 (minimum): + + const node1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 1); + const node1Address = { host: '1.1.1.1', port: 1111 } as NodeAddress; + await nodeGraph.setNode(node1Id, node1Address); + + // Bucket 4 (multiple nodes in 1 bucket): + const node41Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 4); + const node41Address = { host: '41.41.41.41', port: 4141 } as NodeAddress; + await nodeGraph.setNode(node41Id, node41Address); + const node42Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 4, 1); + const node42Address = { host: '42.42.42.42', port: 4242 } as NodeAddress; + await nodeGraph.setNode(node42Id, node42Address); + + // Bucket 10 (lexicographic ordering - should appear after 2): + const node10Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 10); + const node10Address = { host: '10.10.10.10', port: 1010 } as NodeAddress; + await nodeGraph.setNode(node10Id, node10Address); + + // Bucket 255 (maximum): + const node255Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 255); + const node255Address = { + host: '255.255.255.255', + port: 255, + } as NodeAddress; + await nodeGraph.setNode(node255Id, node255Address); + + const buckets = await nodeGraph.getAllBuckets(); + expect(buckets.length).toBe(4); + // Buckets should be returned in lexicographic ordering (using hex keys to + // ensure the bucket indexes are in numberical order) + expect(buckets).toEqual([ + { + [node1Id]: { + address: { host: '1.1.1.1', port: 1111 }, + lastUpdated: expect.any(String), + }, + }, + { + [node41Id]: { + address: { host: '41.41.41.41', port: 4141 }, + lastUpdated: expect.any(String), + }, + [node42Id]: { + address: { host: '42.42.42.42', port: 4242 }, + lastUpdated: expect.any(String), + }, + }, + { + [node10Id]: { + address: { host: '10.10.10.10', port: 1010 }, + lastUpdated: expect.any(String), + }, + }, + { + [node255Id]: { + address: { host: '255.255.255.255', port: 255 }, + lastUpdated: expect.any(String), + }, + }, + ]); + }); + test( + 'refreshes buckets', + async () => { + const initialNodes: Record = {}; + // Generate and add some nodes + for (let i = 1; i < 255; i += 20) { + const newNodeId = nodesTestUtils.generateNodeIdForBucket( + keyManager.getNodeId(), + i, + ); + const nodeAddress = { + host: hostGen(i), + port: i as Port, + }; + await nodeGraph.setNode(newNodeId, nodeAddress); + initialNodes[newNodeId] = { + id: newNodeId, + address: nodeAddress, + distance: nodesUtils.calculateDistance( + keyManager.getNodeId(), + newNodeId, + ), + }; + } + + // Renew the keypair + await keyManager.renewRootKeyPair('newPassword'); + // Reset the test's node ID state + nodeId = keyManager.getNodeId(); + // Refresh the buckets + await nodeGraph.refreshBuckets(); + + // Get all the new buckets, and expect that each node is in the correct bucket + const newBuckets = await nodeGraph.getAllBuckets(); + let nodeCount = 0; + for (const b of newBuckets) { + for (const n of Object.keys(b)) { + const nodeId = IdInternal.fromString(n); + // Check that it was a node in the original DB + expect(initialNodes[nodeId]).toBeDefined(); + // Check it's in the correct bucket + const expectedIndex = nodesUtils.calculateBucketIndex( + keyManager.getNodeId(), + nodeId, + ); + const expectedBucket = await nodeGraph.getBucket(expectedIndex); + expect(expectedBucket).toBeDefined(); + expect(expectedBucket![nodeId]).toBeDefined(); + // Check it has the correct address + expect(b[nodeId].address).toEqual(initialNodes[nodeId].address); + nodeCount++; + } + } + // We had less than k (20) nodes, so we expect that all nodes will be re-added + // If we had more than k nodes, we may lose some of them (because the nodes + // may be re-added to newly full buckets) + expect(Object.keys(initialNodes).length).toEqual(nodeCount); + }, + global.defaultTimeout * 4, + ); + test('updates node', async () => { + // New node added + const node1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 2); + const node1Address = { host: '1.1.1.1', port: 1 } as NodeAddress; + await nodeGraph.setNode(node1Id, node1Address); + + // Check new node is in retrieved bucket from database + const bucket = await nodeGraph.getBucket(2); + const time1 = bucket![node1Id].lastUpdated; + + // Update node and check that time is later + const newNode1Address = { host: '2.2.2.2', port: 2 } as NodeAddress; + await nodeGraph.updateNode(node1Id, newNode1Address); + + const bucket2 = await nodeGraph.getBucket(2); + const time2 = bucket2![node1Id].lastUpdated; + expect(bucket2![node1Id].address).toEqual(newNode1Address); + expect(time1 < time2).toBeTruthy(); + }); +}); diff --git a/tests/nodes/utils.test.ts b/tests/nodes/utils.test.ts index ee1aeadc4..59d565812 100644 --- a/tests/nodes/utils.test.ts +++ b/tests/nodes/utils.test.ts @@ -1,48 +1,69 @@ import type { NodeId } from '@/nodes/types'; +import os from 'os'; +import path from 'path'; +import fs from 'fs'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import lexi from 'lexicographic-integer'; import { IdInternal } from '@matrixai/id'; +import { DB } from '@matrixai/db'; import * as nodesUtils from '@/nodes/utils'; +import * as keysUtils from '@/keys/utils'; +import * as utils from '@/utils'; +import * as testNodesUtils from './utils'; -describe('Nodes utils', () => { - test('basic distance calculation', async () => { - const nodeId1 = IdInternal.create([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, - ]); - const nodeId2 = IdInternal.create([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 23, 0, - 0, 0, 0, 0, 0, 0, 0, 1, - ]); - - const distance = nodesUtils.calculateDistance(nodeId1, nodeId2); - expect(distance).toEqual(316912758671486456376015716356n); +describe('nodes/utils', () => { + const logger = new Logger(`nodes/utils test`, LogLevel.WARN, [ + new StreamHandler(), + ]); + let dataDir: string; + let db: DB; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const dbKey = await keysUtils.generateKey(); + const dbPath = `${dataDir}/db`; + db = await DB.createDB({ + dbPath, + logger, + crypto: { + key: dbKey, + ops: { + encrypt: keysUtils.encryptWithKey, + decrypt: keysUtils.decryptWithKey, + }, + }, + }); }); - test('calculates correct first bucket (bucket 0)', async () => { - // "1" XOR "0" = distance of 1 - // Therefore, bucket 0 - const nodeId1 = IdInternal.create([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, - ]); - const nodeId2 = IdInternal.create([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - ]); - const bucketIndex = nodesUtils.calculateBucketIndex(nodeId1, nodeId2); - expect(bucketIndex).toBe(0); + afterEach(async () => { + await db.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); }); - test('calculates correct arbitrary bucket (bucket 63)', async () => { - const nodeId1 = IdInternal.create([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 255, 0, 0, 0, 0, 0, 0, 0, - ]); - const nodeId2 = IdInternal.create([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - ]); - const bucketIndex = nodesUtils.calculateBucketIndex(nodeId1, nodeId2); - expect(bucketIndex).toBe(63); + test('calculating bucket index from the same node ID', () => { + const nodeId1 = IdInternal.create([0]); + const nodeId2 = IdInternal.create([0]); + const distance = nodesUtils.nodeDistance(nodeId1, nodeId2); + expect(distance).toBe(0n); + expect(() => nodesUtils.bucketIndex(nodeId1, nodeId2)).toThrow(RangeError); + }); + test('calculating bucket index 0', () => { + // Distance is calculated based on XOR operation + // 1 ^ 0 == 1 + // Distance of 1 is bucket 0 + const nodeId1 = IdInternal.create([1]); + const nodeId2 = IdInternal.create([0]); + const distance = nodesUtils.nodeDistance(nodeId1, nodeId2); + const bucketIndex = nodesUtils.bucketIndex(nodeId1, nodeId2); + expect(distance).toBe(1n); + expect(bucketIndex).toBe(0); + // Triangle inequality 2^i <= distance < 2^(i + 1) + expect(2 ** bucketIndex <= distance).toBe(true); + expect(distance < 2 ** (bucketIndex + 1)).toBe(true); }); - test('calculates correct last bucket (bucket 255)', async () => { + test('calculating bucket index 255', () => { const nodeId1 = IdInternal.create([ 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -51,7 +72,103 @@ describe('Nodes utils', () => { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]); - const bucketIndex = nodesUtils.calculateBucketIndex(nodeId1, nodeId2); + const distance = nodesUtils.nodeDistance(nodeId1, nodeId2); + const bucketIndex = nodesUtils.bucketIndex(nodeId1, nodeId2); expect(bucketIndex).toBe(255); + // Triangle inequality 2^i <= distance < 2^(i + 1) + expect(2 ** bucketIndex <= distance).toBe(true); + expect(distance < 2 ** (bucketIndex + 1)).toBe(true); + }); + test('calculating bucket index randomly', () => { + for (let i = 0; i < 1000; i++) { + const nodeId1 = testNodesUtils.generateRandomNodeId(); + const nodeId2 = testNodesUtils.generateRandomNodeId(); + if (nodeId1.equals(nodeId2)) { + continue; + } + const distance = nodesUtils.nodeDistance(nodeId1, nodeId2); + const bucketIndex = nodesUtils.bucketIndex(nodeId1, nodeId2); + // Triangle inequality 2^i <= distance < 2^(i + 1) + expect(2 ** bucketIndex <= distance).toBe(true); + expect(distance < 2 ** (bucketIndex + 1)).toBe(true); + } + }); + test('parse NodeGraph buckets db key', async () => { + const bucketsDb = await db.level('buckets'); + const data: Array<{ + bucketIndex: number; + bucketKey: string; + nodeId: NodeId; + key: Buffer; + }> = []; + for (let i = 0; i < 1000; i++) { + const bucketIndex = Math.floor(Math.random() * (255 + 1)); + const bucketKey = nodesUtils.bucketKey(bucketIndex); + const nodeId = testNodesUtils.generateRandomNodeId(); + data.push({ + bucketIndex, + bucketKey, + nodeId, + key: Buffer.concat([Buffer.from(bucketKey), nodeId]), + }); + const bucketDomain = ['buckets', bucketKey]; + await db.put(bucketDomain, nodesUtils.bucketDbKey(nodeId), null); + } + // LevelDB will store keys in lexicographic order + // Use the key property as a concatenated buffer of the bucket key and node ID + data.sort((a, b) => Buffer.compare(a.key, b.key)); + let i = 0; + for await (const key of bucketsDb.createKeyStream()) { + const { bucketIndex, bucketKey, nodeId } = nodesUtils.parseBucketsDbKey( + key as Buffer, + ); + expect(bucketIndex).toBe(data[i].bucketIndex); + expect(bucketKey).toBe(data[i].bucketKey); + expect(nodeId.equals(data[i].nodeId)).toBe(true); + i++; + } + }); + test('parse NodeGraph lastUpdated buckets db key', async () => { + const lastUpdatedDb = await db.level('lastUpdated'); + const data: Array<{ + bucketIndex: number; + bucketKey: string; + lastUpdated: number; + nodeId: NodeId; + key: Buffer; + }> = []; + for (let i = 0; i < 1000; i++) { + const bucketIndex = Math.floor(Math.random() * (255 + 1)); + const bucketKey = lexi.pack(bucketIndex, 'hex'); + const lastUpdated = utils.getUnixtime(); + const nodeId = testNodesUtils.generateRandomNodeId(); + const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( + lastUpdated, + nodeId, + ); + data.push({ + bucketIndex, + bucketKey, + lastUpdated, + nodeId, + key: Buffer.concat([Buffer.from(bucketKey), lastUpdatedKey]), + }); + const lastUpdatedDomain = ['lastUpdated', bucketKey]; + await db.put(lastUpdatedDomain, lastUpdatedKey, null); + } + // LevelDB will store keys in lexicographic order + // Use the key property as a concatenated buffer of + // the bucket key and last updated and node ID + data.sort((a, b) => Buffer.compare(a.key, b.key)); + let i = 0; + for await (const key of lastUpdatedDb.createKeyStream()) { + const { bucketIndex, bucketKey, lastUpdated, nodeId } = + nodesUtils.parseLastUpdatedBucketsDbKey(key as Buffer); + expect(bucketIndex).toBe(data[i].bucketIndex); + expect(bucketKey).toBe(data[i].bucketKey); + expect(lastUpdated).toBe(data[i].lastUpdated); + expect(nodeId.equals(data[i].nodeId)).toBe(true); + i++; + } }); }); diff --git a/tests/nodes/utils.ts b/tests/nodes/utils.ts index fca9ad53b..e6c603e14 100644 --- a/tests/nodes/utils.ts +++ b/tests/nodes/utils.ts @@ -1,9 +1,27 @@ import type { NodeId, NodeAddress } from '@/nodes/types'; - import type PolykeyAgent from '@/PolykeyAgent'; import { IdInternal } from '@matrixai/id'; +import * as keysUtils from '@/keys/utils'; import { bigInt2Bytes } from '@/utils'; +/** + * Generate random `NodeId` + * If `readable` is `true`, then it will generate a `NodeId` where + * its binary string form will only contain hex characters + * However the `NodeId` will not be uniformly random as it will not cover + * the full space of possible node IDs + * Prefer to keep `readable` `false` if possible to ensure tests are robust + */ +function generateRandomNodeId(readable: boolean = false): NodeId { + if (readable) { + const random = keysUtils.getRandomBytesSync(16).toString('hex'); + return IdInternal.fromString(random); + } else { + const random = keysUtils.getRandomBytesSync(32); + return IdInternal.fromBuffer(random); + } +} + /** * Generate a deterministic NodeId for a specific bucket given an existing NodeId * This requires solving the bucket index (`i`) and distance equation: @@ -61,4 +79,4 @@ async function nodesConnect(localNode: PolykeyAgent, remoteNode: PolykeyAgent) { } as NodeAddress); } -export { generateNodeIdForBucket, nodesConnect }; +export { generateRandomNodeId, generateNodeIdForBucket, nodesConnect }; diff --git a/tests/notifications/utils.test.ts b/tests/notifications/utils.test.ts index 5a3b8a617..fa6373e38 100644 --- a/tests/notifications/utils.test.ts +++ b/tests/notifications/utils.test.ts @@ -2,16 +2,15 @@ import type { Notification, NotificationData } from '@/notifications/types'; import type { VaultActions, VaultName } from '@/vaults/types'; import { createPublicKey } from 'crypto'; import { EmbeddedJWK, jwtVerify, exportJWK } from 'jose'; - import * as keysUtils from '@/keys/utils'; import * as notificationsUtils from '@/notifications/utils'; import * as notificationsErrors from '@/notifications/errors'; import * as vaultsUtils from '@/vaults/utils'; import * as nodesUtils from '@/nodes/utils'; -import * as testUtils from '../utils'; +import * as testNodesUtils from '../nodes/utils'; describe('Notifications utils', () => { - const nodeId = testUtils.generateRandomNodeId(); + const nodeId = testNodesUtils.generateRandomNodeId(); const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); const vaultId = vaultsUtils.generateVaultId(); const vaultIdEncoded = vaultsUtils.encodeVaultId(vaultId); @@ -206,7 +205,7 @@ describe('Notifications utils', () => { }); test('validates correct notifications', async () => { - const nodeIdOther = testUtils.generateRandomNodeId(); + const nodeIdOther = testNodesUtils.generateRandomNodeId(); const nodeIdOtherEncoded = nodesUtils.encodeNodeId(nodeIdOther); const generalNotification: Notification = { data: { diff --git a/tests/sigchain/Sigchain.test.ts b/tests/sigchain/Sigchain.test.ts index e53a4c67f..e35a3c20a 100644 --- a/tests/sigchain/Sigchain.test.ts +++ b/tests/sigchain/Sigchain.test.ts @@ -13,6 +13,7 @@ import * as sigchainErrors from '@/sigchain/errors'; import * as nodesUtils from '@/nodes/utils'; import * as keysUtils from '@/keys/utils'; import * as testUtils from '../utils'; +import * as testNodesUtils from '../nodes/utils'; describe('Sigchain', () => { const logger = new Logger('Sigchain Test', LogLevel.WARN, [ @@ -20,25 +21,25 @@ describe('Sigchain', () => { ]); const password = 'password'; const srcNodeIdEncoded = nodesUtils.encodeNodeId( - testUtils.generateRandomNodeId(), + testNodesUtils.generateRandomNodeId(), ); const nodeId2Encoded = nodesUtils.encodeNodeId( - testUtils.generateRandomNodeId(), + testNodesUtils.generateRandomNodeId(), ); const nodeId3Encoded = nodesUtils.encodeNodeId( - testUtils.generateRandomNodeId(), + testNodesUtils.generateRandomNodeId(), ); const nodeIdAEncoded = nodesUtils.encodeNodeId( - testUtils.generateRandomNodeId(), + testNodesUtils.generateRandomNodeId(), ); const nodeIdBEncoded = nodesUtils.encodeNodeId( - testUtils.generateRandomNodeId(), + testNodesUtils.generateRandomNodeId(), ); const nodeIdCEncoded = nodesUtils.encodeNodeId( - testUtils.generateRandomNodeId(), + testNodesUtils.generateRandomNodeId(), ); const nodeIdDEncoded = nodesUtils.encodeNodeId( - testUtils.generateRandomNodeId(), + testNodesUtils.generateRandomNodeId(), ); let mockedGenerateKeyPair: jest.SpyInstance; @@ -344,7 +345,9 @@ describe('Sigchain', () => { // Add 10 claims for (let i = 1; i <= 5; i++) { - const node2 = nodesUtils.encodeNodeId(testUtils.generateRandomNodeId()); + const node2 = nodesUtils.encodeNodeId( + testNodesUtils.generateRandomNodeId(), + ); node2s.push(node2); const nodeLink: ClaimData = { type: 'node', @@ -393,7 +396,9 @@ describe('Sigchain', () => { for (let i = 1; i <= 30; i++) { // If even, add a node link if (i % 2 === 0) { - const node2 = nodesUtils.encodeNodeId(testUtils.generateRandomNodeId()); + const node2 = nodesUtils.encodeNodeId( + testNodesUtils.generateRandomNodeId(), + ); nodes[i] = node2; const nodeLink: ClaimData = { type: 'node', diff --git a/tests/status/Status.test.ts b/tests/status/Status.test.ts index 311f89a11..0b0744002 100644 --- a/tests/status/Status.test.ts +++ b/tests/status/Status.test.ts @@ -6,15 +6,15 @@ import path from 'path'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import config from '@/config'; import { Status, errors as statusErrors } from '@/status'; -import * as testUtils from '../utils'; +import * as testNodesUtils from '../nodes/utils'; describe('Status', () => { const logger = new Logger(`${Status.name} Test`, LogLevel.WARN, [ new StreamHandler(), ]); - const nodeId1 = testUtils.generateRandomNodeId(); - const nodeId2 = testUtils.generateRandomNodeId(); - const nodeId3 = testUtils.generateRandomNodeId(); + const nodeId1 = testNodesUtils.generateRandomNodeId(); + const nodeId2 = testNodesUtils.generateRandomNodeId(); + const nodeId3 = testNodesUtils.generateRandomNodeId(); let dataDir: string; beforeEach(async () => { dataDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'status-test-')); diff --git a/tests/utils.ts b/tests/utils.ts index 311743565..ea2d11ff9 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -71,113 +71,115 @@ async function setupGlobalKeypair() { } } -/** - * Setup the global agent - * Use this in beforeAll, and use the closeGlobalAgent in afterAll - * This is expected to be executed by multiple worker processes - * Uses a references directory as a reference count - * Uses fd-lock to serialise access - * This means all test modules using this will be serialised - * Any beforeAll must use globalThis.maxTimeout - * Tips for usage: - * * Do not restart this global agent - * * Ensure client-side side-effects are removed at the end of each test - * * Ensure server-side side-effects are removed at the end of each test - */ +// FIXME: what is going on here? is this getting removed? +// /** +// * Setup the global agent +// * Use this in beforeAll, and use the closeGlobalAgent in afterAll +// * This is expected to be executed by multiple worker processes +// * Uses a references directory as a reference count +// * Uses fd-lock to serialise access +// * This means all test modules using this will be serialised +// * Any beforeAll must use globalThis.maxTimeout +// * Tips for usage: +// * * Do not restart this global agent +// * * Ensure client-side side-effects are removed at the end of each test +// * * Ensure server-side side-effects are removed at the end of each test +// */ async function setupGlobalAgent( logger: Logger = new Logger(setupGlobalAgent.name, LogLevel.WARN, [ new StreamHandler(), ]), -) { - const globalAgentPassword = 'password'; - const globalAgentDir = path.join(globalThis.dataDir, 'agent'); - // The references directory will act like our reference count - await fs.promises.mkdir(path.join(globalAgentDir, 'references'), { - recursive: true, - }); - const pid = process.pid.toString(); - // Plus 1 to the reference count - await fs.promises.writeFile(path.join(globalAgentDir, 'references', pid), ''); - const globalAgentLock = await fs.promises.open( - path.join(globalThis.dataDir, 'agent.lock'), - fs.constants.O_WRONLY | fs.constants.O_CREAT, - ); - while (!lock(globalAgentLock.fd)) { - await sleep(1000); - } - const status = new Status({ - statusPath: path.join(globalAgentDir, config.defaults.statusBase), - statusLockPath: path.join(globalAgentDir, config.defaults.statusLockBase), - fs, - }); - let statusInfo = await status.readStatus(); - if (statusInfo == null || statusInfo.status === 'DEAD') { - await PolykeyAgent.createPolykeyAgent({ - password: globalAgentPassword, - nodePath: globalAgentDir, - networkConfig: { - proxyHost: '127.0.0.1' as Host, - forwardHost: '127.0.0.1' as Host, - agentHost: '127.0.0.1' as Host, - clientHost: '127.0.0.1' as Host, - }, - keysConfig: { - rootKeyPairBits: 2048, - }, - seedNodes: {}, // Explicitly no seed nodes on startup - logger, - }); - statusInfo = await status.readStatus(); - } - return { - globalAgentDir, - globalAgentPassword, - globalAgentStatus: statusInfo as StatusLive, - globalAgentClose: async () => { - // Closing the global agent cannot be done in the globalTeardown - // This is due to a sequence of reasons: - // 1. The global agent is not started as a separate process - // 2. Because we need to be able to mock dependencies - // 3. This means it is part of a jest worker process - // 4. Which will block termination of the jest worker process - // 5. Therefore globalTeardown will never get to execute - // 6. The global agent is not part of globalSetup - // 7. Because not all tests need the global agent - // 8. Therefore setupGlobalAgent is lazy and executed by jest worker processes - try { - await fs.promises.rm(path.join(globalAgentDir, 'references', pid)); - // If the references directory is not empty - // there are other processes still using the global agent - try { - await fs.promises.rmdir(path.join(globalAgentDir, 'references')); - } catch (e) { - if (e.code === 'ENOTEMPTY') { - return; - } - throw e; - } - // Stopping may occur in a different jest worker process - // therefore we cannot rely on pkAgent, but instead use GRPC - const statusInfo = (await status.readStatus()) as StatusLive; - const grpcClient = await GRPCClientClient.createGRPCClientClient({ - nodeId: statusInfo.data.nodeId, - host: statusInfo.data.clientHost, - port: statusInfo.data.clientPort, - tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, - logger, - }); - const emptyMessage = new utilsPB.EmptyMessage(); - const meta = clientUtils.encodeAuthFromPassword(globalAgentPassword); - // This is asynchronous - await grpcClient.agentStop(emptyMessage, meta); - await grpcClient.destroy(); - await status.waitFor('DEAD'); - } finally { - lock.unlock(globalAgentLock.fd); - await globalAgentLock.close(); - } - }, - }; +): Promise { + throw Error('not implemented'); + // Const globalAgentPassword = 'password'; + // const globalAgentDir = path.join(globalThis.dataDir, 'agent'); + // // The references directory will act like our reference count + // await fs.promises.mkdir(path.join(globalAgentDir, 'references'), { + // recursive: true, + // }); + // const pid = process.pid.toString(); + // // Plus 1 to the reference count + // await fs.promises.writeFile(path.join(globalAgentDir, 'references', pid), ''); + // const globalAgentLock = await fs.promises.open( + // path.join(globalThis.dataDir, 'agent.lock'), + // fs.constants.O_WRONLY | fs.constants.O_CREAT, + // ); + // while (!lock(globalAgentLock.fd)) { + // await sleep(1000); + // } + // const status = new Status({ + // statusPath: path.join(globalAgentDir, config.defaults.statusBase), + // statusLockPath: path.join(globalAgentDir, config.defaults.statusLockBase), + // fs, + // }); + // let statusInfo = await status.readStatus(); + // if (statusInfo == null || statusInfo.status === 'DEAD') { + // await PolykeyAgent.createPolykeyAgent({ + // password: globalAgentPassword, + // nodePath: globalAgentDir, + // networkConfig: { + // proxyHost: '127.0.0.1' as Host, + // forwardHost: '127.0.0.1' as Host, + // agentHost: '127.0.0.1' as Host, + // clientHost: '127.0.0.1' as Host, + // }, + // keysConfig: { + // rootKeyPairBits: 2048, + // }, + // seedNodes: {}, // Explicitly no seed nodes on startup + // logger, + // }); + // statusInfo = await status.readStatus(); + // } + // return { + // globalAgentDir, + // globalAgentPassword, + // globalAgentStatus: statusInfo as StatusLive, + // globalAgentClose: async () => { + // // Closing the global agent cannot be done in the globalTeardown + // // This is due to a sequence of reasons: + // // 1. The global agent is not started as a separate process + // // 2. Because we need to be able to mock dependencies + // // 3. This means it is part of a jest worker process + // // 4. Which will block termination of the jest worker process + // // 5. Therefore globalTeardown will never get to execute + // // 6. The global agent is not part of globalSetup + // // 7. Because not all tests need the global agent + // // 8. Therefore setupGlobalAgent is lazy and executed by jest worker processes + // try { + // await fs.promises.rm(path.join(globalAgentDir, 'references', pid)); + // // If the references directory is not empty + // // there are other processes still using the global agent + // try { + // await fs.promises.rmdir(path.join(globalAgentDir, 'references')); + // } catch (e) { + // if (e.code === 'ENOTEMPTY') { + // return; + // } + // throw e; + // } + // // Stopping may occur in a different jest worker process + // // therefore we cannot rely on pkAgent, but instead use GRPC + // const statusInfo = (await status.readStatus()) as StatusLive; + // const grpcClient = await GRPCClientClient.createGRPCClientClient({ + // nodeId: statusInfo.data.nodeId, + // host: statusInfo.data.clientHost, + // port: statusInfo.data.clientPort, + // tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, + // logger, + // }); + // const emptyMessage = new utilsPB.EmptyMessage(); + // const meta = clientUtils.encodeAuthFromPassword(globalAgentPassword); + // // This is asynchronous + // await grpcClient.agentStop(emptyMessage, meta); + // await grpcClient.destroy(); + // await status.waitFor('DEAD'); + // } finally { + // lock.unlock(globalAgentLock.fd); + // await globalAgentLock.close(); + // } + // }, + // }; } function generateRandomNodeId(): NodeId { diff --git a/tests/vaults/VaultOps.test.ts b/tests/vaults/VaultOps.test.ts index 81e061cd3..c766ddd74 100644 --- a/tests/vaults/VaultOps.test.ts +++ b/tests/vaults/VaultOps.test.ts @@ -14,6 +14,7 @@ import * as vaultOps from '@/vaults/VaultOps'; import * as vaultsUtils from '@/vaults/utils'; import * as keysUtils from '@/keys/utils'; import * as testUtils from '../utils'; +import * as testNodesUtils from '../nodes/utils'; describe('VaultOps', () => { const logger = new Logger('VaultOps', LogLevel.WARN, [new StreamHandler()]); @@ -27,7 +28,7 @@ describe('VaultOps', () => { let vaultsDbPath: LevelPath; const dummyKeyManager = { getNodeId: () => { - return testUtils.generateRandomNodeId(); + return testNodesUtils.generateRandomNodeId(); }, } as KeyManager; From d08bbe92681a1493b0cf10408ca8e898b5a4ced0 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 15 Mar 2022 17:55:20 +1100 Subject: [PATCH 076/137] feat: added `NodeGraph.getClosestNodes()` Implemented `getClosestNodes()` and relevant tests in `NodeGraph.test.ts`. Relates to #212 --- .../service/nodesClosestLocalNodesGet.ts | 21 +- src/nodes/NodeConnectionManager.ts | 57 +-- src/nodes/NodeGraph.ts | 136 ++++++- .../NodeConnectionManager.general.test.ts | 124 ------- tests/nodes/NodeGraph.test.ts | 341 +++++++++++++++++- 5 files changed, 489 insertions(+), 190 deletions(-) diff --git a/src/agent/service/nodesClosestLocalNodesGet.ts b/src/agent/service/nodesClosestLocalNodesGet.ts index 5c2c0e204..844aa0253 100644 --- a/src/agent/service/nodesClosestLocalNodesGet.ts +++ b/src/agent/service/nodesClosestLocalNodesGet.ts @@ -1,6 +1,6 @@ import type * as grpc from '@grpc/grpc-js'; +import type { NodeGraph } from '../../nodes'; import type { DB } from '@matrixai/db'; -import type NodeConnectionManager from '../../nodes/NodeConnectionManager'; import type { NodeId } from '../../nodes/types'; import type Logger from '@matrixai/logger'; import * as grpcUtils from '../../grpc/utils'; @@ -16,11 +16,11 @@ import * as agentUtils from '../utils'; * to some provided node ID. */ function nodesClosestLocalNodesGet({ - nodeConnectionManager, + nodeGraph, db, logger, }: { - nodeConnectionManager: NodeConnectionManager; + nodeGraph: NodeGraph; db: DB; logger: Logger; }) { @@ -47,21 +47,16 @@ function nodesClosestLocalNodesGet({ ); // Get all local nodes that are closest to the target node from the request const closestNodes = await db.withTransactionF( - async (tran) => - await nodeConnectionManager.getClosestLocalNodes( - nodeId, - undefined, - tran, - ), + async (tran) => await nodeGraph.getClosestNodes(nodeId, tran), ); - for (const node of closestNodes) { + for (const [nodeId, nodeData] of closestNodes) { const addressMessage = new nodesPB.Address(); - addressMessage.setHost(node.address.host); - addressMessage.setPort(node.address.port); + addressMessage.setHost(nodeData.address.host); + addressMessage.setPort(nodeData.address.port); // Add the node to the response's map (mapping of node ID -> node address) response .getNodeTableMap() - .set(nodesUtils.encodeNodeId(node.id), addressMessage); + .set(nodesUtils.encodeNodeId(nodeId), addressMessage); } callback(null, response); return; diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 5c1b34cb7..fc5c99ff8 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -383,49 +383,7 @@ class NodeConnectionManager { return address; } - /** - * Finds the set of nodes (of size k) known by the current node (i.e. in its - * bucket's database) that have the smallest distance to the target node (i.e. - * are closest to the target node). - * i.e. FIND_NODE RPC from Kademlia spec - * - * Used by the RPC service. - * - * @param targetNodeId the node ID to find other nodes closest to it - * @param numClosest the number of the closest nodes to return (by default, returns - * according to the maximum number of nodes per bucket) - * @param tran - * @returns a mapping containing exactly k nodeIds -> nodeAddresses (unless the - * current node has less than k nodes in all of its buckets, in which case it - * returns all nodes it has knowledge of) - */ - @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) - public async getClosestLocalNodes( - targetNodeId: NodeId, - numClosest: number = this.nodeGraph.maxNodesPerBucket, - tran?: DBTransaction, - ): Promise> { - // Retrieve all nodes from buckets in database - const buckets = await this.nodeGraph.getAllBuckets(tran); - // Iterate over all the nodes in each bucket - const distanceToNodes: Array = []; - buckets.forEach(function (bucket) { - for (const nodeIdString of Object.keys(bucket)) { - // Compute the distance from the node, and add it to the array - const nodeId = IdInternal.fromString(nodeIdString); - distanceToNodes.push({ - id: nodeId, - address: bucket[nodeId].address, - distance: nodesUtils.calculateDistance(nodeId, targetNodeId), - }); - } - }); - // Sort the array (based on the distance at index 1) - distanceToNodes.sort(nodesUtils.sortByDistance); - // Return the closest k nodes (i.e. the first k), or all nodes if < k in array - return distanceToNodes.slice(0, numClosest); - } - + // FIXME: getClosestNodes was moved to NodeGraph? that needs to be updated. /** * Attempts to locate a target node in the network (using Kademlia). * Adds all discovered, active nodes to the current node's database (up to k @@ -447,7 +405,7 @@ class NodeConnectionManager { // Let foundTarget: boolean = false; let foundAddress: NodeAddress | undefined = undefined; // Get the closest alpha nodes to the target node (set as shortlist) - const shortlist: Array = await this.getClosestLocalNodes( + const shortlist = await this.nodeGraph.getClosestNodes( targetNodeId, this.initialClosestNodes, ); @@ -470,8 +428,9 @@ class NodeConnectionManager { if (nextNode == null) { break; } + const [nextNodeId, nextNodeAddress] = nextNode; // Skip if the node has already been contacted - if (contacted[nextNode.id]) { + if (contacted[nextNodeId]) { continue; } // Connect to the node (check if pre-existing connection exists, otherwise @@ -479,16 +438,16 @@ class NodeConnectionManager { try { // Add the node to the database so that we can find its address in // call to getConnectionToNode - await this.nodeGraph.setNode(nextNode.id, nextNode.address); - await this.getConnection(nextNode.id); + await this.nodeGraph.setNode(nextNodeId, nextNodeAddress.address); + await this.getConnection(nextNodeId); } catch (e) { // If we can't connect to the node, then skip it continue; } - contacted[nextNode.id] = true; + contacted[nextNodeId] = true; // Ask the node to get their own closest nodes to the target const foundClosest = await this.getRemoteNodeClosestNodes( - nextNode.id, + nextNodeId, targetNodeId, ); // Check to see if any of these are the target node. At the same time, add diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index 9fa404896..34fa5c56a 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -105,7 +105,7 @@ class NodeGraph { // Bucket metadata sublevel: `!meta!! -> value` this.nodeGraphMetaDbPath = [...this.nodeGraphDbPath, 'meta' + space]; // Bucket sublevel: `!buckets!! -> NodeData` - // The BucketIndex can range from 0 to NodeId bitsize minus 1 + // The BucketIndex can range from 0 to NodeId bit-size minus 1 // So 256 bits means 256 buckets of 0 to 255 this.nodeGraphBucketsDbPath = [...this.nodeGraphDbPath, 'buckets' + space]; // Last updated sublevel: `!lastUpdated!!- -> NodeId` @@ -166,7 +166,7 @@ class NodeGraph { } /** - * Get all nodes + * Get all nodes. * Nodes are always sorted by `NodeBucketIndex` first * Then secondly by the node IDs * The `order` parameter applies to both, for example possible sorts: @@ -340,7 +340,7 @@ class NodeGraph { } /** - * Gets all buckets + * Gets all buckets. * Buckets are always sorted by `NodeBucketIndex` first * Then secondly by the `sort` parameter * The `order` parameter applies to both, for example possible sorts: @@ -582,6 +582,136 @@ class NodeGraph { return value; } + /** + * Finds the set of nodes (of size k) known by the current node (i.e. in its + * buckets' database) that have the smallest distance to the target node (i.e. + * are closest to the target node). + * i.e. FIND_NODE RPC from Kademlia spec + * + * Used by the RPC service. + * + * @param nodeId the node ID to find other nodes closest to it + * @param limit the number of the closest nodes to return (by default, returns + * according to the maximum number of nodes per bucket) + * @param tran + * @returns a mapping containing exactly k nodeIds -> nodeAddresses (unless the + * current node has less than k nodes in all of its buckets, in which case it + * returns all nodes it has knowledge of) + */ + @ready(new nodesErrors.ErrorNodeGraphNotRunning()) + public async getClosestNodes( + nodeId: NodeId, + limit: number = this.nodeBucketLimit, + tran: DBTransaction, + ): Promise { + // Buckets map to the target node in the following way; + // 1. 0, 1, ..., T-1 -> T + // 2. T -> 0, 1, ..., T-1 + // 3. T+1, T+2, ..., 255 are unchanged + // We need to obtain nodes in the following bucket order + // 1. T + // 2. iterate over 0 ---> T-1 + // 3. iterate over T+1 ---> K + // Need to work out the relevant bucket to start from + const startingBucket = nodesUtils.bucketIndex( + this.keyManager.getNodeId(), + nodeId, + ); + // Getting the whole target's bucket first + const nodeIds: NodeBucket = await this.getBucket( + startingBucket, + undefined, + undefined, + tran, + ); + // We need to iterate over the key stream + // When streaming we want all nodes in the starting bucket + // The keys takes the form `!(lexpack bucketId)!(nodeId)` + // We can just use `!(lexpack bucketId)` to start from + // Less than `!(bucketId 101)!` gets us buckets 100 and lower + // greater than `!(bucketId 99)!` gets up buckets 100 and greater + const prefix = Buffer.from([33]); // Code for `!` prefix + if (nodeIds.length < limit) { + // Just before target bucket + const bucketId = Buffer.from(nodesUtils.bucketKey(startingBucket)); + const endKeyLower = Buffer.concat([prefix, bucketId, prefix]); + const remainingLimit = limit - nodeIds.length; + // Iterate over lower buckets + tran.iterator( + { + lt: endKeyLower, + limit: remainingLimit, + valueAsBuffer: false, + }, + this.nodeGraphBucketsDbPath, + ); + for await (const [key, nodeData] of tran.iterator( + { + lt: endKeyLower, + limit: remainingLimit, + valueAsBuffer: false, + }, + this.nodeGraphBucketsDbPath, + )) { + const info = nodesUtils.parseBucketsDbKey(key as unknown as Buffer); + nodeIds.push([info.nodeId, nodeData]); + } + } + if (nodeIds.length < limit) { + // Just after target bucket + const bucketId = Buffer.from(nodesUtils.bucketKey(startingBucket + 1)); + const startKeyUpper = Buffer.concat([prefix, bucketId, prefix]); + const remainingLimit = limit - nodeIds.length; + // Iterate over ids further away + tran.iterator( + { + gt: startKeyUpper, + limit: remainingLimit, + }, + this.nodeGraphBucketsDbPath, + ); + for await (const [key, nodeData] of tran.iterator( + { + gt: startKeyUpper, + limit: remainingLimit, + valueAsBuffer: false, + }, + this.nodeGraphBucketsDbPath, + )) { + const info = nodesUtils.parseBucketsDbKey(key as unknown as Buffer); + nodeIds.push([info.nodeId, nodeData]); + } + } + // If no nodes were found, return nothing + if (nodeIds.length === 0) return []; + // Need to get the whole of the last bucket + const lastBucketIndex = nodesUtils.bucketIndex( + this.keyManager.getNodeId(), + nodeIds[nodeIds.length - 1][0], + ); + const lastBucket = await this.getBucket( + lastBucketIndex, + undefined, + undefined, + tran, + ); + // Pop off elements of the same bucket to avoid duplicates + let element = nodeIds.pop(); + while ( + element != null && + nodesUtils.bucketIndex(this.keyManager.getNodeId(), element[0]) === + lastBucketIndex + ) { + element = nodeIds.pop(); + } + if (element != null) nodeIds.push(element); + // Adding last bucket to the list + nodeIds.push(...lastBucket); + + nodesUtils.bucketSortByDistance(nodeIds, nodeId, 'asc'); + return nodeIds.slice(0, limit); + } + /** * Sets a bucket meta property * This is protected because users cannot directly manipulate bucket meta diff --git a/tests/nodes/NodeConnectionManager.general.test.ts b/tests/nodes/NodeConnectionManager.general.test.ts index d21be106b..24986923b 100644 --- a/tests/nodes/NodeConnectionManager.general.test.ts +++ b/tests/nodes/NodeConnectionManager.general.test.ts @@ -74,7 +74,6 @@ describe(`${NodeConnectionManager.name} general test`, () => { let keyManager: KeyManager; let db: DB; let proxy: Proxy; - let nodeGraph: NodeGraph; let remoteNode1: PolykeyAgent; @@ -336,129 +335,6 @@ describe(`${NodeConnectionManager.name} general test`, () => { }, global.failedConnectionTimeout * 2, ); - test('finds a single closest node', async () => { - // NodeConnectionManager under test - const nodeConnectionManager = new NodeConnectionManager({ - keyManager, - nodeGraph, - proxy, - logger: nodeConnectionManagerLogger, - }); - await nodeConnectionManager.start(); - try { - // New node added - const newNode2Id = nodeId1; - const newNode2Address = { host: '227.1.1.1', port: 4567 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - // Find the closest nodes to some node, NODEID3 - const closest = await nodeConnectionManager.getClosestLocalNodes(nodeId3); - expect(closest).toContainEqual({ - id: newNode2Id, - distance: 121n, - address: { host: '227.1.1.1', port: 4567 }, - }); - } finally { - await nodeConnectionManager.stop(); - } - }); - test('finds 3 closest nodes', async () => { - const nodeConnectionManager = new NodeConnectionManager({ - keyManager, - nodeGraph, - proxy, - logger: nodeConnectionManagerLogger, - }); - await nodeConnectionManager.start(); - try { - // Add 3 nodes - await nodeGraph.setNode(nodeId1, { - host: '2.2.2.2', - port: 2222, - } as NodeAddress); - await nodeGraph.setNode(nodeId2, { - host: '3.3.3.3', - port: 3333, - } as NodeAddress); - await nodeGraph.setNode(nodeId3, { - host: '4.4.4.4', - port: 4444, - } as NodeAddress); - - // Find the closest nodes to some node, NODEID4 - const closest = await nodeConnectionManager.getClosestLocalNodes(nodeId3); - expect(closest.length).toBe(5); - expect(closest).toContainEqual({ - id: nodeId3, - distance: 0n, - address: { host: '4.4.4.4', port: 4444 }, - }); - expect(closest).toContainEqual({ - id: nodeId2, - distance: 116n, - address: { host: '3.3.3.3', port: 3333 }, - }); - expect(closest).toContainEqual({ - id: nodeId1, - distance: 121n, - address: { host: '2.2.2.2', port: 2222 }, - }); - } finally { - await nodeConnectionManager.stop(); - } - }); - test('finds the 20 closest nodes', async () => { - const nodeConnectionManager = new NodeConnectionManager({ - keyManager, - nodeGraph, - proxy, - logger: nodeConnectionManagerLogger, - }); - await nodeConnectionManager.start(); - try { - // Generate the node ID to find the closest nodes to (in bucket 100) - const nodeId = keyManager.getNodeId(); - const nodeIdToFind = testNodesUtils.generateNodeIdForBucket(nodeId, 100); - // Now generate and add 20 nodes that will be close to this node ID - const addedClosestNodes: NodeData[] = []; - for (let i = 1; i < 101; i += 5) { - const closeNodeId = testNodesUtils.generateNodeIdForBucket( - nodeIdToFind, - i, - ); - const nodeAddress = { - host: (i + '.' + i + '.' + i + '.' + i) as Host, - port: i as Port, - }; - await nodeGraph.setNode(closeNodeId, nodeAddress); - addedClosestNodes.push({ - id: closeNodeId, - address: nodeAddress, - distance: nodesUtils.calculateDistance(nodeIdToFind, closeNodeId), - }); - } - // Now create and add 10 more nodes that are far away from this node - for (let i = 1; i <= 10; i++) { - const farNodeId = nodeIdGenerator(i); - const nodeAddress = { - host: `${i}.${i}.${i}.${i}` as Host, - port: i as Port, - }; - await nodeGraph.setNode(farNodeId, nodeAddress); - } - - // Find the closest nodes to the original generated node ID - const closest = await nodeConnectionManager.getClosestLocalNodes( - nodeIdToFind, - ); - // We should always only receive k nodes - expect(closest.length).toBe(nodeGraph.maxNodesPerBucket); - // Retrieved closest nodes should be exactly the same as the ones we added - expect(closest).toEqual(addedClosestNodes); - } finally { - await nodeConnectionManager.stop(); - } - }); test('receives 20 closest local nodes from connected target', async () => { let serverPKAgent: PolykeyAgent | undefined; let nodeConnectionManager: NodeConnectionManager | undefined; diff --git a/tests/nodes/NodeGraph.test.ts b/tests/nodes/NodeGraph.test.ts index 6ea350cad..abf5534cd 100644 --- a/tests/nodes/NodeGraph.test.ts +++ b/tests/nodes/NodeGraph.test.ts @@ -172,7 +172,7 @@ describe(`${NodeGraph.name} test`, () => { (nodeId) => !nodeId.equals(keyManager.getNodeId()), ); let bucketIndexes: Array; - let nodes: Array<[NodeId, NodeData]>; + let nodes: NodeBucket; nodes = await utils.asyncIterableArray(nodeGraph.getNodes()); expect(nodes).toHaveLength(0); for (const nodeId of nodeIds) { @@ -715,4 +715,343 @@ describe(`${NodeGraph.name} test`, () => { expect(buckets2).not.toStrictEqual(buckets1); await nodeGraph.stop(); }); + test('get closest nodes, 40 nodes lower than target, take 20', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + const baseNodeId = keyManager.getNodeId(); + const nodeIds: NodeBucket = []; + // Add 1 node to each bucket + for (let i = 0; i < 40; i++) { + const nodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 50 + i, + i, + ); + nodeIds.push([nodeId, {} as NodeData]); + await nodeGraph.setNode(nodeId, { + host: '127.0.0.1', + port: utils.getRandomInt(0, 2 ** 16), + } as NodeAddress); + } + const targetNodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 100, + 2, + ); + const result = await nodeGraph.getClosestNodes(targetNodeId, 20); + nodesUtils.bucketSortByDistance(nodeIds, targetNodeId); + const a = nodeIds.map((a) => nodesUtils.encodeNodeId(a[0])); + const b = result.map((a) => nodesUtils.encodeNodeId(a[0])); + // Are the closest nodes out of all of the nodes + expect(a.slice(0, b.length)).toEqual(b); + + // Check that the list is strictly ascending + const closestNodeDistances = result.map(([nodeId]) => + nodesUtils.nodeDistance(targetNodeId, nodeId), + ); + expect( + closestNodeDistances.slice(1).every((distance, i) => { + return closestNodeDistances[i] < distance; + }), + ).toBe(true); + await nodeGraph.stop(); + }); + test('get closest nodes, 15 nodes lower than target, take 20', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + const baseNodeId = keyManager.getNodeId(); + const nodeIds: NodeBucket = []; + // Add 1 node to each bucket + for (let i = 0; i < 15; i++) { + const nodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 50 + i, + i, + ); + nodeIds.push([nodeId, {} as NodeData]); + await nodeGraph.setNode(nodeId, { + host: '127.0.0.1', + port: utils.getRandomInt(0, 2 ** 16), + } as NodeAddress); + } + const targetNodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 100, + 2, + ); + const result = await nodeGraph.getClosestNodes(targetNodeId); + nodesUtils.bucketSortByDistance(nodeIds, targetNodeId); + const a = nodeIds.map((a) => nodesUtils.encodeNodeId(a[0])); + const b = result.map((a) => nodesUtils.encodeNodeId(a[0])); + // Are the closest nodes out of all of the nodes + expect(a.slice(0, b.length)).toEqual(b); + + // Check that the list is strictly ascending + const closestNodeDistances = result.map(([nodeId]) => + nodesUtils.nodeDistance(targetNodeId, nodeId), + ); + expect( + closestNodeDistances.slice(1).every((distance, i) => { + return closestNodeDistances[i] < distance; + }), + ).toBe(true); + await nodeGraph.stop(); + }); + test('get closest nodes, 10 nodes lower than target, 30 nodes above, take 20', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + const baseNodeId = keyManager.getNodeId(); + const nodeIds: NodeBucket = []; + // Add 1 node to each bucket + for (let i = 0; i < 40; i++) { + const nodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 90 + i, + i, + ); + nodeIds.push([nodeId, {} as NodeData]); + await nodeGraph.setNode(nodeId, { + host: '127.0.0.1', + port: utils.getRandomInt(0, 2 ** 16), + } as NodeAddress); + } + const targetNodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 100, + 2, + ); + const result = await nodeGraph.getClosestNodes(targetNodeId); + nodesUtils.bucketSortByDistance(nodeIds, targetNodeId); + const a = nodeIds.map((a) => nodesUtils.encodeNodeId(a[0])); + const b = result.map((a) => nodesUtils.encodeNodeId(a[0])); + // Are the closest nodes out of all of the nodes + expect(a.slice(0, b.length)).toEqual(b); + + // Check that the list is strictly ascending + const closestNodeDistances = result.map(([nodeId]) => + nodesUtils.nodeDistance(targetNodeId, nodeId), + ); + expect( + closestNodeDistances.slice(1).every((distance, i) => { + return closestNodeDistances[i] < distance; + }), + ).toBe(true); + await nodeGraph.stop(); + }); + test('get closest nodes, 10 nodes lower than target, 30 nodes above, take 5', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + const baseNodeId = keyManager.getNodeId(); + const nodeIds: NodeBucket = []; + // Add 1 node to each bucket + for (let i = 0; i < 40; i++) { + const nodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 90 + i, + i, + ); + nodeIds.push([nodeId, {} as NodeData]); + await nodeGraph.setNode(nodeId, { + host: '127.0.0.1', + port: utils.getRandomInt(0, 2 ** 16), + } as NodeAddress); + } + const targetNodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 100, + 2, + ); + const result = await nodeGraph.getClosestNodes(targetNodeId, 5); + nodesUtils.bucketSortByDistance(nodeIds, targetNodeId); + const a = nodeIds.map((a) => nodesUtils.encodeNodeId(a[0])); + const b = result.map((a) => nodesUtils.encodeNodeId(a[0])); + // Are the closest nodes out of all of the nodes + expect(a.slice(0, b.length)).toEqual(b); + + // Check that the list is strictly ascending + const closestNodeDistances = result.map(([nodeId]) => + nodesUtils.nodeDistance(targetNodeId, nodeId), + ); + expect( + closestNodeDistances.slice(1).every((distance, i) => { + return closestNodeDistances[i] < distance; + }), + ).toBe(true); + await nodeGraph.stop(); + }); + test('get closest nodes, 5 nodes lower than target, 10 nodes above, take 20', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + const baseNodeId = keyManager.getNodeId(); + const nodeIds: NodeBucket = []; + // Add 1 node to each bucket + for (let i = 0; i < 15; i++) { + const nodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 95 + i, + i, + ); + nodeIds.push([nodeId, {} as NodeData]); + await nodeGraph.setNode(nodeId, { + host: '127.0.0.1', + port: utils.getRandomInt(0, 2 ** 16), + } as NodeAddress); + } + const targetNodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 100, + 2, + ); + const result = await nodeGraph.getClosestNodes(targetNodeId); + nodesUtils.bucketSortByDistance(nodeIds, targetNodeId); + const a = nodeIds.map((a) => nodesUtils.encodeNodeId(a[0])); + const b = result.map((a) => nodesUtils.encodeNodeId(a[0])); + // Are the closest nodes out of all of the nodes + expect(a.slice(0, b.length)).toEqual(b); + + // Check that the list is strictly ascending + const closestNodeDistances = result.map(([nodeId]) => + nodesUtils.nodeDistance(targetNodeId, nodeId), + ); + expect( + closestNodeDistances.slice(1).every((distance, i) => { + return closestNodeDistances[i] < distance; + }), + ).toBe(true); + await nodeGraph.stop(); + }); + test('get closest nodes, 40 nodes above target, take 20', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + const baseNodeId = keyManager.getNodeId(); + const nodeIds: NodeBucket = []; + // Add 1 node to each bucket + for (let i = 0; i < 40; i++) { + const nodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 101 + i, + i, + ); + nodeIds.push([nodeId, {} as NodeData]); + await nodeGraph.setNode(nodeId, { + host: '127.0.0.1', + port: utils.getRandomInt(0, 2 ** 16), + } as NodeAddress); + } + const targetNodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 100, + 2, + ); + const result = await nodeGraph.getClosestNodes(targetNodeId); + nodesUtils.bucketSortByDistance(nodeIds, targetNodeId); + const a = nodeIds.map((a) => nodesUtils.encodeNodeId(a[0])); + const b = result.map((a) => nodesUtils.encodeNodeId(a[0])); + // Are the closest nodes out of all of the nodes + expect(a.slice(0, b.length)).toEqual(b); + + // Check that the list is strictly ascending + const closestNodeDistances = result.map(([nodeId]) => + nodesUtils.nodeDistance(targetNodeId, nodeId), + ); + expect( + closestNodeDistances.slice(1).every((distance, i) => { + return closestNodeDistances[i] < distance; + }), + ).toBe(true); + await nodeGraph.stop(); + }); + test('get closest nodes, 15 nodes above target, take 20', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + const baseNodeId = keyManager.getNodeId(); + const nodeIds: NodeBucket = []; + // Add 1 node to each bucket + for (let i = 0; i < 15; i++) { + const nodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 101 + i, + i, + ); + nodeIds.push([nodeId, {} as NodeData]); + await nodeGraph.setNode(nodeId, { + host: '127.0.0.1', + port: utils.getRandomInt(0, 2 ** 16), + } as NodeAddress); + } + const targetNodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 100, + 2, + ); + const result = await nodeGraph.getClosestNodes(targetNodeId); + nodesUtils.bucketSortByDistance(nodeIds, targetNodeId); + const a = nodeIds.map((a) => nodesUtils.encodeNodeId(a[0])); + const b = result.map((a) => nodesUtils.encodeNodeId(a[0])); + // Are the closest nodes out of all of the nodes + expect(a.slice(0, b.length)).toEqual(b); + + // Check that the list is strictly ascending + const closestNodeDistances = result.map(([nodeId]) => + nodesUtils.nodeDistance(targetNodeId, nodeId), + ); + expect( + closestNodeDistances.slice(1).every((distance, i) => { + return closestNodeDistances[i] < distance; + }), + ).toBe(true); + await nodeGraph.stop(); + }); + test('get closest nodes, no nodes, take 20', async () => { + const nodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + const baseNodeId = keyManager.getNodeId(); + const nodeIds: NodeBucket = []; + const targetNodeId = testNodesUtils.generateNodeIdForBucket( + baseNodeId, + 100, + 2, + ); + const result = await nodeGraph.getClosestNodes(targetNodeId); + nodesUtils.bucketSortByDistance(nodeIds, targetNodeId); + const a = nodeIds.map((a) => nodesUtils.encodeNodeId(a[0])); + const b = result.map((a) => nodesUtils.encodeNodeId(a[0])); + // Are the closest nodes out of all of the nodes + expect(a.slice(0, b.length)).toEqual(b); + + // Check that the list is strictly ascending + const closestNodeDistances = result.map(([nodeId]) => + nodesUtils.nodeDistance(targetNodeId, nodeId), + ); + expect( + closestNodeDistances.slice(1).every((distance, i) => { + return closestNodeDistances[i] < distance; + }), + ).toBe(true); + await nodeGraph.stop(); + }); }); From a43851b3687e4fc3331741cde2260dc8ce2118ac Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 17 Mar 2022 17:32:01 +1100 Subject: [PATCH 077/137] fix: `NodeManager.setNode` Properly handles adding new node when bucket is full Logic of adding nodes has been split between `NodeManager` and `NodeGraph`. The `NodeGraph.setNode` just handles adding a node to the bucket where the `NodeManager.setNode` contains the logic of when to add the node Relates #359 --- .../service/nodesClosestLocalNodesGet.ts | 3 +- src/client/GRPCClientClient.ts | 11 +- src/client/service/nodesAdd.ts | 1 + src/nodes/NodeConnectionManager.ts | 10 +- src/nodes/NodeGraph.ts | 153 +++++++++++---- src/nodes/NodeManager.ts | 67 ++++++- src/nodes/utils.ts | 3 - tests/acl/ACL.test.ts | 13 -- tests/nodes/NodeConnection.test.ts | 8 +- tests/nodes/NodeManager.test.ts | 181 ++++++++++++++++++ 10 files changed, 375 insertions(+), 75 deletions(-) diff --git a/src/agent/service/nodesClosestLocalNodesGet.ts b/src/agent/service/nodesClosestLocalNodesGet.ts index 844aa0253..36a172b12 100644 --- a/src/agent/service/nodesClosestLocalNodesGet.ts +++ b/src/agent/service/nodesClosestLocalNodesGet.ts @@ -47,7 +47,8 @@ function nodesClosestLocalNodesGet({ ); // Get all local nodes that are closest to the target node from the request const closestNodes = await db.withTransactionF( - async (tran) => await nodeGraph.getClosestNodes(nodeId, tran), + async (tran) => + await nodeGraph.getClosestNodes(nodeId, undefined, tran), ); for (const [nodeId, nodeData] of closestNodes) { const addressMessage = new nodesPB.Address(); diff --git a/src/client/GRPCClientClient.ts b/src/client/GRPCClientClient.ts index 78b13ec9d..2b1b905db 100644 --- a/src/client/GRPCClientClient.ts +++ b/src/client/GRPCClientClient.ts @@ -3,7 +3,7 @@ import type { ClientReadableStream } from '@grpc/grpc-js/build/src/call'; import type { AsyncGeneratorReadableStreamClient } from '../grpc/types'; import type { Session } from '../sessions'; import type { NodeId } from '../nodes/types'; -import type { Host, Port, TLSConfig, ProxyConfig } from '../network/types'; +import type { Host, Port, ProxyConfig, TLSConfig } from '../network/types'; import type * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb'; import type * as agentPB from '../proto/js/polykey/v1/agent/agent_pb'; import type * as vaultsPB from '../proto/js/polykey/v1/vaults/vaults_pb'; @@ -68,7 +68,7 @@ class GRPCClientClient extends GRPCClient { interceptors, logger, }); - const grpcClientClient = new GRPCClientClient({ + return new GRPCClientClient({ client, nodeId, host, @@ -80,7 +80,6 @@ class GRPCClientClient extends GRPCClient { destroyCallback, logger, }); - return grpcClientClient; } public async destroy() { @@ -905,6 +904,12 @@ class GRPCClientClient extends GRPCClient { public nodesGetAll(...args) { return grpcUtils.promisifyUnaryCall( this.client, + { + nodeId: this.nodeId, + host: this.host, + port: this.port, + command: this.identitiesAuthenticate.name, + }, this.client.nodesGetAll, )(...args); } diff --git a/src/client/service/nodesAdd.ts b/src/client/service/nodesAdd.ts index 079d2eee2..0884a0f0b 100644 --- a/src/client/service/nodesAdd.ts +++ b/src/client/service/nodesAdd.ts @@ -67,6 +67,7 @@ function nodesAdd({ host, port, } as NodeAddress, + undefined, tran, ), ); diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index fc5c99ff8..c20f093f3 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -10,9 +10,7 @@ import type { NodeId, NodeIdString, SeedNodes, - NodeEntry, } from './types'; -import type { DBTransaction } from '@matrixai/db'; import { withF } from '@matrixai/resources'; import Logger from '@matrixai/logger'; import { ready, StartStop } from '@matrixai/async-init/dist/StartStop'; @@ -103,7 +101,7 @@ class NodeConnectionManager { this.logger.info(`Starting ${this.constructor.name}`); for (const nodeIdEncoded in this.seedNodes) { const nodeId = nodesUtils.decodeNodeId(nodeIdEncoded)!; - await this.nodeGraph.setNode(nodeId, this.seedNodes[nodeIdEncoded]); + await this.nodeGraph.setNode(nodeId, this.seedNodes[nodeIdEncoded]); // FIXME: also fine implicit transactions } this.logger.info(`Started ${this.constructor.name}`); } @@ -243,6 +241,7 @@ class NodeConnectionManager { )}`, ); // Creating the connection and set in map + // FIXME: this is fine, just use the implicit tran. fix this when adding optional transactions const targetAddress = await this.findNode(targetNodeId); // If the stored host is not a valid host (IP address), // then we assume it to be a hostname @@ -363,6 +362,7 @@ class NodeConnectionManager { * Retrieves the node address. If an entry doesn't exist in the db, then * proceeds to locate it using Kademlia. * @param targetNodeId Id of the node we are tying to find + * @param tran */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) public async findNode(targetNodeId: NodeId): Promise { @@ -405,6 +405,7 @@ class NodeConnectionManager { // Let foundTarget: boolean = false; let foundAddress: NodeAddress | undefined = undefined; // Get the closest alpha nodes to the target node (set as shortlist) + // FIXME: no tran const shortlist = await this.nodeGraph.getClosestNodes( targetNodeId, this.initialClosestNodes, @@ -438,6 +439,7 @@ class NodeConnectionManager { try { // Add the node to the database so that we can find its address in // call to getConnectionToNode + // FIXME: no tran await this.nodeGraph.setNode(nextNodeId, nextNodeAddress.address); await this.getConnection(nextNodeId); } catch (e) { @@ -458,6 +460,7 @@ class NodeConnectionManager { continue; } if (nodeId.equals(targetNodeId)) { + // FIXME: no tran await this.nodeGraph.setNode(nodeId, nodeData.address); foundAddress = nodeData.address; // We have found the target node, so we can stop trying to look for it @@ -556,6 +559,7 @@ class NodeConnectionManager { ); for (const [nodeId, nodeData] of nodes) { // FIXME: this should be the `nodeManager.setNode` + // FIXME: no tran needed await this.nodeGraph.setNode(nodeId, nodeData.address); } } diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index 34fa5c56a..0bf30f3ae 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -154,8 +154,14 @@ class NodeGraph { @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async getNode( nodeId: NodeId, - tran: DBTransaction, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.getNode(nodeId, tran), + ); + } + const [bucketIndex] = this.bucketIndex(nodeId); const bucketDomain = [ ...this.nodeGraphBucketsDbPath, @@ -176,8 +182,15 @@ class NodeGraph { @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async *getNodes( order: 'asc' | 'desc' = 'asc', - tran: DBTransaction, + tran?: DBTransaction, ): AsyncGenerator<[NodeId, NodeData]> { + if (tran == null) { + const getNodes = (tran) => this.getNodes(order, tran); + return yield* this.db.withTransactionG(async function* (tran) { + return yield* getNodes(tran); + }); + } + for await (const [key, nodeData] of tran.iterator( { reverse: order !== 'asc', @@ -190,12 +203,25 @@ class NodeGraph { } } + /** + * Will add a node to the node graph and increment the bucket count. + * If the node already existed it will be updated. + * @param nodeId NodeId to add to the NodeGraph + * @param nodeAddress Address information to add + * @param tran + */ @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async setNode( nodeId: NodeId, nodeAddress: NodeAddress, - tran: DBTransaction, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.setNode(nodeId, nodeAddress, tran), + ); + } + const [bucketIndex, bucketKey] = this.bucketIndex(nodeId); const lastUpdatedPath = [...this.nodeGraphLastUpdatedDbPath, bucketKey]; const bucketPath = [...this.nodeGraphBucketsDbPath, bucketKey]; @@ -203,57 +229,67 @@ class NodeGraph { ...bucketPath, nodesUtils.bucketDbKey(nodeId), ]); - // If this is a new entry, check the bucket limit - if (nodeData == null) { - const count = await this.getBucketMetaProp(bucketIndex, 'count', tran); - if (count < this.nodeBucketLimit) { - // Increment the bucket count - await this.setBucketMetaProp(bucketIndex, 'count', count + 1, tran); - } else { - // Remove the oldest entry in the bucket - let oldestLastUpdatedKey: Buffer; - let oldestNodeId: NodeId; - for await (const [key] of tran.iterator( - { - limit: 1, - values: false, - }, - this.nodeGraphLastUpdatedDbPath, - )) { - oldestLastUpdatedKey = key as unknown as Buffer; - ({ nodeId: oldestNodeId } = nodesUtils.parseLastUpdatedBucketDbKey( - key as unknown as Buffer, - )); - } - await tran.del([...bucketPath, oldestNodeId!.toBuffer()]); - await tran.del([...lastUpdatedPath, oldestLastUpdatedKey!]); - } - } else { - // This is an existing entry, so the index entry must be reset + if (nodeData != null) { + // If the node already exists we want to remove the old `lastUpdated` const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( nodeData.lastUpdated, nodeId, ); await tran.del([...lastUpdatedPath, lastUpdatedKey]); + } else { + // It didn't exist so we want to increment the bucket count + const count = await this.getBucketMetaProp(bucketIndex, 'count', tran); + await this.setBucketMetaProp(bucketIndex, 'count', count + 1, tran); } const lastUpdated = getUnixtime(); await tran.put([...bucketPath, nodesUtils.bucketDbKey(nodeId)], { address: nodeAddress, lastUpdated, }); - const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( + const newLastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( lastUpdated, nodeId, ); await tran.put( - [...lastUpdatedPath, lastUpdatedKey], + [...lastUpdatedPath, newLastUpdatedKey], nodesUtils.bucketDbKey(nodeId), true, ); } @ready(new nodesErrors.ErrorNodeGraphNotRunning()) - public async unsetNode(nodeId: NodeId, tran: DBTransaction): Promise { + public async getOldestNode( + bucketIndex: number, + tran?: DBTransaction, + ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.getOldestNode(bucketIndex, tran), + ); + } + + const bucketKey = nodesUtils.bucketKey(bucketIndex); + // Remove the oldest entry in the bucket + let oldestNodeId: NodeId | undefined; + for await (const [key] of tran.iterator({ limit: 1 }, [ + ...this.nodeGraphLastUpdatedDbPath, + bucketKey, + ])) { + ({ nodeId: oldestNodeId } = nodesUtils.parseLastUpdatedBucketDbKey( + key as unknown as Buffer, + )); + } + return oldestNodeId; + } + + @ready(new nodesErrors.ErrorNodeGraphNotRunning()) + public async unsetNode(nodeId: NodeId, tran?: DBTransaction): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.unsetNode(nodeId, tran), + ); + } + const [bucketIndex, bucketKey] = this.bucketIndex(nodeId); const bucketPath = [...this.nodeGraphBucketsDbPath, bucketKey]; const lastUpdatedPath = [...this.nodeGraphLastUpdatedDbPath, bucketKey]; @@ -284,8 +320,14 @@ class NodeGraph { bucketIndex: NodeBucketIndex, sort: 'nodeId' | 'distance' | 'lastUpdated' = 'nodeId', order: 'asc' | 'desc' = 'asc', - tran: DBTransaction, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.getBucket(bucketIndex, sort, order, tran), + ); + } + if (bucketIndex < 0 || bucketIndex >= this.nodeIdBits) { throw new nodesErrors.ErrorNodeGraphBucketIndex( `bucketIndex must be between 0 and ${this.nodeIdBits - 1} inclusive`, @@ -355,8 +397,15 @@ class NodeGraph { public async *getBuckets( sort: 'nodeId' | 'distance' | 'lastUpdated' = 'nodeId', order: 'asc' | 'desc' = 'asc', - tran: DBTransaction, + tran?: DBTransaction, ): AsyncGenerator<[NodeBucketIndex, NodeBucket]> { + if (tran == null) { + const getBuckets = (tran) => this.getBuckets(sort, order, tran); + return yield* this.db.withTransactionG(async function* (tran) { + return yield* getBuckets(tran); + }); + } + let bucketIndex: NodeBucketIndex | undefined = undefined; let bucket: NodeBucket = []; if (sort === 'nodeId' || sort === 'distance') { @@ -448,8 +497,14 @@ class NodeGraph { @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async resetBuckets( nodeIdOwn: NodeId, - tran: DBTransaction, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.resetBuckets(nodeIdOwn, tran), + ); + } + // Setup new space const spaceNew = this.space === '0' ? '1' : '0'; const nodeGraphMetaDbPathNew = [...this.nodeGraphDbPath, 'meta' + spaceNew]; @@ -536,8 +591,14 @@ class NodeGraph { @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async getBucketMeta( bucketIndex: NodeBucketIndex, - tran: DBTransaction, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.getBucketMeta(bucketIndex, tran), + ); + } + if (bucketIndex < 0 || bucketIndex >= this.nodeIdBits) { throw new nodesErrors.ErrorNodeGraphBucketIndex( `bucketIndex must be between 0 and ${this.nodeIdBits - 1} inclusive`, @@ -561,8 +622,14 @@ class NodeGraph { public async getBucketMetaProp( bucketIndex: NodeBucketIndex, key: Key, - tran: DBTransaction, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.getBucketMetaProp(bucketIndex, key, tran), + ); + } + if (bucketIndex < 0 || bucketIndex >= this.nodeIdBits) { throw new nodesErrors.ErrorNodeGraphBucketIndex( `bucketIndex must be between 0 and ${this.nodeIdBits - 1} inclusive`, @@ -602,8 +669,14 @@ class NodeGraph { public async getClosestNodes( nodeId: NodeId, limit: number = this.nodeBucketLimit, - tran: DBTransaction, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.getClosestNodes(nodeId, limit, tran), + ); + } + // Buckets map to the target node in the following way; // 1. 0, 1, ..., T-1 -> T // 2. T -> 0, 1, ..., T-1 @@ -736,7 +809,7 @@ class NodeGraph { * The bucket key is the string encoded version of bucket index * that preserves lexicographic order */ - protected bucketIndex(nodeId: NodeId): [NodeBucketIndex, string] { + public bucketIndex(nodeId: NodeId): [NodeBucketIndex, string] { const nodeIdOwn = this.keyManager.getNodeId(); if (nodeId.equals(nodeIdOwn)) { throw new nodesErrors.ErrorNodeGraphSameNodeId(); diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index ac9d3a4a4..d5b905cbc 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -53,6 +53,10 @@ class NodeManager { * Determines whether a node in the Polykey network is online. * @return true if online, false if offline */ + // FIXME: We shouldn't be trying to find the node just to ping it + // since we are usually pinging it during the find procedure anyway. + // I think we should be providing the address of what we're trying to ping, + // possibly make it an optional parameter? public async pingNode(targetNodeId: NodeId): Promise { const targetAddress: NodeAddress = await this.nodeConnectionManager.findNode(targetNodeId); @@ -311,7 +315,7 @@ class NodeManager { */ public async getNodeAddress( nodeId: NodeId, - tran?: DBTransaction, + tran: DBTransaction, ): Promise { return (await this.nodeGraph.getNode(nodeId, tran))?.address; } @@ -324,7 +328,7 @@ class NodeManager { */ public async knowsNode( targetNodeId: NodeId, - tran?: DBTransaction, + tran: DBTransaction, ): Promise { return (await this.nodeGraph.getNode(targetNodeId, tran)) != null; } @@ -334,22 +338,68 @@ class NodeManager { */ public async getBucket( bucketIndex: number, - tran?: DBTransaction, + tran: DBTransaction, ): Promise { - return await this.nodeGraph.getBucket(bucketIndex, tran); + return await this.nodeGraph.getBucket( + bucketIndex, + undefined, + undefined, + tran, + ); } /** - * Sets a node in the NodeGraph + * Adds a node to the node graph. + * Updates the node if the node already exists. + * */ public async setNode( nodeId: NodeId, nodeAddress: NodeAddress, - tran?: DBTransaction, + force = false, + tran: DBTransaction, ): Promise { - return await this.nodeGraph.setNode(nodeId, nodeAddress, tran); + // When adding a node we need to handle 3 cases + // 1. The node already exists. We need to update it's last updated field + // 2. The node doesn't exist and bucket has room. + // We need to add the node to the bucket + // 3. The node doesn't exist and the bucket is full. + // We need to ping the oldest node. If the ping succeeds we need to update + // the lastUpdated of the oldest node and drop the new one. If the ping + // fails we delete the old node and add in the new one. + const nodeData = await this.nodeGraph.getNode(nodeId, tran); + // If this is a new entry, check the bucket limit + const [bucketIndex] = this.nodeGraph.bucketIndex(nodeId); + const count = await this.nodeGraph.getBucketMetaProp( + bucketIndex, + 'count', + tran, + ); + if (nodeData != null || count < this.nodeGraph.nodeBucketLimit) { + // Either already exists or has room in the bucket + // We want to add or update the node + await this.nodeGraph.setNode(nodeId, nodeAddress, tran); + } else { + // We want to add a node but the bucket is full + // We need to ping the oldest node + const oldestNodeId = (await this.nodeGraph.getOldestNode( + bucketIndex, + tran, + ))!; + if ((await this.pingNode(oldestNodeId)) && !force) { + // The node responded, we need to update it's info and drop the new node + const oldestNode = (await this.nodeGraph.getNode(oldestNodeId, tran))!; + await this.nodeGraph.setNode(oldestNodeId, oldestNode.address, tran); + } else { + // The node could not be contacted or force was set, + // we drop it in favor of the new node + await this.nodeGraph.unsetNode(oldestNodeId, tran); + await this.nodeGraph.setNode(nodeId, nodeAddress, tran); + } + } } + // FIXME // /** // * Updates the node in the NodeGraph // */ @@ -364,10 +414,11 @@ class NodeManager { /** * Removes a node from the NodeGraph */ - public async unsetNode(nodeId: NodeId, tran?: DBTransaction): Promise { + public async unsetNode(nodeId: NodeId, tran: DBTransaction): Promise { return await this.nodeGraph.unsetNode(nodeId, tran); } + // FIXME // /** // * Gets all buckets from the NodeGraph // */ diff --git a/src/nodes/utils.ts b/src/nodes/utils.ts index 1db803381..76bb4058a 100644 --- a/src/nodes/utils.ts +++ b/src/nodes/utils.ts @@ -1,12 +1,9 @@ import type { - NodeData, NodeId, NodeIdEncoded, NodeBucket, - NodeIdString, NodeBucketIndex, } from './types'; -import { utils as dbUtils } from '@matrixai/db'; import { IdInternal } from '@matrixai/id'; import lexi from 'lexicographic-integer'; import { bytes2BigInt, bufferSplit } from '../utils'; diff --git a/tests/acl/ACL.test.ts b/tests/acl/ACL.test.ts index cd0658560..ec4020a1b 100644 --- a/tests/acl/ACL.test.ts +++ b/tests/acl/ACL.test.ts @@ -11,7 +11,6 @@ import ACL from '@/acl/ACL'; import * as aclErrors from '@/acl/errors'; import * as keysUtils from '@/keys/utils'; import * as vaultsUtils from '@/vaults/utils'; -import * as testUtils from '../utils'; import * as testNodesUtils from '../nodes/utils'; describe(ACL.name, () => { @@ -109,30 +108,18 @@ describe(ACL.name, () => { await expect(acl.setNodesPerm([], {} as Permission)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); - await expect(acl.setNodesPermOps([], {} as Permission)).rejects.toThrow( - aclErrors.ErrorACLNotRunning, - ); await expect(acl.setNodePerm(nodeIdX, {} as Permission)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); - await expect(acl.setNodePermOps(nodeIdX, {} as Permission)).rejects.toThrow( - aclErrors.ErrorACLNotRunning, - ); await expect(acl.unsetNodePerm(nodeIdX)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); - await expect(acl.unsetNodePermOps(nodeIdX)).rejects.toThrow( - aclErrors.ErrorACLNotRunning, - ); await expect(acl.unsetVaultPerms(1 as VaultId)).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); await expect(acl.joinNodePerm(nodeIdX, [])).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); - await expect(acl.joinNodePermOps(nodeIdX, [])).rejects.toThrow( - aclErrors.ErrorACLNotRunning, - ); await expect(acl.joinVaultPerms(1 as VaultId, [])).rejects.toThrow( aclErrors.ErrorACLNotRunning, ); diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index c22475912..3ce2e7183 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -704,7 +704,7 @@ describe('${NodeConnection.name} test', () => { "should call `killSelf and throw if the server %s's during testUnaryFail", async (option) => { let nodeConnection: - | NodeConnection + | NodeConnection | undefined; let testProxy: Proxy | undefined; let testProcess: child_process.ChildProcessWithoutNullStreams | undefined; @@ -749,7 +749,7 @@ describe('${NodeConnection.name} test', () => { targetHost: testProxy.getProxyHost(), targetPort: testProxy.getProxyPort(), clientFactory: (args) => - testGrpcUtils.GRPCClientTest.createGRPCClientTest(args), + grpcTestUtils.GRPCClientTest.createGRPCClientTest(args), }); const client = nodeConnection.getClient(); @@ -774,7 +774,7 @@ describe('${NodeConnection.name} test', () => { "should call `killSelf and throw if the server %s's during testStreamFail", async (option) => { let nodeConnection: - | NodeConnection + | NodeConnection | undefined; let testProxy: Proxy | undefined; let testProcess: child_process.ChildProcessWithoutNullStreams | undefined; @@ -819,7 +819,7 @@ describe('${NodeConnection.name} test', () => { targetHost: testProxy.getProxyHost(), targetPort: testProxy.getProxyPort(), clientFactory: (args) => - testGrpcUtils.GRPCClientTest.createGRPCClientTest(args), + grpcTestUtils.GRPCClientTest.createGRPCClientTest(args), }); const client = nodeConnection.getClient(); diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index 0ac96ec27..d74df5c6a 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -18,6 +18,7 @@ import Sigchain from '@/sigchain/Sigchain'; import * as claimsUtils from '@/claims/utils'; import { promisify, sleep } from '@/utils'; import * as nodesUtils from '@/nodes/utils'; +import * as nodesTestUtils from './utils'; describe(`${NodeManager.name} test`, () => { const password = 'password'; @@ -423,4 +424,184 @@ describe(`${NodeManager.name} test`, () => { expect(chainData).toContain(nodesUtils.encodeNodeId(yNodeId)); }); }); + test('should add a node when bucket has room', async () => { + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph, + nodeConnectionManager: {} as NodeConnectionManager, + logger, + }); + const localNodeId = keyManager.getNodeId(); + const bucketIndex = 100; + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + ); + await nodeManager.setNode(nodeId, {} as NodeAddress); + + // Checking bucket + const bucket = await nodeManager.getBucket(bucketIndex); + expect(bucket).toHaveLength(1); + }); + test('should update a node if node exists', async () => { + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph, + nodeConnectionManager: {} as NodeConnectionManager, + logger, + }); + const localNodeId = keyManager.getNodeId(); + const bucketIndex = 100; + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + ); + await nodeManager.setNode(nodeId, { + host: '' as Host, + port: 11111 as Port, + }); + + const nodeData = (await nodeGraph.getNode(nodeId))!; + await sleep(1100); + + // Should update the node + await nodeManager.setNode(nodeId, { + host: '' as Host, + port: 22222 as Port, + }); + + const newNodeData = (await nodeGraph.getNode(nodeId))!; + expect(newNodeData.address.port).not.toEqual(nodeData.address.port); + expect(newNodeData.lastUpdated).not.toEqual(nodeData.lastUpdated); + }); + test('should not add node if bucket is full and old node is alive', async () => { + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph, + nodeConnectionManager: {} as NodeConnectionManager, + logger, + }); + const localNodeId = keyManager.getNodeId(); + const bucketIndex = 100; + // Creating 20 nodes in bucket + for (let i = 1; i <= 20; i++) { + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + i, + ); + await nodeManager.setNode(nodeId, { port: i } as NodeAddress); + } + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + ); + // Mocking ping + const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); + nodeManagerPingMock.mockResolvedValue(true); + const oldestNodeId = await nodeGraph.getOldestNode(bucketIndex); + const oldestNode = await nodeGraph.getNode(oldestNodeId!); + // Waiting for a second to tick over + await sleep(1100); + // Adding a new node with bucket full + await nodeManager.setNode(nodeId, { port: 55555 } as NodeAddress); + // Bucket still contains max nodes + const bucket = await nodeManager.getBucket(bucketIndex); + expect(bucket).toHaveLength(nodeGraph.nodeBucketLimit); + // New node was not added + const node = await nodeGraph.getNode(nodeId); + expect(node).toBeUndefined(); + // Oldest node was updated + const oldestNodeNew = await nodeGraph.getNode(oldestNodeId!); + expect(oldestNodeNew!.lastUpdated).not.toEqual(oldestNode!.lastUpdated); + nodeManagerPingMock.mockRestore(); + }); + test('should add node if bucket is full, old node is alive and force is set', async () => { + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph, + nodeConnectionManager: {} as NodeConnectionManager, + logger, + }); + const localNodeId = keyManager.getNodeId(); + const bucketIndex = 100; + // Creating 20 nodes in bucket + for (let i = 1; i <= 20; i++) { + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + i, + ); + await nodeManager.setNode(nodeId, { port: i } as NodeAddress); + } + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + ); + // Mocking ping + const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); + nodeManagerPingMock.mockResolvedValue(true); + const oldestNodeId = await nodeGraph.getOldestNode(bucketIndex); + // Adding a new node with bucket full + await nodeManager.setNode(nodeId, { port: 55555 } as NodeAddress, true); + // Bucket still contains max nodes + const bucket = await nodeManager.getBucket(bucketIndex); + expect(bucket).toHaveLength(nodeGraph.nodeBucketLimit); + // New node was added + const node = await nodeGraph.getNode(nodeId); + expect(node).toBeDefined(); + // Oldest node was removed + const oldestNodeNew = await nodeGraph.getNode(oldestNodeId!); + expect(oldestNodeNew).toBeUndefined(); + nodeManagerPingMock.mockRestore(); + }); + test('should add node if bucket is full and old node is dead', async () => { + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph, + nodeConnectionManager: {} as NodeConnectionManager, + logger, + }); + const localNodeId = keyManager.getNodeId(); + const bucketIndex = 100; + // Creating 20 nodes in bucket + for (let i = 1; i <= 20; i++) { + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + i, + ); + await nodeManager.setNode(nodeId, { port: i } as NodeAddress); + } + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + ); + // Mocking ping + const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); + nodeManagerPingMock.mockResolvedValue(false); + const oldestNodeId = await nodeGraph.getOldestNode(bucketIndex); + // Adding a new node with bucket full + await nodeManager.setNode(nodeId, { port: 55555 } as NodeAddress, true); + // Bucket still contains max nodes + const bucket = await nodeManager.getBucket(bucketIndex); + expect(bucket).toHaveLength(nodeGraph.nodeBucketLimit); + // New node was added + const node = await nodeGraph.getNode(nodeId); + expect(node).toBeDefined(); + // Oldest node was removed + const oldestNodeNew = await nodeGraph.getNode(oldestNodeId!); + expect(oldestNodeNew).toBeUndefined(); + nodeManagerPingMock.mockRestore(); + }); }); From dc4ec33e6afbc24bfb4491ca721ba5aaab1f3376 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 23 Mar 2022 18:43:14 +1100 Subject: [PATCH 078/137] test: fixed `nodeGraph` `get all buckets` test fix into 7cc74d059f94739591307d9543fa73f999d3345f --- tests/nodes/NodeGraph.test.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/nodes/NodeGraph.test.ts b/tests/nodes/NodeGraph.test.ts index abf5534cd..66b958716 100644 --- a/tests/nodes/NodeGraph.test.ts +++ b/tests/nodes/NodeGraph.test.ts @@ -402,7 +402,6 @@ describe(`${NodeGraph.name} test`, () => { expect(bucketIndex > bucketIndex_).toBe(true); bucketIndex_ = bucketIndex; expect(bucket.length > 0).toBe(true); - expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); for (const [nodeId, nodeData] of bucket) { expect(nodeId.byteLength).toBe(32); expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( @@ -432,7 +431,6 @@ describe(`${NodeGraph.name} test`, () => { expect(bucketIndex < bucketIndex_).toBe(true); bucketIndex_ = bucketIndex; expect(bucket.length > 0).toBe(true); - expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); for (const [nodeId, nodeData] of bucket) { expect(nodeId.byteLength).toBe(32); expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( @@ -462,7 +460,6 @@ describe(`${NodeGraph.name} test`, () => { expect(bucketIndex > bucketIndex_).toBe(true); bucketIndex_ = bucketIndex; expect(bucket.length > 0).toBe(true); - expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); for (const [nodeId, nodeData] of bucket) { expect(nodeId.byteLength).toBe(32); expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( @@ -494,7 +491,6 @@ describe(`${NodeGraph.name} test`, () => { expect(bucketIndex < bucketIndex_).toBe(true); bucketIndex_ = bucketIndex; expect(bucket.length > 0).toBe(true); - expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); for (const [nodeId, nodeData] of bucket) { expect(nodeId.byteLength).toBe(32); expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( @@ -525,7 +521,6 @@ describe(`${NodeGraph.name} test`, () => { expect(bucketIndex > bucketIndex_).toBe(true); bucketIndex_ = bucketIndex; expect(bucket.length > 0).toBe(true); - expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); for (const [nodeId, nodeData] of bucket) { expect(nodeId.byteLength).toBe(32); expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( @@ -556,7 +551,6 @@ describe(`${NodeGraph.name} test`, () => { expect(bucketIndex < bucketIndex_).toBe(true); bucketIndex_ = bucketIndex; expect(bucket.length > 0).toBe(true); - expect(bucket.length <= nodeGraph.nodeBucketLimit).toBe(true); for (const [nodeId, nodeData] of bucket) { expect(nodeId.byteLength).toBe(32); expect(nodesUtils.bucketIndex(keyManager.getNodeId(), nodeId)).toBe( From ea32dc76850d99872482d5a3477c517ed91ad9ca Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 24 Mar 2022 13:21:22 +1100 Subject: [PATCH 079/137] feat: added `connectionEstablishedCallback` to `Proxy` Added a callback to the `Proxy` that is called when a `ForwardConnection` or `ReverseConnection` is established and authenticated. It is called with the following connection information; `remoteNodeId`, `remoteHost`, `remotePort` and `type`. They type signifies if it was a forward or reverse connection. Note that this is only triggered by composed connections. Added a test for if the callback was called when a `ReverseConnection` is established. Relates #332 Relates #344 --- src/network/Proxy.ts | 29 ++++++++- src/network/types.ts | 11 ++++ tests/network/Proxy.test.ts | 118 +++++++++++++++++++++++++++++++++++- 3 files changed, 156 insertions(+), 2 deletions(-) diff --git a/src/network/Proxy.ts b/src/network/Proxy.ts index 1a6ff46f1..973c7f525 100644 --- a/src/network/Proxy.ts +++ b/src/network/Proxy.ts @@ -1,5 +1,12 @@ import type { AddressInfo, Socket } from 'net'; -import type { Host, Port, Address, ConnectionInfo, TLSConfig } from './types'; +import type { + Host, + Port, + Address, + ConnectionInfo, + TLSConfig, + ConnectionEstablishedCallback, +} from './types'; import type { ConnectionsForward } from './ConnectionForward'; import type { NodeId } from '../nodes/types'; import type { Timer } from '../types'; @@ -48,6 +55,7 @@ class Proxy { proxy: new Map(), reverse: new Map(), }; + protected connectionEstablishedCallback: ConnectionEstablishedCallback; constructor({ authToken, @@ -56,6 +64,7 @@ class Proxy { connEndTime = 1000, connPunchIntervalTime = 1000, connKeepAliveIntervalTime = 1000, + connectionEstablishedCallback = () => {}, logger, }: { authToken: string; @@ -64,6 +73,7 @@ class Proxy { connEndTime?: number; connPunchIntervalTime?: number; connKeepAliveIntervalTime?: number; + connectionEstablishedCallback?: ConnectionEstablishedCallback; logger?: Logger; }) { this.logger = logger ?? new Logger(Proxy.name); @@ -77,6 +87,7 @@ class Proxy { this.server = http.createServer(); this.server.on('request', this.handleRequest); this.server.on('connect', this.handleConnectForward); + this.connectionEstablishedCallback = connectionEstablishedCallback; this.logger.info(`Created ${Proxy.name}`); } @@ -521,6 +532,14 @@ class Proxy { timer, ); conn.compose(clientSocket); + // With the connection composed without error we can assume that the + // connection was established and verified + await this.connectionEstablishedCallback({ + remoteNodeId: conn.getServerNodeIds()[0], + remoteHost: conn.host, + remotePort: conn.port, + type: 'forward', + }); } protected async establishConnectionForward( @@ -687,6 +706,14 @@ class Proxy { timer, ); await conn.compose(utpConn, timer); + // With the connection composed without error we can assume that the + // connection was established and verified + await this.connectionEstablishedCallback({ + remoteNodeId: conn.getClientNodeIds()[0], + remoteHost: conn.host, + remotePort: conn.port, + type: 'reverse', + }); } protected async establishConnectionReverse( diff --git a/src/network/types.ts b/src/network/types.ts index 40d672a85..a5a62b4c2 100644 --- a/src/network/types.ts +++ b/src/network/types.ts @@ -55,6 +55,15 @@ type ConnectionInfo = { remotePort: Port; }; +type ConnectionData = { + remoteNodeId: NodeId; + remoteHost: Host; + remotePort: Port; + type: 'forward' | 'reverse'; +}; + +type ConnectionEstablishedCallback = (data: ConnectionData) => any; + type PingMessage = { type: 'ping'; }; @@ -73,6 +82,8 @@ export type { TLSConfig, ProxyConfig, ConnectionInfo, + ConnectionData, + ConnectionEstablishedCallback, PingMessage, PongMessage, NetworkMessage, diff --git a/tests/network/Proxy.test.ts b/tests/network/Proxy.test.ts index fc8055ea7..7e8b12d46 100644 --- a/tests/network/Proxy.test.ts +++ b/tests/network/Proxy.test.ts @@ -1,6 +1,6 @@ import type { AddressInfo, Socket } from 'net'; import type { KeyPairPem } from '@/keys/types'; -import type { Host, Port } from '@/network/types'; +import type { ConnectionData, Host, Port } from '@/network/types'; import net from 'net'; import http from 'http'; import tls from 'tls'; @@ -2973,4 +2973,120 @@ describe(Proxy.name, () => { utpSocket.unref(); await serverClose(); }); + test('connectionEstablishedCallback is called when a ReverseConnection is established', async () => { + const clientKeyPair = await keysUtils.generateKeyPair(1024); + const clientKeyPairPem = keysUtils.keyPairToPem(clientKeyPair); + const clientCert = keysUtils.generateCertificate( + clientKeyPair.publicKey, + clientKeyPair.privateKey, + clientKeyPair.privateKey, + 86400, + ); + const clientCertPem = keysUtils.certToPem(clientCert); + const { + serverListen, + serverClose, + serverConnP, + serverConnEndP, + serverConnClosedP, + serverHost, + serverPort, + } = tcpServer(); + await serverListen(0, localHost); + const clientNodeId = keysUtils.certNodeId(clientCert)!; + let callbackData: ConnectionData | undefined; + const proxy = new Proxy({ + logger: logger, + authToken: '', + connectionEstablishedCallback: (data) => { + callbackData = data; + }, + }); + await proxy.start({ + serverHost: serverHost(), + serverPort: serverPort(), + proxyHost: localHost, + tlsConfig: { + keyPrivatePem: keyPairPem.privateKey, + certChainPem: certPem, + }, + }); + + const proxyHost = proxy.getProxyHost(); + const proxyPort = proxy.getProxyPort(); + const { p: clientReadyP, resolveP: resolveClientReadyP } = promise(); + const { p: clientSecureConnectP, resolveP: resolveClientSecureConnectP } = + promise(); + const { p: clientCloseP, resolveP: resolveClientCloseP } = promise(); + const utpSocket = UTP({ allowHalfOpen: true }); + const utpSocketBind = promisify(utpSocket.bind).bind(utpSocket); + const handleMessage = async (data: Buffer) => { + const msg = networkUtils.unserializeNetworkMessage(data); + if (msg.type === 'ping') { + resolveClientReadyP(); + await send(networkUtils.pongBuffer); + } + }; + utpSocket.on('message', handleMessage); + const send = async (data: Buffer) => { + const utpSocketSend = promisify(utpSocket.send).bind(utpSocket); + await utpSocketSend(data, 0, data.byteLength, proxyPort, proxyHost); + }; + await utpSocketBind(0, localHost); + const utpSocketPort = utpSocket.address().port; + await proxy.openConnectionReverse( + localHost, + utpSocketPort as Port, + ); + const utpConn = utpSocket.connect(proxyPort, proxyHost); + const tlsSocket = tls.connect( + { + key: Buffer.from(clientKeyPairPem.privateKey, 'ascii'), + cert: Buffer.from(clientCertPem, 'ascii'), + socket: utpConn, + rejectUnauthorized: false, + }, + () => { + resolveClientSecureConnectP(); + }, + ); + let tlsSocketEnded = false; + tlsSocket.on('end', () => { + tlsSocketEnded = true; + if (utpConn.destroyed) { + tlsSocket.destroy(); + } else { + tlsSocket.end(); + tlsSocket.destroy(); + } + }); + tlsSocket.on('close', () => { + resolveClientCloseP(); + }); + await send(networkUtils.pingBuffer); + expect(proxy.getConnectionReverseCount()).toBe(1); + await clientReadyP; + await clientSecureConnectP; + await serverConnP; + await proxy.closeConnectionReverse( + localHost, + utpSocketPort as Port, + ); + expect(proxy.getConnectionReverseCount()).toBe(0); + await clientCloseP; + await serverConnEndP; + await serverConnClosedP; + expect(tlsSocketEnded).toBe(true); + utpSocket.off('message', handleMessage); + utpSocket.close(); + utpSocket.unref(); + await proxy.stop(); + await serverClose(); + + // Checking callback data + expect(callbackData?.remoteNodeId.equals(clientNodeId)).toBe(true); + expect(callbackData?.remoteHost).toEqual(localHost); + expect(callbackData?.remotePort).toEqual(utpSocketPort); + expect(callbackData?.type).toEqual('reverse'); + }); }); From a36cd3a83dcc11fcea1023907ec9ec1641bd1c7d Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 24 Mar 2022 18:10:28 +1100 Subject: [PATCH 080/137] feat: `Proxy` trigger adding nodes to `Nodegraph` Added an event to the `EventBus` that is triggered by the `Proxy`'s `connectionEstablishedCallback`. this adds the node to the `NodeGraph`. Related #344 --- src/PolykeyAgent.ts | 28 +++++++++++++++++++++- tests/nodes/NodeManager.test.ts | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index 68e3b5571..a3f5241f3 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -1,6 +1,6 @@ import type { FileSystem } from './types'; import type { PolykeyWorkerManagerInterface } from './workers/types'; -import type { Host, Port } from './network/types'; +import type { ConnectionData, Host, Port } from './network/types'; import type { SeedNodes } from './nodes/types'; import type { KeyManagerChangeData } from './keys/types'; import path from 'path'; @@ -8,6 +8,7 @@ import process from 'process'; import Logger from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { CreateDestroyStartStop } from '@matrixai/async-init/dist/CreateDestroyStartStop'; +import * as networkUtils from '@/network/utils'; import KeyManager from './keys/KeyManager'; import Status from './status/Status'; import Schema from './schema/Schema'; @@ -59,8 +60,10 @@ class PolykeyAgent { */ public static readonly eventSymbols = { [KeyManager.name]: Symbol(KeyManager.name), + [Proxy.name]: Symbol(Proxy.name), } as { readonly KeyManager: unique symbol; + readonly Proxy: unique symbol; }; public static async createPolykeyAgent({ @@ -266,6 +269,8 @@ class PolykeyAgent { proxy ?? new Proxy({ ...proxyConfig_, + connectionEstablishedCallback: (data) => + events.emitAsync(PolykeyAgent.eventSymbols.Proxy, data), logger: logger.getChild(Proxy.name), }); nodeGraph = @@ -542,6 +547,27 @@ class PolykeyAgent { this.logger.info(`${KeyManager.name} change propagated`); }, ); + this.events.on( + PolykeyAgent.eventSymbols.Proxy, + async (data: ConnectionData) => { + if (data.type === 'reverse') { + const address = networkUtils.buildAddress( + data.remoteHost, + data.remotePort, + ); + const nodeIdEncoded = nodesUtils.encodeNodeId(data.remoteNodeId); + this.logger.info( + `Reverse connection adding ${nodeIdEncoded}:${address} to ${NodeGraph.name}`, + ); + // Reverse connection was established and authenticated, + // add it to the node graph + await this.nodeManager.setNode(data.remoteNodeId, { + host: data.remoteHost, + port: data.remotePort, + }); + } + }, + ); const networkConfig_ = { ...config.defaults.networkConfig, ...utils.filterEmptyObject(networkConfig), diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index d74df5c6a..8d2c249b8 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -18,6 +18,7 @@ import Sigchain from '@/sigchain/Sigchain'; import * as claimsUtils from '@/claims/utils'; import { promisify, sleep } from '@/utils'; import * as nodesUtils from '@/nodes/utils'; +import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as nodesTestUtils from './utils'; describe(`${NodeManager.name} test`, () => { @@ -604,4 +605,45 @@ describe(`${NodeManager.name} test`, () => { expect(oldestNodeNew).toBeUndefined(); nodeManagerPingMock.mockRestore(); }); + test('should add node when an incoming connection is established', async () => { + let server: PolykeyAgent | undefined; + try { + server = await PolykeyAgent.createPolykeyAgent({ + password: 'password', + nodePath: path.join(dataDir, 'server'), + keysConfig: { + rootKeyPairBits: 2048, + }, + logger: logger, + }); + const serverNodeId = server.keyManager.getNodeId(); + const serverNodeAddress: NodeAddress = { + host: server.proxy.getProxyHost(), + port: server.proxy.getProxyPort(), + }; + await nodeGraph.setNode(serverNodeId, serverNodeAddress); + + const expectedHost = proxy.getProxyHost(); + const expectedPort = proxy.getProxyPort(); + const expectedNodeId = keyManager.getNodeId(); + + const nodeData = await server.nodeGraph.getNode(expectedNodeId); + expect(nodeData).toBeUndefined(); + + // Now we want to connect to the server by making an echo request. + await nodeConnectionManager.withConnF(serverNodeId, async (conn) => { + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello')); + }); + + const nodeData2 = await server.nodeGraph.getNode(expectedNodeId); + expect(nodeData2).toBeDefined(); + expect(nodeData2?.address.host).toEqual(expectedHost); + expect(nodeData2?.address.port).toEqual(expectedPort); + } finally { + // Clean up + await server?.stop(); + await server?.destroy(); + } + }); }); From cb47f8b0571accaccf8659a0055d2d8fc657d7d3 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 25 Mar 2022 18:02:09 +1100 Subject: [PATCH 081/137] feat: added optional timeout timers to `NodeConnectionManager` methods In some cases we want to specify how long we attempt to connect to a node on a per-connection basis. Related #363 --- src/PolykeyClient.ts | 8 +- src/agent/GRPCClientAgent.ts | 7 +- src/client/GRPCClientClient.ts | 7 +- src/grpc/GRPCClient.ts | 17 ++- src/nodes/NodeConnection.ts | 7 +- src/nodes/NodeConnectionManager.ts | 119 ++++++++++++------ src/nodes/NodeManager.ts | 1 + tests/agent/GRPCClientAgent.test.ts | 5 +- tests/agent/utils.ts | 3 +- tests/client/GRPCClientClient.test.ts | 3 +- tests/client/utils.ts | 4 +- tests/grpc/GRPCClient.test.ts | 19 +-- tests/grpc/utils/GRPCClientTest.ts | 7 +- tests/nodes/NodeConnection.test.ts | 15 +-- .../NodeConnectionManager.lifecycle.test.ts | 1 + 15 files changed, 143 insertions(+), 80 deletions(-) diff --git a/src/PolykeyClient.ts b/src/PolykeyClient.ts index b124feefa..bea2b830b 100644 --- a/src/PolykeyClient.ts +++ b/src/PolykeyClient.ts @@ -1,4 +1,4 @@ -import type { FileSystem } from './types'; +import type { FileSystem, Timer } from './types'; import type { NodeId } from './nodes/types'; import type { Host, Port } from './network/types'; @@ -29,7 +29,7 @@ class PolykeyClient { nodePath = config.defaults.nodePath, session, grpcClient, - timeout, + timer, fs = require('fs'), logger = new Logger(this.name), fresh = false, @@ -38,7 +38,7 @@ class PolykeyClient { host: Host; port: Port; nodePath?: string; - timeout?: number; + timer?: Timer; session?: Session; grpcClient?: GRPCClientClient; fs?: FileSystem; @@ -66,7 +66,7 @@ class PolykeyClient { port, tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, session, - timeout, + timer, logger: logger.getChild(GRPCClientClient.name), })); const pkClient = new PolykeyClient({ diff --git a/src/agent/GRPCClientAgent.ts b/src/agent/GRPCClientAgent.ts index bb4593785..db94979db 100644 --- a/src/agent/GRPCClientAgent.ts +++ b/src/agent/GRPCClientAgent.ts @@ -10,6 +10,7 @@ import type * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb'; import type * as vaultsPB from '../proto/js/polykey/v1/vaults/vaults_pb'; import type * as nodesPB from '../proto/js/polykey/v1/nodes/nodes_pb'; import type * as notificationsPB from '../proto/js/polykey/v1/notifications/notifications_pb'; +import type { Timer } from '../types'; import Logger from '@matrixai/logger'; import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; import * as agentErrors from './errors'; @@ -32,7 +33,7 @@ class GRPCClientAgent extends GRPCClient { port, tlsConfig, proxyConfig, - timeout = Infinity, + timer, destroyCallback = async () => {}, logger = new Logger(this.name), }: { @@ -41,7 +42,7 @@ class GRPCClientAgent extends GRPCClient { port: Port; tlsConfig?: Partial; proxyConfig?: ProxyConfig; - timeout?: number; + timer?: Timer; destroyCallback?: () => Promise; logger?: Logger; }): Promise { @@ -53,7 +54,7 @@ class GRPCClientAgent extends GRPCClient { port, tlsConfig, proxyConfig, - timeout, + timer, logger, }); const grpcClientAgent = new GRPCClientAgent({ diff --git a/src/client/GRPCClientClient.ts b/src/client/GRPCClientClient.ts index 2b1b905db..8b9816536 100644 --- a/src/client/GRPCClientClient.ts +++ b/src/client/GRPCClientClient.ts @@ -14,6 +14,7 @@ import type * as identitiesPB from '../proto/js/polykey/v1/identities/identities import type * as keysPB from '../proto/js/polykey/v1/keys/keys_pb'; import type * as permissionsPB from '../proto/js/polykey/v1/permissions/permissions_pb'; import type * as secretsPB from '../proto/js/polykey/v1/secrets/secrets_pb'; +import type { Timer } from '../types'; import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; import Logger from '@matrixai/logger'; import * as clientErrors from './errors'; @@ -38,7 +39,7 @@ class GRPCClientClient extends GRPCClient { tlsConfig, proxyConfig, session, - timeout = Infinity, + timer, destroyCallback = async () => {}, logger = new Logger(this.name), }: { @@ -48,7 +49,7 @@ class GRPCClientClient extends GRPCClient { tlsConfig?: Partial; proxyConfig?: ProxyConfig; session?: Session; - timeout?: number; + timer?: Timer; destroyCallback?: () => Promise; logger?: Logger; }): Promise { @@ -64,7 +65,7 @@ class GRPCClientClient extends GRPCClient { port, tlsConfig, proxyConfig, - timeout, + timer, interceptors, logger, }); diff --git a/src/grpc/GRPCClient.ts b/src/grpc/GRPCClient.ts index 4e88291a1..0434a1753 100644 --- a/src/grpc/GRPCClient.ts +++ b/src/grpc/GRPCClient.ts @@ -9,6 +9,7 @@ import type { import type { NodeId } from '../nodes/types'; import type { Certificate } from '../keys/types'; import type { Host, Port, TLSConfig, ProxyConfig } from '../network/types'; +import type { Timer } from '../types'; import http2 from 'http2'; import Logger from '@matrixai/logger'; import * as grpc from '@grpc/grpc-js'; @@ -44,7 +45,7 @@ abstract class GRPCClient { port, tlsConfig, proxyConfig, - timeout = Infinity, + timer, interceptors = [], logger = new Logger(this.name), }: { @@ -58,7 +59,7 @@ abstract class GRPCClient { port: Port; tlsConfig?: Partial; proxyConfig?: ProxyConfig; - timeout?: number; + timer?: Timer; interceptors?: Array; logger?: Logger; }): Promise<{ @@ -123,9 +124,17 @@ abstract class GRPCClient { } const waitForReady = promisify(client.waitForReady).bind(client); // Add the current unix time because grpc expects the milliseconds since unix epoch - timeout += Date.now(); try { - await waitForReady(timeout); + if (timer != null) { + await Promise.race([timer.timerP, waitForReady(Infinity)]); + // If the timer resolves first we throw a timeout error + if (timer?.timedOut === true) { + throw new grpcErrors.ErrorGRPCClientTimeout(); + } + } else { + // No timer given so we wait forever + await waitForReady(Infinity); + } } catch (e) { // If we fail here then we leak the client object... client.close(); diff --git a/src/nodes/NodeConnection.ts b/src/nodes/NodeConnection.ts index f79272413..f4f4fbfb3 100644 --- a/src/nodes/NodeConnection.ts +++ b/src/nodes/NodeConnection.ts @@ -5,6 +5,7 @@ import type { Certificate, PublicKey, PublicKeyPem } from '../keys/types'; import type Proxy from '../network/Proxy'; import type GRPCClient from '../grpc/GRPCClient'; import type NodeConnectionManager from './NodeConnectionManager'; +import type { Timer } from '../types'; import Logger from '@matrixai/logger'; import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; import * as asyncInit from '@matrixai/async-init'; @@ -38,7 +39,7 @@ class NodeConnection { targetHost, targetPort, targetHostname, - connConnectTime = 20000, + timer, proxy, keyManager, clientFactory, @@ -50,7 +51,7 @@ class NodeConnection { targetHost: Host; targetPort: Port; targetHostname?: Hostname; - connConnectTime?: number; + timer?: Timer; proxy: Proxy; keyManager: KeyManager; clientFactory: (...args) => Promise; @@ -125,7 +126,7 @@ class NodeConnection { await nodeConnection.destroy(); } }, - timeout: connConnectTime, + timer: timer, }), holePunchPromises, ]); diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index c20f093f3..5b5810492 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -26,6 +26,7 @@ import * as networkUtils from '../network/utils'; import * as agentErrors from '../agent/errors'; import * as grpcErrors from '../grpc/errors'; import * as nodesPB from '../proto/js/polykey/v1/nodes/nodes_pb'; +import { timerStart } from '../utils'; type ConnectionAndTimer = { connection: NodeConnection; @@ -123,14 +124,22 @@ class NodeConnectionManager { * itself is such that we can pass targetNodeId as a parameter (as opposed to * an acquire function with no parameters). * @param targetNodeId Id of target node to communicate with + * @param timer Connection timeout timer + * @param address Optional address to connect to * @returns ResourceAcquire Resource API for use in with contexts */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) public async acquireConnection( targetNodeId: NodeId, + timer?: Timer, + address?: NodeAddress, ): Promise>> { return async () => { - const { connection, timer } = await this.getConnection(targetNodeId); + const { connection, timer } = await this.getConnection( + targetNodeId, + address, + timer, + ); // Acquire the read lock and the release function const [release] = await this.connectionLocks.lock([ targetNodeId.toString(), @@ -164,14 +173,16 @@ class NodeConnectionManager { * for use with normal arrow function * @param targetNodeId Id of target node to communicate with * @param f Function to handle communication + * @param timer Connection timeout timer */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) public async withConnF( targetNodeId: NodeId, f: (conn: NodeConnection) => Promise, + timer?: Timer, ): Promise { return await withF( - [await this.acquireConnection(targetNodeId)], + [await this.acquireConnection(targetNodeId, timer, undefined)], async ([conn]) => { this.logger.info( `withConnF calling function with connection to ${nodesUtils.encodeNodeId( @@ -190,6 +201,7 @@ class NodeConnectionManager { * for use with a generator function * @param targetNodeId Id of target node to communicate with * @param g Generator function to handle communication + * @param timer Connection timeout timer */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) public async *withConnG( @@ -197,8 +209,13 @@ class NodeConnectionManager { g: ( conn: NodeConnection, ) => AsyncGenerator, + timer?: Timer, ): AsyncGenerator { - const acquire = await this.acquireConnection(targetNodeId); + const acquire = await this.acquireConnection( + targetNodeId, + timer, + undefined, + ); const [release, conn] = await acquire(); let caughtError; try { @@ -216,10 +233,14 @@ class NodeConnectionManager { * Create a connection to another node (without performing any function). * This is a NOOP if a connection already exists. * @param targetNodeId Id of node we are creating connection to - * @returns ConnectionAndLock that was created or exists in the connection map. + * @param address Optional address to connect to + * @param timer Connection timeout timer + * @returns ConnectionAndLock that was created or exists in the connection map */ protected async getConnection( targetNodeId: NodeId, + address?: NodeAddress, + timer?: Timer, ): Promise { this.logger.info( `Getting connection to ${nodesUtils.encodeNodeId(targetNodeId)}`, @@ -273,7 +294,7 @@ class NodeConnectionManager { keyManager: this.keyManager, nodeConnectionManager: this, destroyCallback, - connConnectTime: this.connConnectTime, + timer: timer ?? timerStart(this.connConnectTime), logger: this.logger.getChild( `${NodeConnection.name} ${targetHost}:${targetAddress.port}`, ), @@ -281,13 +302,13 @@ class NodeConnectionManager { GRPCClientAgent.createGRPCClientAgent(args), }); // Creating TTL timeout - const timer = setTimeout(async () => { + const timeToLiveTimer = setTimeout(async () => { await this.destroyConnection(targetNodeId); }, this.connTimeoutTime); const newConnAndTimer: ConnectionAndTimer = { connection: newConnection, - timer: timer, + timer: timeToLiveTimer, }; this.connections.set(targetNodeIdString, newConnAndTimer); return newConnAndTimer; @@ -396,11 +417,13 @@ class NodeConnectionManager { * port). * @param targetNodeId ID of the node attempting to be found (i.e. attempting * to find its IP address and port) + * @param timer Connection timeout timer * @returns whether the target node was located in the process */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) public async getClosestGlobalNodes( targetNodeId: NodeId, + timer?: Timer, ): Promise { // Let foundTarget: boolean = false; let foundAddress: NodeAddress | undefined = undefined; @@ -441,7 +464,7 @@ class NodeConnectionManager { // call to getConnectionToNode // FIXME: no tran await this.nodeGraph.setNode(nextNodeId, nextNodeAddress.address); - await this.getConnection(nextNodeId); + await this.getConnection(nextNodeId, undefined, timer); } catch (e) { // If we can't connect to the node, then skip it continue; @@ -451,11 +474,12 @@ class NodeConnectionManager { const foundClosest = await this.getRemoteNodeClosestNodes( nextNodeId, targetNodeId, + timer, ); // Check to see if any of these are the target node. At the same time, add // them to the shortlist for (const [nodeId, nodeData] of foundClosest) { - // Ignore any nodes that have been contacted + // Ignore a`ny nodes that have been contacted if (contacted[nodeId]) { continue; } @@ -494,40 +518,46 @@ class NodeConnectionManager { * target node ID. * @param nodeId the node ID to search on * @param targetNodeId the node ID to find other nodes closest to it + * @param timer Connection timeout timer * @returns list of nodes and their IP/port that are closest to the target */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) public async getRemoteNodeClosestNodes( nodeId: NodeId, targetNodeId: NodeId, + timer?: Timer, ): Promise> { // Construct the message const nodeIdMessage = new nodesPB.Node(); nodeIdMessage.setNodeId(nodesUtils.encodeNodeId(targetNodeId)); // Send through client - return this.withConnF(nodeId, async (connection) => { - const client = await connection.getClient(); - const response = await client.nodesClosestLocalNodesGet(nodeIdMessage); - const nodes: Array<[NodeId, NodeData]> = []; - // Loop over each map element (from the returned response) and populate nodes - response.getNodeTableMap().forEach((address, nodeIdString: string) => { - const nodeId = nodesUtils.decodeNodeId(nodeIdString); - // If the nodeId is not valid we don't add it to the list of nodes - if (nodeId != null) { - nodes.push([ - nodeId, - { - address: { - host: address.getHost() as Host | Hostname, - port: address.getPort() as Port, + return this.withConnF( + nodeId, + async (connection) => { + const client = await connection.getClient(); + const response = await client.nodesClosestLocalNodesGet(nodeIdMessage); + const nodes: Array<[NodeId, NodeData]> = []; + // Loop over each map element (from the returned response) and populate nodes + response.getNodeTableMap().forEach((address, nodeIdString: string) => { + const nodeId = nodesUtils.decodeNodeId(nodeIdString); + // If the nodeId is not valid we don't add it to the list of nodes + if (nodeId != null) { + nodes.push([ + nodeId, + { + address: { + host: address.getHost() as Host | Hostname, + port: address.getPort() as Port, + }, + lastUpdated: 0, // FIXME? }, - lastUpdated: 0, // FIXME? - }, - ]); - } - }); - return nodes; - }); + ]); + } + }); + return nodes; + }, + timer, + ); } /** @@ -541,13 +571,14 @@ class NodeConnectionManager { * This has been removed from start() as there's a chicken-egg scenario * where we require the NodeGraph instance to be created in order to get * connections. + * @param timer Connection timeout timer */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) - public async syncNodeGraph() { + public async syncNodeGraph(timer?: Timer) { for (const seedNodeId of this.getSeedNodes()) { // Check if the connection is viable try { - await this.getConnection(seedNodeId); + await this.getConnection(seedNodeId, undefined, timer); } catch (e) { if (e instanceof nodesErrors.ErrorNodeConnectionTimeout) continue; throw e; @@ -556,6 +587,7 @@ class NodeConnectionManager { const nodes = await this.getRemoteNodeClosestNodes( seedNodeId, this.keyManager.getNodeId(), + timer, ); for (const [nodeId, nodeData] of nodes) { // FIXME: this should be the `nodeManager.setNode` @@ -574,6 +606,7 @@ class NodeConnectionManager { * @param targetNodeId node ID of the target node to hole punch * @param proxyAddress string of address in the form `proxyHost:proxyPort` * @param signature signature to verify source node is sender (signature based + * @param timer Connection timeout timer * on proxyAddress as message) */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) @@ -583,16 +616,21 @@ class NodeConnectionManager { targetNodeId: NodeId, proxyAddress: string, signature: Buffer, + timer?: Timer, ): Promise { const relayMsg = new nodesPB.Relay(); relayMsg.setSrcId(nodesUtils.encodeNodeId(sourceNodeId)); relayMsg.setTargetId(nodesUtils.encodeNodeId(targetNodeId)); relayMsg.setProxyAddress(proxyAddress); relayMsg.setSignature(signature.toString()); - await this.withConnF(relayNodeId, async (connection) => { - const client = connection.getClient(); - await client.nodesHolePunchMessageSend(relayMsg); - }); + await this.withConnF( + relayNodeId, + async (connection) => { + const client = connection.getClient(); + await client.nodesHolePunchMessageSend(relayMsg); + }, + timer, + ); } /** @@ -602,15 +640,20 @@ class NodeConnectionManager { * node). * @param message the original relay message (assumed to be created in * nodeConnection.start()) + * @param timer Connection timeout timer */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) - public async relayHolePunchMessage(message: nodesPB.Relay): Promise { + public async relayHolePunchMessage( + message: nodesPB.Relay, + timer?: Timer, + ): Promise { await this.sendHolePunchMessage( validationUtils.parseNodeId(message.getTargetId()), validationUtils.parseNodeId(message.getSrcId()), validationUtils.parseNodeId(message.getTargetId()), message.getProxyAddress(), Buffer.from(message.getSignature()), + timer, ); } diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index d5b905cbc..9ef964b3f 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -7,6 +7,7 @@ import type Sigchain from '../sigchain/Sigchain'; import type { ChainData, ChainDataEncoded } from '../sigchain/types'; import type { NodeId, NodeAddress, NodeBucket } from '../nodes/types'; import type { ClaimEncoded } from '../claims/types'; +import type { Timer } from '../types'; import Logger from '@matrixai/logger'; import * as nodesErrors from './errors'; import * as nodesUtils from './utils'; diff --git a/tests/agent/GRPCClientAgent.test.ts b/tests/agent/GRPCClientAgent.test.ts index 60a84410c..89c9ec9d7 100644 --- a/tests/agent/GRPCClientAgent.test.ts +++ b/tests/agent/GRPCClientAgent.test.ts @@ -21,6 +21,7 @@ import NotificationsManager from '@/notifications/NotificationsManager'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as agentErrors from '@/agent/errors'; import * as keysUtils from '@/keys/utils'; +import { timerStart } from '@/utils'; import * as testAgentUtils from './utils'; describe(GRPCClientAgent.name, () => { @@ -257,7 +258,7 @@ describe(GRPCClientAgent.name, () => { port: clientProxy1.getForwardPort(), authToken: clientProxy1.authToken, }, - timeout: 5000, + timer: timerStart(5000), logger, }); @@ -291,7 +292,7 @@ describe(GRPCClientAgent.name, () => { port: clientProxy2.getForwardPort(), authToken: clientProxy2.authToken, }, - timeout: 5000, + timer: timerStart(5000), }); }); afterEach(async () => { diff --git a/tests/agent/utils.ts b/tests/agent/utils.ts index 7712d0fa8..afa61c0c0 100644 --- a/tests/agent/utils.ts +++ b/tests/agent/utils.ts @@ -19,6 +19,7 @@ import { createAgentService, GRPCClientAgent, } from '@/agent'; +import { timerStart } from '@/utils'; import * as testNodesUtils from '../nodes/utils'; async function openTestAgentServer({ @@ -94,7 +95,7 @@ async function openTestAgentClient( logger: logger, destroyCallback: async () => {}, proxyConfig, - timeout: 30000, + timer: timerStart(30000), }); } diff --git a/tests/client/GRPCClientClient.test.ts b/tests/client/GRPCClientClient.test.ts index bb083f816..b90406a80 100644 --- a/tests/client/GRPCClientClient.test.ts +++ b/tests/client/GRPCClientClient.test.ts @@ -11,6 +11,7 @@ import Session from '@/sessions/Session'; import * as keysUtils from '@/keys/utils'; import * as clientErrors from '@/client/errors'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import { timerStart } from '@/utils'; import * as testClientUtils from './utils'; import * as testUtils from '../utils'; @@ -76,7 +77,7 @@ describe(GRPCClientClient.name, () => { port: port as Port, tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, logger: logger, - timeout: 10000, + timer: timerStart(10000), session: session, }); await client.destroy(); diff --git a/tests/client/utils.ts b/tests/client/utils.ts index 036257328..9af325dba 100644 --- a/tests/client/utils.ts +++ b/tests/client/utils.ts @@ -11,7 +11,7 @@ import { } from '@/proto/js/polykey/v1/client_service_grpc_pb'; import createClientService from '@/client/service'; import PolykeyClient from '@/PolykeyClient'; -import { promisify } from '@/utils'; +import { promisify, timerStart } from '@/utils'; import * as grpcUtils from '@/grpc/utils'; async function openTestClientServer({ @@ -82,7 +82,7 @@ async function openTestClientClient( port: port, fs, logger, - timeout: 30000, + timer: timerStart(30000), }); return pkc; diff --git a/tests/grpc/GRPCClient.test.ts b/tests/grpc/GRPCClient.test.ts index e18f301e6..bf252bc6d 100644 --- a/tests/grpc/GRPCClient.test.ts +++ b/tests/grpc/GRPCClient.test.ts @@ -16,6 +16,7 @@ import * as keysUtils from '@/keys/utils'; import * as grpcErrors from '@/grpc/errors'; import * as clientUtils from '@/client/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import { timerStart } from '@/utils'; import * as utils from './utils'; import * as testNodesUtils from '../nodes/utils'; import { expectRemoteError } from '../utils'; @@ -110,7 +111,7 @@ describe('GRPCClient', () => { keyPrivatePem: keysUtils.privateKeyToPem(clientKeyPair.privateKey), certChainPem: keysUtils.certToPem(clientCert), }, - timeout: 1000, + timer: timerStart(1000), logger, }); await client.destroy(); @@ -124,7 +125,7 @@ describe('GRPCClient', () => { keyPrivatePem: keysUtils.privateKeyToPem(clientKeyPair.privateKey), certChainPem: keysUtils.certToPem(clientCert), }, - timeout: 1000, + timer: timerStart(1000), logger, }); const m = new utilsPB.EchoMessage(); @@ -157,7 +158,7 @@ describe('GRPCClient', () => { certChainPem: keysUtils.certToPem(clientCert), }, session, - timeout: 1000, + timer: timerStart(1000), logger, }); let pCall: PromiseUnaryCall; @@ -193,7 +194,7 @@ describe('GRPCClient', () => { keyPrivatePem: keysUtils.privateKeyToPem(clientKeyPair.privateKey), certChainPem: keysUtils.certToPem(clientCert), }, - timeout: 1000, + timer: timerStart(1000), logger, }); const challenge = 'f9s8d7f4'; @@ -236,7 +237,7 @@ describe('GRPCClient', () => { certChainPem: keysUtils.certToPem(clientCert), }, session, - timeout: 1000, + timer: timerStart(1000), logger, }); const challenge = 'f9s8d7f4'; @@ -261,7 +262,7 @@ describe('GRPCClient', () => { keyPrivatePem: keysUtils.privateKeyToPem(clientKeyPair.privateKey), certChainPem: keysUtils.certToPem(clientCert), }, - timeout: 1000, + timer: timerStart(1000), logger, }); const [stream, response] = client.clientStream(); @@ -299,7 +300,7 @@ describe('GRPCClient', () => { certChainPem: keysUtils.certToPem(clientCert), }, session, - timeout: 1000, + timer: timerStart(1000), logger, }); const [stream] = client.clientStream(); @@ -322,7 +323,7 @@ describe('GRPCClient', () => { keyPrivatePem: keysUtils.privateKeyToPem(clientKeyPair.privateKey), certChainPem: keysUtils.certToPem(clientCert), }, - timeout: 1000, + timer: timerStart(1000), logger, }); const stream = client.duplexStream(); @@ -357,7 +358,7 @@ describe('GRPCClient', () => { certChainPem: keysUtils.certToPem(clientCert), }, session, - timeout: 1000, + timer: timerStart(1000), logger, }); const stream = client.duplexStream(); diff --git a/tests/grpc/utils/GRPCClientTest.ts b/tests/grpc/utils/GRPCClientTest.ts index e3c5f9489..3b2af291d 100644 --- a/tests/grpc/utils/GRPCClientTest.ts +++ b/tests/grpc/utils/GRPCClientTest.ts @@ -5,6 +5,7 @@ import type { Host, Port, TLSConfig, ProxyConfig } from '@/network/types'; import type * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import type { ClientReadableStream } from '@grpc/grpc-js/build/src/call'; import type { AsyncGeneratorReadableStreamClient } from '@/grpc/types'; +import type { Timer } from '@/types'; import Logger from '@matrixai/logger'; import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; import GRPCClient from '@/grpc/GRPCClient'; @@ -22,7 +23,7 @@ class GRPCClientTest extends GRPCClient { tlsConfig, proxyConfig, session, - timeout = Infinity, + timer, destroyCallback, logger = new Logger(this.name), }: { @@ -32,7 +33,7 @@ class GRPCClientTest extends GRPCClient { tlsConfig?: TLSConfig; proxyConfig?: ProxyConfig; session?: Session; - timeout?: number; + timer?: Timer; destroyCallback?: () => Promise; logger?: Logger; }): Promise { @@ -48,7 +49,7 @@ class GRPCClientTest extends GRPCClient { port, tlsConfig, proxyConfig, - timeout, + timer, interceptors, logger, }); diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index 3ce2e7183..5ef4ed470 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -33,6 +33,7 @@ import * as GRPCErrors from '@/grpc/errors'; import * as nodesUtils from '@/nodes/utils'; import * as agentErrors from '@/agent/errors'; import * as grpcUtils from '@/grpc/utils'; +import { timerStart } from '@/utils'; import * as testNodesUtils from './utils'; import * as testUtils from '../utils'; import * as grpcTestUtils from '../grpc/utils'; @@ -483,7 +484,7 @@ describe('${NodeConnection.name} test', () => { // Have a nodeConnection try to connect to it const killSelf = jest.fn(); nodeConnection = await NodeConnection.createNodeConnection({ - connConnectTime: 500, + timer: timerStart(500), proxy: clientProxy, keyManager: clientKeyManager, logger: logger, @@ -518,7 +519,7 @@ describe('${NodeConnection.name} test', () => { targetNodeId: targetNodeId, targetHost: '128.0.0.1' as Host, targetPort: 12345 as Port, - connConnectTime: 300, + timer: timerStart(300), proxy: clientProxy, keyManager: clientKeyManager, nodeConnectionManager: dummyNodeConnectionManager, @@ -593,7 +594,7 @@ describe('${NodeConnection.name} test', () => { // Have a nodeConnection try to connect to it const killSelf = jest.fn(); const nodeConnectionP = NodeConnection.createNodeConnection({ - connConnectTime: 500, + timer: timerStart(500), proxy: clientProxy, keyManager: clientKeyManager, logger: logger, @@ -636,7 +637,7 @@ describe('${NodeConnection.name} test', () => { // Have a nodeConnection try to connect to it const killSelf = jest.fn(); const nodeConnectionP = NodeConnection.createNodeConnection({ - connConnectTime: 500, + timer: timerStart(500), proxy: clientProxy, keyManager: clientKeyManager, logger: logger, @@ -674,7 +675,7 @@ describe('${NodeConnection.name} test', () => { // Have a nodeConnection try to connect to it const killSelf = jest.fn(); nodeConnection = await NodeConnection.createNodeConnection({ - connConnectTime: 500, + timer: timerStart(500), proxy: clientProxy, keyManager: clientKeyManager, logger: logger, @@ -736,7 +737,7 @@ describe('${NodeConnection.name} test', () => { const killSelfCheck = jest.fn(); const killSelfP = promise(); nodeConnection = await NodeConnection.createNodeConnection({ - connConnectTime: 2000, + timer: timerStart(2000), proxy: clientProxy, keyManager: clientKeyManager, logger: logger, @@ -806,7 +807,7 @@ describe('${NodeConnection.name} test', () => { const killSelfCheck = jest.fn(); const killSelfP = promise(); nodeConnection = await NodeConnection.createNodeConnection({ - connConnectTime: 2000, + timer: timerStart(2000), proxy: clientProxy, keyManager: clientKeyManager, logger: logger, diff --git a/tests/nodes/NodeConnectionManager.lifecycle.test.ts b/tests/nodes/NodeConnectionManager.lifecycle.test.ts index 6117ddc41..49239bb72 100644 --- a/tests/nodes/NodeConnectionManager.lifecycle.test.ts +++ b/tests/nodes/NodeConnectionManager.lifecycle.test.ts @@ -17,6 +17,7 @@ import * as nodesUtils from '@/nodes/utils'; import * as nodesErrors from '@/nodes/errors'; import * as keysUtils from '@/keys/utils'; import * as grpcUtils from '@/grpc/utils'; +import { timerStart } from '@/utils'; describe(`${NodeConnectionManager.name} lifecycle test`, () => { const logger = new Logger( From fa39cd51a7d742e84aa52ffabbb52d846258a970 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 25 Mar 2022 18:20:05 +1100 Subject: [PATCH 082/137] refactor: updated implementation of `nodePing` Added `nodePing` command to `NodeConnectionManager` and `NodeManager.nodePing` calls that now. the new `nodePing` command essentially attempts to create a connection to the target node. In this process we authenticate the connection and check that the nodeIds match. If no address is provided it will default to trying to find the node through kademlia. Related #322 --- src/nodes/NodeConnectionManager.ts | 44 +++++ src/nodes/NodeManager.ts | 33 +--- .../NodeConnectionManager.lifecycle.test.ts | 166 +++++++++++++++++- 3 files changed, 216 insertions(+), 27 deletions(-) diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 5b5810492..c190c20d3 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -666,6 +666,50 @@ class NodeConnectionManager { (nodeIdEncoded) => nodesUtils.decodeNodeId(nodeIdEncoded)!, ); } + + /** + * Checks if a connection can be made to the target. Returns true if the + * connection can be authenticated, it's certificate matches the nodeId and + * the addresses match if provided. Otherwise returns false. + * @param nodeId - NodeId of the target + * @param address - Optional address of the target + * @param connConnectTime - Optional timeout for making the connection. + */ + @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) + public async pingNode( + nodeId: NodeId, + address?: NodeAddress, + connConnectTime?: number, + ): Promise { + // If we can create a connection then we have punched though the NAT, + // authenticated and confimed the nodeId matches + let connAndLock: ConnectionAndLock; + try { + connAndLock = await this.createConnection( + nodeId, + address, + connConnectTime, + ); + } catch (e) { + if ( + e instanceof nodesErrors.ErrorNodeConnectionDestroyed || + e instanceof nodesErrors.ErrorNodeConnectionTimeout || + e instanceof grpcErrors.ErrorGRPC || + e instanceof agentErrors.ErrorAgentClientDestroyed + ) { + // Failed to connect, returning false + return false; + } + throw e; + } + const remoteHost = connAndLock.connection?.host; + const remotePort = connAndLock.connection?.port; + // If address wasn't set then nothing to check + if (address == null) return true; + // Check if the address information match in case there was an + // existing connection + return address.host === remoteHost && address.port === remotePort; + } } export default NodeConnectionManager; diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 9ef964b3f..96db367a8 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -53,31 +53,16 @@ class NodeManager { /** * Determines whether a node in the Polykey network is online. * @return true if online, false if offline + * @param nodeId - NodeId of the node we're pinging + * @param address - Optional Host and Port we want to ping + * @param timeout - Optional timeout */ - // FIXME: We shouldn't be trying to find the node just to ping it - // since we are usually pinging it during the find procedure anyway. - // I think we should be providing the address of what we're trying to ping, - // possibly make it an optional parameter? - public async pingNode(targetNodeId: NodeId): Promise { - const targetAddress: NodeAddress = - await this.nodeConnectionManager.findNode(targetNodeId); - try { - // Attempt to open a connection via the forward proxy - // i.e. no NodeConnection object created (no need for GRPCClient) - await this.nodeConnectionManager.holePunchForward( - targetNodeId, - await networkUtils.resolveHost(targetAddress.host), - targetAddress.port, - ); - } catch (e) { - // If the connection request times out, then return false - if (e instanceof networkErrors.ErrorConnectionStart) { - return false; - } - // Throw any other error back up the callstack - throw e; - } - return true; + public async pingNode( + nodeId: NodeId, + address?: NodeAddress, + timeout?: number, + ): Promise { + return this.nodeConnectionManager.pingNode(nodeId, address, timeout); } /** diff --git a/tests/nodes/NodeConnectionManager.lifecycle.test.ts b/tests/nodes/NodeConnectionManager.lifecycle.test.ts index 49239bb72..5871fa4d3 100644 --- a/tests/nodes/NodeConnectionManager.lifecycle.test.ts +++ b/tests/nodes/NodeConnectionManager.lifecycle.test.ts @@ -1,4 +1,9 @@ -import type { NodeId, NodeIdString, SeedNodes } from '@/nodes/types'; +import type { + NodeAddress, + NodeId, + NodeIdString, + SeedNodes, +} from '@/nodes/types'; import type { Host, Port } from '@/network/types'; import fs from 'fs'; import path from 'path'; @@ -100,7 +105,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { password, nodePath: path.join(dataDir2, 'remoteNode1'), networkConfig: { - proxyHost: '127.0.0.1' as Host, + proxyHost: serverHost, }, logger: logger.getChild('remoteNode1'), }); @@ -110,7 +115,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { password, nodePath: path.join(dataDir2, 'remoteNode2'), networkConfig: { - proxyHost: '127.0.0.1' as Host, + proxyHost: serverHost, }, logger: logger.getChild('remoteNode2'), }); @@ -499,4 +504,159 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { await nodeConnectionManager?.stop(); } }); + + // New ping tests + test('should ping node', async () => { + // NodeConnectionManager under test + let nodeConnectionManager: NodeConnectionManager | undefined; + try { + nodeConnectionManager = new NodeConnectionManager({ + keyManager, + nodeGraph, + proxy, + logger: nodeConnectionManagerLogger, + }); + await nodeConnectionManager.start(); + // @ts-ignore: kidnap connections + const connections = nodeConnectionManager.connections; + await expect(nodeConnectionManager.pingNode(remoteNodeId1)).resolves.toBe( + true, + ); + const finalConnLock = connections.get( + remoteNodeId1.toString() as NodeIdString, + ); + // Check entry is in map and lock is released + expect(finalConnLock).toBeDefined(); + expect(finalConnLock?.lock.isLocked()).toBeFalsy(); + } finally { + await nodeConnectionManager?.stop(); + } + }); + test('should ping node with address', async () => { + // NodeConnectionManager under test + let nodeConnectionManager: NodeConnectionManager | undefined; + try { + nodeConnectionManager = new NodeConnectionManager({ + keyManager, + nodeGraph, + proxy, + logger: nodeConnectionManagerLogger, + }); + await nodeConnectionManager.start(); + const remoteNodeAddress1: NodeAddress = { + host: remoteNode1.proxy.getProxyHost(), + port: remoteNode1.proxy.getProxyPort(), + }; + await nodeConnectionManager.pingNode(remoteNodeId1, remoteNodeAddress1); + } finally { + await nodeConnectionManager?.stop(); + } + }); + test('should ping node with address when connection exists', async () => { + // NodeConnectionManager under test + let nodeConnectionManager: NodeConnectionManager | undefined; + try { + nodeConnectionManager = new NodeConnectionManager({ + keyManager, + nodeGraph, + proxy, + logger: nodeConnectionManagerLogger, + }); + await nodeConnectionManager.start(); + const remoteNodeAddress1: NodeAddress = { + host: remoteNode1.proxy.getProxyHost(), + port: remoteNode1.proxy.getProxyPort(), + }; + await nodeConnectionManager.withConnF(remoteNodeId1, nop); + await nodeConnectionManager.pingNode(remoteNodeId1, remoteNodeAddress1); + } finally { + await nodeConnectionManager?.stop(); + } + }); + test('should fail to ping non existent node', async () => { + // NodeConnectionManager under test + let nodeConnectionManager: NodeConnectionManager | undefined; + try { + nodeConnectionManager = new NodeConnectionManager({ + keyManager, + nodeGraph, + proxy, + logger: nodeConnectionManagerLogger, + }); + await nodeConnectionManager.start(); + + // Pinging node + expect( + await nodeConnectionManager.pingNode( + remoteNodeId1, + { host: '127.1.2.3' as Host, port: 55555 as Port }, + timerStart(1000), + ), + ).toEqual(false); + } finally { + await nodeConnectionManager?.stop(); + } + }); + test('should fail to ping node with wrong address when connection exists', async () => { + // NodeConnectionManager under test + let nodeConnectionManager: NodeConnectionManager | undefined; + try { + nodeConnectionManager = new NodeConnectionManager({ + keyManager, + nodeGraph, + proxy, + logger: nodeConnectionManagerLogger, + }); + await nodeConnectionManager.start(); + await nodeConnectionManager.withConnF(remoteNodeId1, nop); + expect( + await nodeConnectionManager.pingNode( + remoteNodeId1, + { host: '127.1.2.3' as Host, port: 55555 as Port }, + timerStart(1000), + ), + ).toEqual(false); + } finally { + await nodeConnectionManager?.stop(); + } + }); + test('should fail to ping node if NodeId does not match', async () => { + // NodeConnectionManager under test + let nodeConnectionManager: NodeConnectionManager | undefined; + try { + nodeConnectionManager = new NodeConnectionManager({ + keyManager, + nodeGraph, + proxy, + logger: nodeConnectionManagerLogger, + }); + await nodeConnectionManager.start(); + const remoteNodeAddress1: NodeAddress = { + host: remoteNode1.proxy.getProxyHost(), + port: remoteNode1.proxy.getProxyPort(), + }; + const remoteNodeAddress2: NodeAddress = { + host: remoteNode2.proxy.getProxyHost(), + port: remoteNode2.proxy.getProxyPort(), + }; + + expect( + await nodeConnectionManager.pingNode( + remoteNodeId1, + remoteNodeAddress2, + timerStart(1000), + ), + ).toEqual(false); + + expect( + await nodeConnectionManager.pingNode( + remoteNodeId2, + remoteNodeAddress1, + timerStart(1000), + ), + ).toEqual(false); + } finally { + await nodeConnectionManager?.stop(); + } + }); }); From e92503476de391c0dfc236853c5589ce5c72a1fd Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Mon, 28 Mar 2022 18:19:09 +1100 Subject: [PATCH 083/137] feat: `NodeManager.setNode` authenticates the added node `setNode` now authenticates the node you are trying to add. Added a flag for skipping this authentication as well as a timeout timer for the authentication. this is shared between authentication new node and the old node if the bucket is full. Related #322 --- src/nodes/NodeConnectionManager.ts | 16 ++++------------ src/nodes/NodeManager.ts | 26 ++++++++++++++++---------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index c190c20d3..9d1f7302c 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -673,23 +673,15 @@ class NodeConnectionManager { * the addresses match if provided. Otherwise returns false. * @param nodeId - NodeId of the target * @param address - Optional address of the target - * @param connConnectTime - Optional timeout for making the connection. + * @param timer Connection timeout timer */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) - public async pingNode( - nodeId: NodeId, - address?: NodeAddress, - connConnectTime?: number, - ): Promise { + public async pingNode(nodeId: NodeId, address?: NodeAddress, timer?: Timer): Promise { // If we can create a connection then we have punched though the NAT, - // authenticated and confimed the nodeId matches + // authenticated and confirmed the nodeId matches let connAndLock: ConnectionAndLock; try { - connAndLock = await this.createConnection( - nodeId, - address, - connConnectTime, - ); + connAndLock = await this.createConnection(nodeId, address, timer); } catch (e) { if ( e instanceof nodesErrors.ErrorNodeConnectionDestroyed || diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 96db367a8..9ac3eac2c 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -55,14 +55,10 @@ class NodeManager { * @return true if online, false if offline * @param nodeId - NodeId of the node we're pinging * @param address - Optional Host and Port we want to ping - * @param timeout - Optional timeout + * @param timer Connection timeout timer */ - public async pingNode( - nodeId: NodeId, - address?: NodeAddress, - timeout?: number, - ): Promise { - return this.nodeConnectionManager.pingNode(nodeId, address, timeout); + public async pingNode(nodeId: NodeId, address?: NodeAddress, timer?: Timer): Promise { + return this.nodeConnectionManager.pingNode(nodeId, address, timer); } /** @@ -337,14 +333,24 @@ class NodeManager { /** * Adds a node to the node graph. * Updates the node if the node already exists. - * + * @param nodeId - Id of the node we wish to add + * @param nodeAddress - Expected address of the node we want to add + * @param authenticate - Flag for if we want to authenticate the node we're adding + * @param force - Flag for if we want to add the node without authenticating or if the bucket is full. + * This will drop the oldest node in favor of the new. + * @param timer Connection timeout timer */ public async setNode( nodeId: NodeId, nodeAddress: NodeAddress, - force = false, + authenticate: boolean = true, + force: boolean = false, + timer?: Timer, tran: DBTransaction, ): Promise { + // if we fail to ping and authenticate the new node we return + // skip if force is true or authenticate is false + if (!force && authenticate && !(await this.pingNode(nodeId, nodeAddress, timer))) return // When adding a node we need to handle 3 cases // 1. The node already exists. We need to update it's last updated field // 2. The node doesn't exist and bucket has room. @@ -372,7 +378,7 @@ class NodeManager { bucketIndex, tran, ))!; - if ((await this.pingNode(oldestNodeId)) && !force) { + if ((await this.pingNode(oldestNodeId, undefined, timer)) && !force) { // The node responded, we need to update it's info and drop the new node const oldestNode = (await this.nodeGraph.getNode(oldestNodeId, tran))!; await this.nodeGraph.setNode(oldestNodeId, oldestNode.address, tran); From 7815b2e8a85dde1848c03a0ec43532c489d83c1e Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 29 Mar 2022 12:12:37 +1100 Subject: [PATCH 084/137] syntax: general linting and fixes from api changes --- src/PolykeyAgent.ts | 2 +- src/bin/nodes/CommandGetAll.ts | 12 ++++-------- src/client/service/nodesGetAll.ts | 5 ++--- src/nodes/NodeConnectionManager.ts | 9 ++++++++- src/nodes/NodeManager.ts | 18 +++++++++++++----- src/nodes/types.ts | 4 ++-- tests/client/service/keysKeyPairRenew.test.ts | 4 ++-- tests/client/service/keysKeyPairReset.test.ts | 4 ++-- tests/client/service/nodesAdd.test.ts | 3 +-- .../NodeConnectionManager.general.test.ts | 18 ++++++++++-------- tests/utils.ts | 19 ++++++++++--------- tests/vaults/VaultInternal.test.ts | 4 ++-- tests/vaults/VaultManager.test.ts | 8 ++++---- 13 files changed, 61 insertions(+), 49 deletions(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index a3f5241f3..792a8778b 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -8,7 +8,7 @@ import process from 'process'; import Logger from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { CreateDestroyStartStop } from '@matrixai/async-init/dist/CreateDestroyStartStop'; -import * as networkUtils from '@/network/utils'; +import * as networkUtils from './network/utils'; import KeyManager from './keys/KeyManager'; import Status from './status/Status'; import Schema from './schema/Schema'; diff --git a/src/bin/nodes/CommandGetAll.ts b/src/bin/nodes/CommandGetAll.ts index 5d1b5a8fc..243991fc9 100644 --- a/src/bin/nodes/CommandGetAll.ts +++ b/src/bin/nodes/CommandGetAll.ts @@ -43,14 +43,10 @@ class CommandGetAll extends CommandPolykey { logger: this.logger.getChild(PolykeyClient.name), }); const emptyMessage = new utilsPB.EmptyMessage(); - try { - result = await binUtils.retryAuthentication( - (auth) => pkClient.grpcClient.nodesGetAll(emptyMessage, auth), - meta, - ); - } catch (err) { - throw err; - } + result = await binUtils.retryAuthentication( + (auth) => pkClient.grpcClient.nodesGetAll(emptyMessage, auth), + meta, + ); let output: any = {}; for (const [bucketIndex, bucket] of result.getBucketsMap().entries()) { output[bucketIndex] = {}; diff --git a/src/client/service/nodesGetAll.ts b/src/client/service/nodesGetAll.ts index 6a658fedd..bc01e84e0 100644 --- a/src/client/service/nodesGetAll.ts +++ b/src/client/service/nodesGetAll.ts @@ -1,6 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { NodeGraph } from '../../nodes'; import type { KeyManager } from '../../keys'; import type { NodeId } from '../../nodes/types'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; @@ -13,11 +12,11 @@ import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; * Retrieves all nodes from all buckets in the NodeGraph. */ function nodesGetAll({ - nodeGraph, + // NodeGraph, keyManager, authenticate, }: { - nodeGraph: NodeGraph; + // NodeGraph: NodeGraph; keyManager: KeyManager; authenticate: Authenticate; }) { diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 9d1f7302c..31540aaa8 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -10,6 +10,9 @@ import type { NodeId, NodeIdString, SeedNodes, + NodeEntry, + NodeBucket, + NodeIdString, } from './types'; import { withF } from '@matrixai/resources'; import Logger from '@matrixai/logger'; @@ -676,7 +679,11 @@ class NodeConnectionManager { * @param timer Connection timeout timer */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) - public async pingNode(nodeId: NodeId, address?: NodeAddress, timer?: Timer): Promise { + public async pingNode( + nodeId: NodeId, + address?: NodeAddress, + timer?: Timer, + ): Promise { // If we can create a connection then we have punched though the NAT, // authenticated and confirmed the nodeId matches let connAndLock: ConnectionAndLock; diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 9ac3eac2c..4bb1d05ab 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -14,8 +14,6 @@ import * as nodesUtils from './utils'; import * as validationUtils from '../validation/utils'; import * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb'; import * as claimsErrors from '../claims/errors'; -import * as networkErrors from '../network/errors'; -import * as networkUtils from '../network/utils'; import * as sigchainUtils from '../sigchain/utils'; import * as claimsUtils from '../claims/utils'; @@ -57,7 +55,11 @@ class NodeManager { * @param address - Optional Host and Port we want to ping * @param timer Connection timeout timer */ - public async pingNode(nodeId: NodeId, address?: NodeAddress, timer?: Timer): Promise { + public async pingNode( + nodeId: NodeId, + address?: NodeAddress, + timer?: Timer, + ): Promise { return this.nodeConnectionManager.pingNode(nodeId, address, timer); } @@ -348,9 +350,15 @@ class NodeManager { timer?: Timer, tran: DBTransaction, ): Promise { - // if we fail to ping and authenticate the new node we return + // If we fail to ping and authenticate the new node we return // skip if force is true or authenticate is false - if (!force && authenticate && !(await this.pingNode(nodeId, nodeAddress, timer))) return + if ( + !force && + authenticate && + !(await this.pingNode(nodeId, nodeAddress, timer)) + ) { + return; + } // When adding a node we need to handle 3 cases // 1. The node already exists. We need to update it's last updated field // 2. The node doesn't exist and bucket has room. diff --git a/src/nodes/types.ts b/src/nodes/types.ts index 683143e83..8e173b4f2 100644 --- a/src/nodes/types.ts +++ b/src/nodes/types.ts @@ -1,5 +1,5 @@ import type { Id } from '@matrixai/id'; -import type { Opaque, NonFunctionProperties } from '../types'; +import type { Opaque } from '../types'; import type { Host, Hostname, Port } from '../network/types'; import type { Claim, ClaimId } from '../claims/types'; import type { ChainData } from '../sigchain/types'; @@ -33,7 +33,7 @@ type NodeBucketMeta = { count: number; }; -type NodeBucketMetaProps = NonFunctionProperties; +// Type NodeBucketMetaProps = NonFunctionProperties; // Just make the bucket entries also // bucketIndex anot as a key diff --git a/tests/client/service/keysKeyPairRenew.test.ts b/tests/client/service/keysKeyPairRenew.test.ts index 8a792254b..a36c621c1 100644 --- a/tests/client/service/keysKeyPairRenew.test.ts +++ b/tests/client/service/keysKeyPairRenew.test.ts @@ -7,7 +7,6 @@ import path from 'path'; import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { Metadata } from '@grpc/grpc-js'; -import NodeGraph from '@/nodes/NodeGraph'; import PolykeyAgent from '@/PolykeyAgent'; import GRPCServer from '@/grpc/GRPCServer'; import GRPCClientClient from '@/client/GRPCClientClient'; @@ -17,6 +16,7 @@ import * as keysPB from '@/proto/js/polykey/v1/keys/keys_pb'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; +import { NodeManager } from '@/nodes'; import * as testUtils from '../../utils'; describe('keysKeyPairRenew', () => { @@ -32,7 +32,7 @@ describe('keysKeyPairRenew', () => { beforeAll(async () => { const globalKeyPair = await testUtils.setupGlobalKeypair(); const newKeyPair = await keysUtils.generateKeyPair(1024); - mockedRefreshBuckets = jest.spyOn(NodeGraph.prototype, 'refreshBuckets'); + mockedRefreshBuckets = jest.spyOn(NodeManager.prototype, 'refreshBuckets'); mockedGenerateKeyPair = jest .spyOn(keysUtils, 'generateKeyPair') .mockResolvedValueOnce(globalKeyPair) diff --git a/tests/client/service/keysKeyPairReset.test.ts b/tests/client/service/keysKeyPairReset.test.ts index 8c41064b1..335d5c5fd 100644 --- a/tests/client/service/keysKeyPairReset.test.ts +++ b/tests/client/service/keysKeyPairReset.test.ts @@ -7,7 +7,6 @@ import path from 'path'; import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { Metadata } from '@grpc/grpc-js'; -import NodeGraph from '@/nodes/NodeGraph'; import PolykeyAgent from '@/PolykeyAgent'; import GRPCServer from '@/grpc/GRPCServer'; import GRPCClientClient from '@/client/GRPCClientClient'; @@ -17,6 +16,7 @@ import * as keysPB from '@/proto/js/polykey/v1/keys/keys_pb'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; +import { NodeManager } from '@/nodes'; import * as testUtils from '../../utils'; describe('keysKeyPairReset', () => { @@ -32,7 +32,7 @@ describe('keysKeyPairReset', () => { beforeAll(async () => { const globalKeyPair = await testUtils.setupGlobalKeypair(); const newKeyPair = await keysUtils.generateKeyPair(1024); - mockedRefreshBuckets = jest.spyOn(NodeGraph.prototype, 'refreshBuckets'); + mockedRefreshBuckets = jest.spyOn(NodeManager.prototype, 'refreshBuckets'); mockedGenerateKeyPair = jest .spyOn(keysUtils, 'generateKeyPair') .mockResolvedValueOnce(globalKeyPair) diff --git a/tests/client/service/nodesAdd.test.ts b/tests/client/service/nodesAdd.test.ts index 86923b961..e0a07e171 100644 --- a/tests/client/service/nodesAdd.test.ts +++ b/tests/client/service/nodesAdd.test.ts @@ -166,8 +166,7 @@ describe('nodesAdd', () => { )!, ); expect(result).toBeDefined(); - expect(result!.host).toBe('127.0.0.1'); - expect(result!.port).toBe(11111); + expect(result!.address).toBe('127.0.0.1:11111'); }); test('cannot add invalid node', async () => { // Invalid host diff --git a/tests/nodes/NodeConnectionManager.general.test.ts b/tests/nodes/NodeConnectionManager.general.test.ts index 24986923b..d13c838de 100644 --- a/tests/nodes/NodeConnectionManager.general.test.ts +++ b/tests/nodes/NodeConnectionManager.general.test.ts @@ -1,4 +1,4 @@ -import type { NodeAddress, NodeData, NodeId, SeedNodes } from '@/nodes/types'; +import type { NodeAddress, NodeBucket, NodeId, SeedNodes } from '@/nodes/types'; import type { Host, Port } from '@/network/types'; import fs from 'fs'; import path from 'path'; @@ -362,7 +362,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { }); // Now generate and add 20 nodes that will be close to this node ID - const addedClosestNodes: NodeData[] = []; + const addedClosestNodes: NodeBucket = []; for (let i = 1; i < 101; i += 5) { const closeNodeId = testNodesUtils.generateNodeIdForBucket( targetNodeId, @@ -373,11 +373,13 @@ describe(`${NodeConnectionManager.name} general test`, () => { port: i as Port, }; await serverPKAgent.nodeGraph.setNode(closeNodeId, nodeAddress); - addedClosestNodes.push({ - id: closeNodeId, - address: nodeAddress, - distance: nodesUtils.calculateDistance(targetNodeId, closeNodeId), - }); + addedClosestNodes.push([ + closeNodeId, + { + address: nodeAddress, + lastUpdated: 0, + }, + ]); } // Now create and add 10 more nodes that are far away from this node for (let i = 1; i <= 10; i++) { @@ -396,7 +398,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { ); // Sort the received nodes on distance such that we can check its equality // with addedClosestNodes - closest.sort(nodesUtils.sortByDistance); + nodesUtils.bucketSortByDistance(closest, targetNodeId); expect(closest.length).toBe(20); expect(closest).toEqual(addedClosestNodes); } finally { diff --git a/tests/utils.ts b/tests/utils.ts index ea2d11ff9..c7636c4a5 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,20 +1,21 @@ -import type { StatusLive } from '@/status/types'; +// Import type { StatusLive } from '@/status/types'; import type { NodeId } from '@/nodes/types'; -import type { Host } from '@/network/types'; +// import type { Host } from '@/network/types'; import path from 'path'; import fs from 'fs'; import lock from 'fd-lock'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; -import PolykeyAgent from '@/PolykeyAgent'; -import Status from '@/status/Status'; -import GRPCClientClient from '@/client/GRPCClientClient'; -import * as clientUtils from '@/client/utils'; +// Import PolykeyAgent from '@/PolykeyAgent'; +// import Status from '@/status/Status'; +// import GRPCClientClient from '@/client/GRPCClientClient'; +// import * as clientUtils from '@/client/utils'; import * as keysUtils from '@/keys/utils'; -import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +// Import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as grpcErrors from '@/grpc/errors'; import { sleep } from '@/utils'; -import config from '@/config'; +import * as errors from '@/errors'; +// import config from '@/config'; /** * Setup the global keypair @@ -86,7 +87,7 @@ async function setupGlobalKeypair() { // * * Ensure server-side side-effects are removed at the end of each test // */ async function setupGlobalAgent( - logger: Logger = new Logger(setupGlobalAgent.name, LogLevel.WARN, [ + _logger: Logger = new Logger(setupGlobalAgent.name, LogLevel.WARN, [ new StreamHandler(), ]), ): Promise { diff --git a/tests/vaults/VaultInternal.test.ts b/tests/vaults/VaultInternal.test.ts index 86c283baf..d91978c5a 100644 --- a/tests/vaults/VaultInternal.test.ts +++ b/tests/vaults/VaultInternal.test.ts @@ -15,7 +15,7 @@ import * as vaultsErrors from '@/vaults/errors'; import { sleep } from '@/utils'; import * as keysUtils from '@/keys/utils'; import * as vaultsUtils from '@/vaults/utils'; -import * as testsUtils from '../utils'; +import * as nodeTestUtils from '../nodes/utils'; jest.mock('@/keys/utils', () => ({ ...jest.requireActual('@/keys/utils'), @@ -39,7 +39,7 @@ describe('VaultInternal', () => { const fakeKeyManager = { getNodeId: () => { - return testsUtils.generateRandomNodeId(); + return nodeTestUtils.generateRandomNodeId(); }, } as KeyManager; const secret1 = { name: 'secret-1', content: 'secret-content-1' }; diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index e4ed618aa..f37dfba38 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -30,7 +30,7 @@ import * as vaultsUtils from '@/vaults/utils'; import * as keysUtils from '@/keys/utils'; import { sleep } from '@/utils'; import VaultInternal from '@/vaults/VaultInternal'; -import * as testsUtils from '../utils'; +import * as nodeTestUtils from '../nodes/utils'; import { expectRemoteError } from '../utils'; const mockedGenerateDeterministicKeyPair = jest @@ -65,7 +65,7 @@ describe('VaultManager', () => { let db: DB; // We only ever use this to get NodeId, No need to create a whole one - const nodeId = testsUtils.generateRandomNodeId(); + const nodeId = nodeTestUtils.generateRandomNodeId(); const dummyKeyManager = { getNodeId: () => nodeId, } as KeyManager; @@ -1394,8 +1394,8 @@ describe('VaultManager', () => { }); try { // Setting up state - const nodeId1 = testsUtils.generateRandomNodeId(); - const nodeId2 = testsUtils.generateRandomNodeId(); + const nodeId1 = nodeTestUtils.generateRandomNodeId(); + const nodeId2 = nodeTestUtils.generateRandomNodeId(); await gestaltGraph.setNode({ id: nodesUtils.encodeNodeId(nodeId1), chain: {}, From 9505e20fbd7f3716abefe69a35fc114607b45ba8 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 31 Mar 2022 14:04:03 +1100 Subject: [PATCH 085/137] fix: squash into ping node changes. Updated `NodeConnectionManager.pingNode` to just use the proxy connection. #322 --- src/nodes/NodeConnectionManager.ts | 72 +++++++++++++++--------------- src/nodes/NodeManager.ts | 13 +++++- 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 31540aaa8..43f703988 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -135,14 +135,9 @@ class NodeConnectionManager { public async acquireConnection( targetNodeId: NodeId, timer?: Timer, - address?: NodeAddress, ): Promise>> { return async () => { - const { connection, timer } = await this.getConnection( - targetNodeId, - address, - timer, - ); + const { connection, timer } = await this.getConnection(targetNodeId, timer); // Acquire the read lock and the release function const [release] = await this.connectionLocks.lock([ targetNodeId.toString(), @@ -185,7 +180,7 @@ class NodeConnectionManager { timer?: Timer, ): Promise { return await withF( - [await this.acquireConnection(targetNodeId, timer, undefined)], + [await this.acquireConnection(targetNodeId, timer)], async ([conn]) => { this.logger.info( `withConnF calling function with connection to ${nodesUtils.encodeNodeId( @@ -214,11 +209,7 @@ class NodeConnectionManager { ) => AsyncGenerator, timer?: Timer, ): AsyncGenerator { - const acquire = await this.acquireConnection( - targetNodeId, - timer, - undefined, - ); + const acquire = await this.acquireConnection(targetNodeId, timer); const [release, conn] = await acquire(); let caughtError; try { @@ -236,13 +227,11 @@ class NodeConnectionManager { * Create a connection to another node (without performing any function). * This is a NOOP if a connection already exists. * @param targetNodeId Id of node we are creating connection to - * @param address Optional address to connect to * @param timer Connection timeout timer * @returns ConnectionAndLock that was created or exists in the connection map */ protected async getConnection( targetNodeId: NodeId, - address?: NodeAddress, timer?: Timer, ): Promise { this.logger.info( @@ -467,7 +456,7 @@ class NodeConnectionManager { // call to getConnectionToNode // FIXME: no tran await this.nodeGraph.setNode(nextNodeId, nextNodeAddress.address); - await this.getConnection(nextNodeId, undefined, timer); + await this.getConnection(nextNodeId, timer); } catch (e) { // If we can't connect to the node, then skip it continue; @@ -581,7 +570,7 @@ class NodeConnectionManager { for (const seedNodeId of this.getSeedNodes()) { // Check if the connection is viable try { - await this.getConnection(seedNodeId, undefined, timer); + await this.getConnection(seedNodeId, timer); } catch (e) { if (e instanceof nodesErrors.ErrorNodeConnectionTimeout) continue; throw e; @@ -675,39 +664,48 @@ class NodeConnectionManager { * connection can be authenticated, it's certificate matches the nodeId and * the addresses match if provided. Otherwise returns false. * @param nodeId - NodeId of the target - * @param address - Optional address of the target + * @param host - Host of the target node + * @param port - Port of the target node * @param timer Connection timeout timer */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) public async pingNode( nodeId: NodeId, - address?: NodeAddress, + host: Host, + port: Port, timer?: Timer, ): Promise { // If we can create a connection then we have punched though the NAT, // authenticated and confirmed the nodeId matches - let connAndLock: ConnectionAndLock; + const proxyAddress = networkUtils.buildAddress( + this.proxy.getProxyHost(), + this.proxy.getProxyPort(), + ); + const signature = await this.keyManager.signWithRootKeyPair( + Buffer.from(proxyAddress), + ); + const holePunchPromises = Array.from(this.getSeedNodes(), (seedNodeId) => { + return this.sendHolePunchMessage( + seedNodeId, + this.keyManager.getNodeId(), + nodeId, + proxyAddress, + signature, + ); + }); + const forwardPunchPromise = this.holePunchForward( + nodeId, + host, + port, + timer, + ); + try { - connAndLock = await this.createConnection(nodeId, address, timer); + await Promise.all([forwardPunchPromise, ...holePunchPromises]); } catch (e) { - if ( - e instanceof nodesErrors.ErrorNodeConnectionDestroyed || - e instanceof nodesErrors.ErrorNodeConnectionTimeout || - e instanceof grpcErrors.ErrorGRPC || - e instanceof agentErrors.ErrorAgentClientDestroyed - ) { - // Failed to connect, returning false - return false; - } - throw e; + return false; } - const remoteHost = connAndLock.connection?.host; - const remotePort = connAndLock.connection?.port; - // If address wasn't set then nothing to check - if (address == null) return true; - // Check if the address information match in case there was an - // existing connection - return address.host === remoteHost && address.port === remotePort; + return true; } } diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 4bb1d05ab..d18b406de 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -11,6 +11,7 @@ import type { Timer } from '../types'; import Logger from '@matrixai/logger'; import * as nodesErrors from './errors'; import * as nodesUtils from './utils'; +import * as networkUtils from '../network/utils'; import * as validationUtils from '../validation/utils'; import * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb'; import * as claimsErrors from '../claims/errors'; @@ -60,7 +61,17 @@ class NodeManager { address?: NodeAddress, timer?: Timer, ): Promise { - return this.nodeConnectionManager.pingNode(nodeId, address, timer); + // We need to attempt a connection using the proxies + // For now we will just do a forward connect + relay message + const targetAddress = + address ?? (await this.nodeConnectionManager.findNode(nodeId)); + const targetHost = await networkUtils.resolveHost(targetAddress.host); + return await this.nodeConnectionManager.pingNode( + nodeId, + targetHost, + targetAddress.port, + timer, + ); } /** From 0e34a170fe411742b1a6f217962803bf26613a6e Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 31 Mar 2022 14:23:11 +1100 Subject: [PATCH 086/137] fix: setNode now does not ping the new node #322 --- src/nodes/NodeManager.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index d18b406de..4e1e12914 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -344,11 +344,10 @@ class NodeManager { } /** - * Adds a node to the node graph. + * Adds a node to the node graph. This assumes that you have already authenticated the node. * Updates the node if the node already exists. * @param nodeId - Id of the node we wish to add * @param nodeAddress - Expected address of the node we want to add - * @param authenticate - Flag for if we want to authenticate the node we're adding * @param force - Flag for if we want to add the node without authenticating or if the bucket is full. * This will drop the oldest node in favor of the new. * @param timer Connection timeout timer @@ -356,20 +355,10 @@ class NodeManager { public async setNode( nodeId: NodeId, nodeAddress: NodeAddress, - authenticate: boolean = true, force: boolean = false, timer?: Timer, tran: DBTransaction, ): Promise { - // If we fail to ping and authenticate the new node we return - // skip if force is true or authenticate is false - if ( - !force && - authenticate && - !(await this.pingNode(nodeId, nodeAddress, timer)) - ) { - return; - } // When adding a node we need to handle 3 cases // 1. The node already exists. We need to update it's last updated field // 2. The node doesn't exist and bucket has room. From 976421341a7301182b072d54e4cbae6fb24bc475 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 31 Mar 2022 15:16:37 +1100 Subject: [PATCH 087/137] feat: setNode concurrently pings multiple nodes `setNode` now pings 3 nodes concurrently, updating ones that respond and removing ones that don't. If there is room in the bucket afterwards then we add the new node. #322 --- src/nodes/NodeGraph.ts | 20 ++++------ src/nodes/NodeManager.ts | 69 ++++++++++++++++++++++----------- tests/nodes/NodeManager.test.ts | 6 +-- 3 files changed, 57 insertions(+), 38 deletions(-) diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index 0bf30f3ae..d6c6be1c6 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -260,26 +260,22 @@ class NodeGraph { @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async getOldestNode( bucketIndex: number, + limit: number = 1, tran?: DBTransaction, - ): Promise { + ): Promise> { if (tran == null) { return this.db.withTransactionF(async (tran) => - this.getOldestNode(bucketIndex, tran), + this.getOldestNode(bucketIndex, limit, tran), ); } - const bucketKey = nodesUtils.bucketKey(bucketIndex); // Remove the oldest entry in the bucket - let oldestNodeId: NodeId | undefined; - for await (const [key] of tran.iterator({ limit: 1 }, [ - ...this.nodeGraphLastUpdatedDbPath, - bucketKey, - ])) { - ({ nodeId: oldestNodeId } = nodesUtils.parseLastUpdatedBucketDbKey( - key as unknown as Buffer, - )); + const oldestNodeIds: Array = []; + for await (const [key] of tran.iterator({ limit }, [...this.nodeGraphLastUpdatedDbPath, bucketKey])) { + const { nodeId } = nodesUtils.parseLastUpdatedBucketDbKey(key as unknown as Buffer); + oldestNodeIds.push(nodeId); } - return oldestNodeId; + return oldestNodeIds; } @ready(new nodesErrors.ErrorNodeGraphNotRunning()) diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 4e1e12914..8aa576e3f 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -68,8 +68,10 @@ class NodeManager { const targetHost = await networkUtils.resolveHost(targetAddress.host); return await this.nodeConnectionManager.pingNode( nodeId, - targetHost, - targetAddress.port, + { + host: targetHost, + port: targetAddress.port, + }, timer, ); } @@ -351,6 +353,7 @@ class NodeManager { * @param force - Flag for if we want to add the node without authenticating or if the bucket is full. * This will drop the oldest node in favor of the new. * @param timer Connection timeout timer + * @param tran */ public async setNode( nodeId: NodeId, @@ -382,35 +385,55 @@ class NodeManager { } else { // We want to add a node but the bucket is full // We need to ping the oldest node - const oldestNodeId = (await this.nodeGraph.getOldestNode( + const oldestNodeIds = (await this.nodeGraph.getOldestNode( bucketIndex, + 3, tran, ))!; - if ((await this.pingNode(oldestNodeId, undefined, timer)) && !force) { - // The node responded, we need to update it's info and drop the new node - const oldestNode = (await this.nodeGraph.getNode(oldestNodeId, tran))!; - await this.nodeGraph.setNode(oldestNodeId, oldestNode.address, tran); - } else { - // The node could not be contacted or force was set, - // we drop it in favor of the new node - await this.nodeGraph.unsetNode(oldestNodeId, tran); + if (force) { + // We just add the new node anyway without checking the old one + const oldNodeId = oldestNodeIds[0]; + await this.nodeGraph.unsetNode(oldNodeId, tran); + await this.nodeGraph.setNode(nodeId, nodeAddress, tran); + return; + } + // We want to concurrently ping the nodes + const pingPromises = oldestNodeIds.map((nodeId) => { + const doPing = async (): Promise<{ + nodeId: NodeId; + success: boolean; + }> => { + // This needs to return nodeId and ping result + const data = await this.nodeGraph.getNode(nodeId, tran); + if (data == null) return { nodeId, success: false }; + const result = await this.pingNode(nodeId, undefined, timer); + return { nodeId, success: result }; + }; + return doPing(); + }); + const pingResults = await Promise.all(pingPromises); + for (const { nodeId, success } of pingResults) { + if (success) { + // Ping succeeded, update the node + const node = (await this.nodeGraph.getNode(nodeId, tran))!; + await this.nodeGraph.setNode(nodeId, node.address, tran); + } else { + // Otherwise we remove the node + await this.nodeGraph.unsetNode(nodeId, tran); + } + } + // Check if we now have room and add the new node + const count = await this.nodeGraph.getBucketMetaProp( + bucketIndex, + 'count', + tran, + ); + if (count < this.nodeGraph.nodeBucketLimit) { await this.nodeGraph.setNode(nodeId, nodeAddress, tran); } } } - // FIXME - // /** - // * Updates the node in the NodeGraph - // */ - // public async updateNode( - // nodeId: NodeId, - // nodeAddress?: NodeAddress, - // tran?: DBTransaction, - // ): Promise { - // return await this.nodeGraph.updateNode(nodeId, nodeAddress, tran); - // } - /** * Removes a node from the NodeGraph */ diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index 8d2c249b8..da7451d99 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -506,7 +506,7 @@ describe(`${NodeManager.name} test`, () => { // Mocking ping const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); nodeManagerPingMock.mockResolvedValue(true); - const oldestNodeId = await nodeGraph.getOldestNode(bucketIndex); + const oldestNodeId = (await nodeGraph.getOldestNode(bucketIndex)).pop(); const oldestNode = await nodeGraph.getNode(oldestNodeId!); // Waiting for a second to tick over await sleep(1100); @@ -550,7 +550,7 @@ describe(`${NodeManager.name} test`, () => { // Mocking ping const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); nodeManagerPingMock.mockResolvedValue(true); - const oldestNodeId = await nodeGraph.getOldestNode(bucketIndex); + const oldestNodeId = (await nodeGraph.getOldestNode(bucketIndex)).pop(); // Adding a new node with bucket full await nodeManager.setNode(nodeId, { port: 55555 } as NodeAddress, true); // Bucket still contains max nodes @@ -591,7 +591,7 @@ describe(`${NodeManager.name} test`, () => { // Mocking ping const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); nodeManagerPingMock.mockResolvedValue(false); - const oldestNodeId = await nodeGraph.getOldestNode(bucketIndex); + const oldestNodeId = (await nodeGraph.getOldestNode(bucketIndex)).pop(); // Adding a new node with bucket full await nodeManager.setNode(nodeId, { port: 55555 } as NodeAddress, true); // Bucket still contains max nodes From a02cfea412c42ec3ff5c12cab0c4bcd3c5694289 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 31 Mar 2022 19:17:27 +1100 Subject: [PATCH 088/137] feat: nodeManager is now startStop #322 --- src/nodes/NodeManager.ts | 15 +++++++++++++++ src/nodes/errors.ts | 6 ++++++ 2 files changed, 21 insertions(+) diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 8aa576e3f..ea800fcfb 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -9,6 +9,7 @@ import type { NodeId, NodeAddress, NodeBucket } from '../nodes/types'; import type { ClaimEncoded } from '../claims/types'; import type { Timer } from '../types'; import Logger from '@matrixai/logger'; +import { StartStop } from '@matrixai/async-init/dist/StartStop'; import * as nodesErrors from './errors'; import * as nodesUtils from './utils'; import * as networkUtils from '../network/utils'; @@ -18,6 +19,8 @@ import * as claimsErrors from '../claims/errors'; import * as sigchainUtils from '../sigchain/utils'; import * as claimsUtils from '../claims/utils'; +interface NodeManager extends StartStop {} +@StartStop() class NodeManager { protected db: DB; protected logger: Logger; @@ -49,6 +52,18 @@ class NodeManager { this.nodeGraph = nodeGraph; } + public async start() { + this.logger.info(`Starting ${this.constructor.name}`); + this.setNodeQueueRunner = this.startSetNodeQueue(); + this.logger.info(`Started ${this.constructor.name}`); + } + + public async stop() { + this.logger.info(`Stopping ${this.constructor.name}`); + await this.stopSetNodeQueue(); + this.logger.info(`Stopped ${this.constructor.name}`); + } + /** * Determines whether a node in the Polykey network is online. * @return true if online, false if offline diff --git a/src/nodes/errors.ts b/src/nodes/errors.ts index 83a5597d4..863e19a37 100644 --- a/src/nodes/errors.ts +++ b/src/nodes/errors.ts @@ -2,6 +2,11 @@ import { ErrorPolykey, sysexits } from '../errors'; class ErrorNodes extends ErrorPolykey {} +class ErrorNodeManagerNotRunning extends ErrorNodes { + static description = 'NodeManager is not running'; + exitCode = sysexits.USAGE; +} + class ErrorNodeGraphRunning extends ErrorNodes { static description = 'NodeGraph is running'; exitCode = sysexits.USAGE; @@ -74,6 +79,7 @@ class ErrorNodeConnectionHostWildcard extends ErrorNodes { export { ErrorNodes, + ErrorNodeManagerNotRunning, ErrorNodeGraphRunning, ErrorNodeGraphNotRunning, ErrorNodeGraphDestroyed, From 4460779c35c49f74da7863510b2dd0ceffa7ecf9 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 31 Mar 2022 19:23:22 +1100 Subject: [PATCH 089/137] feat: async queueing for setting nodes `setNode` now has a `blocking` flag that defaults to false. If it encounters a full bucket when adding a node then it will add the operation to the queue and asynchronously trys a blocking `setNode` in the background. `setNode`s will only be added to the queue if the bucket was full. #322 --- src/nodes/NodeGraph.ts | 15 +++ src/nodes/NodeManager.ts | 218 ++++++++++++++++++++++++++------ tests/nodes/NodeManager.test.ts | 193 +++++++++++++++++++++++++++- 3 files changed, 383 insertions(+), 43 deletions(-) diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index d6c6be1c6..d7437b389 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -230,6 +230,11 @@ class NodeGraph { nodesUtils.bucketDbKey(nodeId), ]); if (nodeData != null) { + this.logger.debug( + `Updating node ${nodesUtils.encodeNodeId( + nodeId, + )} in bucket ${bucketIndex}`, + ); // If the node already exists we want to remove the old `lastUpdated` const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( nodeData.lastUpdated, @@ -237,6 +242,11 @@ class NodeGraph { ); await tran.del([...lastUpdatedPath, lastUpdatedKey]); } else { + this.logger.debug( + `Adding node ${nodesUtils.encodeNodeId( + nodeId, + )} to bucket ${bucketIndex}`, + ); // It didn't exist so we want to increment the bucket count const count = await this.getBucketMetaProp(bucketIndex, 'count', tran); await this.setBucketMetaProp(bucketIndex, 'count', count + 1, tran); @@ -294,6 +304,11 @@ class NodeGraph { nodesUtils.bucketDbKey(nodeId), ]); if (nodeData != null) { + this.logger.debug( + `Removing node ${nodesUtils.encodeNodeId( + nodeId, + )} from bucket ${bucketIndex}`, + ); const count = await this.getBucketMetaProp(bucketIndex, 'count', tran); await this.setBucketMetaProp(bucketIndex, 'count', count - 1, tran); await tran.del([...bucketPath, nodesUtils.bucketDbKey(nodeId)]); diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index ea800fcfb..f94c5315d 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -9,7 +9,7 @@ import type { NodeId, NodeAddress, NodeBucket } from '../nodes/types'; import type { ClaimEncoded } from '../claims/types'; import type { Timer } from '../types'; import Logger from '@matrixai/logger'; -import { StartStop } from '@matrixai/async-init/dist/StartStop'; +import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; import * as nodesErrors from './errors'; import * as nodesUtils from './utils'; import * as networkUtils from '../network/utils'; @@ -18,6 +18,7 @@ import * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb'; import * as claimsErrors from '../claims/errors'; import * as sigchainUtils from '../sigchain/utils'; import * as claimsUtils from '../claims/utils'; +import { timerStart } from '../utils/utils'; interface NodeManager extends StartStop {} @StartStop() @@ -28,6 +29,18 @@ class NodeManager { protected keyManager: KeyManager; protected nodeConnectionManager: NodeConnectionManager; protected nodeGraph: NodeGraph; + // SetNodeQueue + protected endQueue: boolean = false; + protected setNodeQueue: Array<{ + nodeId: NodeId; + nodeAddress: NodeAddress; + timeout?: number; + }> = []; + protected setNodeQueuePlug: Promise; + protected setNodeQueueUnplug: (() => void) | undefined; + protected setNodeQueueRunner: Promise; + protected setNodeQueueEmpty: Promise; + protected setNodeQueueDrained: () => void; constructor({ db, @@ -365,16 +378,19 @@ class NodeManager { * Updates the node if the node already exists. * @param nodeId - Id of the node we wish to add * @param nodeAddress - Expected address of the node we want to add + * @param blocking - Flag for if the operation should block or utilize the async queue * @param force - Flag for if we want to add the node without authenticating or if the bucket is full. * This will drop the oldest node in favor of the new. - * @param timer Connection timeout timer + * @param timeout Connection timeout timeout * @param tran */ + @ready(new nodesErrors.ErrorNodeManagerNotRunning()) public async setNode( nodeId: NodeId, nodeAddress: NodeAddress, + blocking: boolean = false, force: boolean = false, - timer?: Timer, + timeout?: number, tran: DBTransaction, ): Promise { // When adding a node we need to handle 3 cases @@ -400,53 +416,87 @@ class NodeManager { } else { // We want to add a node but the bucket is full // We need to ping the oldest node - const oldestNodeIds = (await this.nodeGraph.getOldestNode( - bucketIndex, - 3, - tran, - ))!; if (force) { // We just add the new node anyway without checking the old one - const oldNodeId = oldestNodeIds[0]; + const oldNodeId = ( + await this.nodeGraph.getOldestNode(bucketIndex, 1, tran) + ).pop()!; + this.logger.debug( + `Force was set, removing ${nodesUtils.encodeNodeId( + oldNodeId, + )} and adding ${nodesUtils.encodeNodeId(nodeId)}`, + ); await this.nodeGraph.unsetNode(oldNodeId, tran); await this.nodeGraph.setNode(nodeId, nodeAddress, tran); return; } - // We want to concurrently ping the nodes - const pingPromises = oldestNodeIds.map((nodeId) => { - const doPing = async (): Promise<{ - nodeId: NodeId; - success: boolean; - }> => { - // This needs to return nodeId and ping result - const data = await this.nodeGraph.getNode(nodeId, tran); - if (data == null) return { nodeId, success: false }; - const result = await this.pingNode(nodeId, undefined, timer); - return { nodeId, success: result }; - }; - return doPing(); - }); - const pingResults = await Promise.all(pingPromises); - for (const { nodeId, success } of pingResults) { - if (success) { - // Ping succeeded, update the node - const node = (await this.nodeGraph.getNode(nodeId, tran))!; - await this.nodeGraph.setNode(nodeId, node.address, tran); - } else { - // Otherwise we remove the node - await this.nodeGraph.unsetNode(nodeId, tran); - } + if (blocking) { + this.logger.debug( + `Bucket was full and blocking was true, garbage collecting old nodes to add ${nodesUtils.encodeNodeId( + nodeId, + )}`, + ); + await this.garbageCollectOldNode( + bucketIndex, + nodeId, + nodeAddress, + timeout, + ); + } else { + this.logger.debug( + `Bucket was full and blocking was false, adding ${nodesUtils.encodeNodeId( + nodeId, + )} to queue`, + ); + // Re-attempt this later asynchronously by adding the the queue + this.queueSetNode(nodeId, nodeAddress, timeout); } - // Check if we now have room and add the new node - const count = await this.nodeGraph.getBucketMetaProp( - bucketIndex, - 'count', - tran, - ); - if (count < this.nodeGraph.nodeBucketLimit) { - await this.nodeGraph.setNode(nodeId, nodeAddress, tran); + } + } + + private async garbageCollectOldNode( + bucketIndex: number, + nodeId: NodeId, + nodeAddress: NodeAddress, + timeout?: number, + ) { + const oldestNodeIds = await this.nodeGraph.getOldestNode(bucketIndex, 3, tran); + // We want to concurrently ping the nodes + const pingPromises = oldestNodeIds.map((nodeId) => { + const doPing = async (): Promise<{ + nodeId: NodeId; + success: boolean; + }> => { + // This needs to return nodeId and ping result + const data = await this.nodeGraph.getNode(nodeId); + if (data == null) return { nodeId, success: false }; + const timer = timeout != null ? timerStart(timeout) : undefined; + const result = await this.pingNode(nodeId, nodeAddress, timer); + return { nodeId, success: result }; + }; + return doPing(); + }); + const pingResults = await Promise.all(pingPromises); + for (const { nodeId, success } of pingResults) { + if (success) { + // Ping succeeded, update the node + this.logger.debug( + `Ping succeeded for ${nodesUtils.encodeNodeId(nodeId)}`, + ); + const node = (await this.nodeGraph.getNode(nodeId))!; + await this.nodeGraph.setNode(nodeId, node.address); + } else { + this.logger.debug(`Ping failed for ${nodesUtils.encodeNodeId(nodeId)}`); + // Otherwise we remove the node + await this.nodeGraph.unsetNode(nodeId); } } + // Check if we now have room and add the new node + const count = await this.nodeGraph.getBucketMetaProp(bucketIndex, 'count'); + if (count < this.nodeGraph.nodeBucketLimit) { + this.logger.debug(`Bucket ${bucketIndex} now has room, adding new node`); + await this.nodeGraph.setNode(nodeId, nodeAddress); + } } /** @@ -473,6 +523,92 @@ class NodeManager { throw Error('fixme'); // Return await this.nodeGraph.refreshBuckets(tran); } + + // SetNode queue + + /** + * This adds a setNode operation to the queue + */ + private queueSetNode( + nodeId: NodeId, + nodeAddress: NodeAddress, + timeout?: number, + ): void { + this.logger.debug(`Adding ${nodesUtils.encodeNodeId(nodeId)} to queue`); + this.setNodeQueue.push({ + nodeId, + nodeAddress, + timeout, + }); + this.unplugQueue(); + } + + /** + * This starts the process of digesting the queue + */ + private async startSetNodeQueue(): Promise { + this.logger.debug('Starting setNodeQueue'); + this.plugQueue(); + // While queue hasn't ended + while (true) { + // Wait for queue to be unplugged + await this.setNodeQueuePlug; + if (this.endQueue) break; + const job = this.setNodeQueue.shift(); + if (job == null) { + // If the queue is empty then we pause the queue + this.plugQueue(); + continue; + } + // Process the job + this.logger.debug( + `SetNodeQueue processing job for: ${nodesUtils.encodeNodeId( + job.nodeId, + )}`, + ); + await this.setNode(job.nodeId, job.nodeAddress, true, false, job.timeout); + } + this.logger.debug('SetNodeQueue has ended'); + } + + private async stopSetNodeQueue(): Promise { + this.logger.debug('Stopping setNodeQueue'); + // Tell the queue runner to end + this.endQueue = true; + this.unplugQueue(); + // Wait for runner to finish it's current job + await this.setNodeQueueRunner; + } + + private plugQueue(): void { + if (this.setNodeQueueUnplug == null) { + this.logger.debug('Plugging setNodeQueue'); + // Pausing queue + this.setNodeQueuePlug = new Promise((resolve) => { + this.setNodeQueueUnplug = resolve; + }); + // Signaling queue is empty + if (this.setNodeQueueDrained != null) this.setNodeQueueDrained(); + } + } + + private unplugQueue(): void { + if (this.setNodeQueueUnplug != null) { + this.logger.debug('Unplugging setNodeQueue'); + // Starting queue + this.setNodeQueueUnplug(); + this.setNodeQueueUnplug = undefined; + // Signalling queue is running + this.setNodeQueueEmpty = new Promise((resolve) => { + this.setNodeQueueDrained = resolve; + }); + } + } + + @ready(new nodesErrors.ErrorNodeManagerNotRunning()) + public async queueDrained(): Promise { + await this.setNodeQueueEmpty; + } } export default NodeManager; diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index da7451d99..4e4c2f62b 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -16,14 +16,15 @@ import NodeManager from '@/nodes/NodeManager'; import Proxy from '@/network/Proxy'; import Sigchain from '@/sigchain/Sigchain'; import * as claimsUtils from '@/claims/utils'; -import { promisify, sleep } from '@/utils'; +import { promise, promisify, sleep } from '@/utils'; import * as nodesUtils from '@/nodes/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as nodesTestUtils from './utils'; +import { generateNodeIdForBucket } from './utils'; describe(`${NodeManager.name} test`, () => { const password = 'password'; - const logger = new Logger(`${NodeManager.name} test`, LogLevel.WARN, [ + const logger = new Logger(`${NodeManager.name} test`, LogLevel.DEBUG, [ new StreamHandler(), ]); let dataDir: string; @@ -39,14 +40,22 @@ describe(`${NodeManager.name} test`, () => { const serverHost = '::1' as Host; const externalHost = '127.0.0.1' as Host; + const localhost = '127.0.0.1' as Host; + const port = 55556 as Port; const serverPort = 0 as Port; const externalPort = 0 as Port; const mockedGenerateDeterministicKeyPair = jest.spyOn( keysUtils, 'generateDeterministicKeyPair', ); + const mockedPingNode = jest.fn(); // Jest.spyOn(NodeManager.prototype, 'pingNode'); + const dummyNodeConnectionManager = { + pingNode: mockedPingNode, + } as unknown as NodeConnectionManager; beforeEach(async () => { + mockedPingNode.mockClear(); + mockedPingNode.mockImplementation(async (_) => true); mockedGenerateDeterministicKeyPair.mockImplementation((bits, _) => { return keysUtils.generateKeyPair(bits); }); @@ -110,6 +119,8 @@ describe(`${NodeManager.name} test`, () => { await nodeConnectionManager.start(); }); afterEach(async () => { + mockedPingNode.mockClear(); + mockedPingNode.mockImplementation(async (_) => true); await nodeConnectionManager.stop(); await nodeGraph.stop(); await nodeGraph.destroy(); @@ -646,4 +657,182 @@ describe(`${NodeManager.name} test`, () => { await server?.destroy(); } }); + test('should not add nodes to full bucket if pings succeeds', async () => { + const tempNodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + mockedPingNode.mockImplementation(async (_) => true); + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph: tempNodeGraph, + nodeConnectionManager: dummyNodeConnectionManager, + logger, + }); + await nodeManager.start(); + const nodeId = keyManager.getNodeId(); + const address = { host: localhost, port }; + // Let's fill a bucket + for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { + const newNode = generateNodeIdForBucket(nodeId, 100, i); + await nodeManager.setNode(newNode, address); + } + + // Helpers + const listBucket = async (bucketIndex: number) => { + const bucket = await nodeManager.getBucket(bucketIndex); + return bucket?.map(([nodeId]) => nodesUtils.encodeNodeId(nodeId)); + }; + + // Pings succeed, node not added + mockedPingNode.mockImplementation(async (_) => true); + const newNode = generateNodeIdForBucket(nodeId, 100, 21); + await nodeManager.setNode(newNode, address); + expect(await listBucket(100)).not.toContain( + nodesUtils.encodeNodeId(newNode), + ); + + // Clean up + await nodeManager.queueDrained(); + await nodeManager.stop(); + await tempNodeGraph.stop(); + await tempNodeGraph.destroy(); + }); + test('should add nodes to full bucket if pings fail', async () => { + const tempNodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + mockedPingNode.mockImplementation(async (_) => true); + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph: tempNodeGraph, + nodeConnectionManager: dummyNodeConnectionManager, + logger, + }); + await nodeManager.start(); + const nodeId = keyManager.getNodeId(); + const address = { host: localhost, port }; + // Let's fill a bucket + for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { + const newNode = generateNodeIdForBucket(nodeId, 100, i); + await nodeManager.setNode(newNode, address); + } + + // Helpers + const listBucket = async (bucketIndex: number) => { + const bucket = await nodeManager.getBucket(bucketIndex); + return bucket?.map(([nodeId]) => nodesUtils.encodeNodeId(nodeId)); + }; + + // Pings fail, new nodes get added + mockedPingNode.mockImplementation(async (_) => false); + const newNode1 = generateNodeIdForBucket(nodeId, 100, 22); + const newNode2 = generateNodeIdForBucket(nodeId, 100, 23); + const newNode3 = generateNodeIdForBucket(nodeId, 100, 24); + await nodeManager.setNode(newNode1, address); + await nodeManager.setNode(newNode2, address); + await nodeManager.setNode(newNode3, address); + await nodeManager.queueDrained(); + const list = await listBucket(100); + expect(list).toContain(nodesUtils.encodeNodeId(newNode1)); + expect(list).toContain(nodesUtils.encodeNodeId(newNode2)); + expect(list).toContain(nodesUtils.encodeNodeId(newNode3)); + + // Clean up + await nodeManager.queueDrained(); + await nodeManager.stop(); + await tempNodeGraph.stop(); + await tempNodeGraph.destroy(); + }); + test('should not block when bucket is full', async () => { + const tempNodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + mockedPingNode.mockImplementation(async (_) => true); + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph: tempNodeGraph, + nodeConnectionManager: dummyNodeConnectionManager, + logger, + }); + await nodeManager.start(); + const nodeId = keyManager.getNodeId(); + const address = { host: localhost, port }; + // Let's fill a bucket + for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { + const newNode = generateNodeIdForBucket(nodeId, 100, i); + await nodeManager.setNode(newNode, address); + } + + // Set node does not block + const delayPing = promise(); + mockedPingNode.mockImplementation(async (_) => { + await delayPing.p; + return true; + }); + const newNode4 = generateNodeIdForBucket(nodeId, 100, 25); + await expect( + nodeManager.setNode(newNode4, address), + ).resolves.toBeUndefined(); + delayPing.resolveP(null); + await nodeManager.queueDrained(); + + // Clean up + await nodeManager.queueDrained(); + await nodeManager.stop(); + await tempNodeGraph.stop(); + await tempNodeGraph.destroy(); + }); + test('should block when blocking is set to true', async () => { + const tempNodeGraph = await NodeGraph.createNodeGraph({ + db, + keyManager, + logger, + }); + mockedPingNode.mockImplementation(async (_) => true); + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph: tempNodeGraph, + nodeConnectionManager: dummyNodeConnectionManager, + logger, + }); + await nodeManager.start(); + const nodeId = keyManager.getNodeId(); + const address = { host: localhost, port }; + // Let's fill a bucket + for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { + const newNode = generateNodeIdForBucket(nodeId, 100, i); + await nodeManager.setNode(newNode, address); + } + + // Set node can block + mockedPingNode.mockClear(); + mockedPingNode.mockImplementation(async (_) => { + return true; + }); + const newNode5 = generateNodeIdForBucket(nodeId, 100, 25); + await expect( + nodeManager.setNode(newNode5, address, true), + ).resolves.toBeUndefined(); + expect(mockedPingNode).toBeCalled(); + + // CLean up + await nodeManager.queueDrained(); + await nodeManager.stop(); + await tempNodeGraph.stop(); + await tempNodeGraph.destroy(); + }); }); From aa7c4bcefb356d2eb43f7dd49024ee1b770b8ff2 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 7 Apr 2022 17:04:08 +1000 Subject: [PATCH 090/137] feat: establishing a `NodeConnection` adds the node to the nodeGraph `NodeConnectionManager` now takes `NodeGraph` in the `nodeConnectionManager.start` method. It has to be part of the start method since they are co-dependent. `NodeConnectionManager` cals `NodeManager.setNode()` when a connection is established. This fulfills the condition of adding a node to the graph during a forward connection. Fixed up tests that were failing in relation to the `NodeManager` `StartStop` conversion. #322 --- src/PolykeyAgent.ts | 5 +- src/nodes/NodeConnectionManager.ts | 10 +- tests/agent/GRPCClientAgent.test.ts | 4 +- tests/agent/service/notificationsSend.test.ts | 3 +- .../gestaltsDiscoveryByIdentity.test.ts | 4 +- .../service/gestaltsDiscoveryByNode.test.ts | 4 +- .../gestaltsGestaltTrustByIdentity.test.ts | 4 +- .../gestaltsGestaltTrustByNode.test.ts | 4 +- tests/client/service/identitiesClaim.test.ts | 4 +- tests/client/service/nodesAdd.test.ts | 3 +- tests/client/service/nodesClaim.test.ts | 3 +- tests/client/service/nodesFind.test.ts | 3 +- tests/client/service/nodesPing.test.ts | 2 +- .../client/service/notificationsClear.test.ts | 3 +- .../client/service/notificationsRead.test.ts | 3 +- .../client/service/notificationsSend.test.ts | 3 +- tests/discovery/Discovery.test.ts | 4 +- tests/nodes/NodeConnection.test.ts | 5 +- .../NodeConnectionManager.general.test.ts | 14 +- .../NodeConnectionManager.lifecycle.test.ts | 130 +---- .../NodeConnectionManager.seednodes.test.ts | 10 +- .../NodeConnectionManager.termination.test.ts | 20 +- .../NodeConnectionManager.timeout.test.ts | 8 +- tests/nodes/NodeManager.test.ts | 501 +++++++++--------- .../NotificationsManager.test.ts | 3 +- tests/vaults/VaultManager.test.ts | 15 +- 26 files changed, 385 insertions(+), 387 deletions(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index 792a8778b..ddc7ca2cd 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -301,6 +301,7 @@ class PolykeyAgent { nodeConnectionManager, logger: logger.getChild(NodeManager.name), }); + await nodeManager.start(); discovery = discovery ?? (await Discovery.createDiscovery({ @@ -646,7 +647,8 @@ class PolykeyAgent { proxyPort: networkConfig_.proxyPort, tlsConfig, }); - await this.nodeConnectionManager.start(); + await this.nodeManager.start(); + await this.nodeConnectionManager.start({ nodeManager: this.nodeManager }); await this.nodeGraph.start({ fresh }); await this.nodeConnectionManager.syncNodeGraph(); await this.discovery.start({ fresh }); @@ -701,6 +703,7 @@ class PolykeyAgent { await this.discovery.stop(); await this.nodeConnectionManager.stop(); await this.nodeGraph.stop(); + await this.nodeManager.stop(); await this.proxy.stop(); await this.grpcServerAgent.stop(); await this.grpcServerClient.stop(); diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 43f703988..544fd5687 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -15,6 +15,7 @@ import type { NodeIdString, } from './types'; import { withF } from '@matrixai/resources'; +import type NodeManager from './NodeManager'; import Logger from '@matrixai/logger'; import { ready, StartStop } from '@matrixai/async-init/dist/StartStop'; import { IdInternal } from '@matrixai/id'; @@ -58,6 +59,8 @@ class NodeConnectionManager { protected nodeGraph: NodeGraph; protected keyManager: KeyManager; protected proxy: Proxy; + // NodeManager has to be passed in during start to allow co-dependency + protected nodeManager: NodeManager | undefined; protected seedNodes: SeedNodes; /** * Data structure to store all NodeConnections. If a connection to a node n does @@ -101,8 +104,9 @@ class NodeConnectionManager { this.connTimeoutTime = connTimeoutTime; } - public async start() { + public async start({ nodeManager }: { nodeManager: NodeManager }) { this.logger.info(`Starting ${this.constructor.name}`); + this.nodeManager = nodeManager; for (const nodeIdEncoded in this.seedNodes) { const nodeId = nodesUtils.decodeNodeId(nodeIdEncoded)!; await this.nodeGraph.setNode(nodeId, this.seedNodes[nodeIdEncoded]); // FIXME: also fine implicit transactions @@ -112,6 +116,7 @@ class NodeConnectionManager { public async stop() { this.logger.info(`Stopping ${this.constructor.name}`); + this.nodeManager = undefined; for (const [nodeId, connAndLock] of this.connections) { if (connAndLock == null) continue; if (connAndLock.connection == null) continue; @@ -293,6 +298,9 @@ class NodeConnectionManager { clientFactory: async (args) => GRPCClientAgent.createGRPCClientAgent(args), }); + // We can assume connection was established and destination was valid, + // we can add the target to the nodeGraph + await this.nodeManager?.setNode(targetNodeId, targetAddress); // Creating TTL timeout const timeToLiveTimer = setTimeout(async () => { await this.destroyConnection(targetNodeId); diff --git a/tests/agent/GRPCClientAgent.test.ts b/tests/agent/GRPCClientAgent.test.ts index 89c9ec9d7..5cc38708a 100644 --- a/tests/agent/GRPCClientAgent.test.ts +++ b/tests/agent/GRPCClientAgent.test.ts @@ -116,7 +116,6 @@ describe(GRPCClientAgent.name, () => { proxy, logger, }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db: db, sigchain: sigchain, @@ -125,6 +124,8 @@ describe(GRPCClientAgent.name, () => { nodeConnectionManager: nodeConnectionManager, logger: logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); notificationsManager = await NotificationsManager.createNotificationsManager({ acl: acl, @@ -176,6 +177,7 @@ describe(GRPCClientAgent.name, () => { await notificationsManager.stop(); await sigchain.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await nodeGraph.stop(); await gestaltGraph.stop(); await acl.stop(); diff --git a/tests/agent/service/notificationsSend.test.ts b/tests/agent/service/notificationsSend.test.ts index c0b79e91c..46a9aa07e 100644 --- a/tests/agent/service/notificationsSend.test.ts +++ b/tests/agent/service/notificationsSend.test.ts @@ -117,7 +117,6 @@ describe('notificationsSend', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -126,6 +125,8 @@ describe('notificationsSend', () => { sigchain, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); notificationsManager = await NotificationsManager.createNotificationsManager({ acl, diff --git a/tests/client/service/gestaltsDiscoveryByIdentity.test.ts b/tests/client/service/gestaltsDiscoveryByIdentity.test.ts index 2c314711b..a9a4d7a17 100644 --- a/tests/client/service/gestaltsDiscoveryByIdentity.test.ts +++ b/tests/client/service/gestaltsDiscoveryByIdentity.test.ts @@ -133,7 +133,6 @@ describe('gestaltsDiscoveryByIdentity', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -142,6 +141,8 @@ describe('gestaltsDiscoveryByIdentity', () => { sigchain, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); discovery = await Discovery.createDiscovery({ db, keyManager, @@ -177,6 +178,7 @@ describe('gestaltsDiscoveryByIdentity', () => { await discovery.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await sigchain.stop(); await proxy.stop(); await identitiesManager.stop(); diff --git a/tests/client/service/gestaltsDiscoveryByNode.test.ts b/tests/client/service/gestaltsDiscoveryByNode.test.ts index e553a0693..e34f5f8ed 100644 --- a/tests/client/service/gestaltsDiscoveryByNode.test.ts +++ b/tests/client/service/gestaltsDiscoveryByNode.test.ts @@ -134,7 +134,6 @@ describe('gestaltsDiscoveryByNode', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -143,6 +142,8 @@ describe('gestaltsDiscoveryByNode', () => { sigchain, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); discovery = await Discovery.createDiscovery({ db, keyManager, @@ -178,6 +179,7 @@ describe('gestaltsDiscoveryByNode', () => { await discovery.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await sigchain.stop(); await proxy.stop(); await identitiesManager.stop(); diff --git a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts index ec38cc41d..949a5f5e4 100644 --- a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts +++ b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts @@ -199,7 +199,6 @@ describe('gestaltsGestaltTrustByIdentity', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -208,6 +207,8 @@ describe('gestaltsGestaltTrustByIdentity', () => { nodeConnectionManager, logger: logger.getChild('nodeManager'), }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); await nodeManager.setNode(nodesUtils.decodeNodeId(nodeId)!, { host: node.proxy.getProxyHost(), port: node.proxy.getProxyPort(), @@ -248,6 +249,7 @@ describe('gestaltsGestaltTrustByIdentity', () => { await grpcServer.stop(); await discovery.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await nodeGraph.stop(); await proxy.stop(); await sigchain.stop(); diff --git a/tests/client/service/gestaltsGestaltTrustByNode.test.ts b/tests/client/service/gestaltsGestaltTrustByNode.test.ts index 1c1ad87b0..d8ecae06e 100644 --- a/tests/client/service/gestaltsGestaltTrustByNode.test.ts +++ b/tests/client/service/gestaltsGestaltTrustByNode.test.ts @@ -198,7 +198,6 @@ describe('gestaltsGestaltTrustByNode', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -207,6 +206,8 @@ describe('gestaltsGestaltTrustByNode', () => { nodeConnectionManager, logger: logger.getChild('nodeManager'), }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); await nodeManager.setNode(nodesUtils.decodeNodeId(nodeId)!, { host: node.proxy.getProxyHost(), port: node.proxy.getProxyPort(), @@ -247,6 +248,7 @@ describe('gestaltsGestaltTrustByNode', () => { await grpcServer.stop(); await discovery.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await nodeGraph.stop(); await proxy.stop(); await sigchain.stop(); diff --git a/tests/client/service/identitiesClaim.test.ts b/tests/client/service/identitiesClaim.test.ts index 39535394a..f03e1be07 100644 --- a/tests/client/service/identitiesClaim.test.ts +++ b/tests/client/service/identitiesClaim.test.ts @@ -2,6 +2,7 @@ import type { ClaimLinkIdentity } from '@/claims/types'; import type { NodeIdEncoded } from '@/nodes/types'; import type { IdentityId, ProviderId } from '@/identities/types'; import type { Host, Port } from '@/network/types'; +import type NodeManager from '@/nodes/NodeManager'; import fs from 'fs'; import path from 'path'; import os from 'os'; @@ -55,6 +56,7 @@ describe('identitiesClaim', () => { let mockedGenerateKeyPair: jest.SpyInstance; let mockedGenerateDeterministicKeyPair: jest.SpyInstance; let mockedAddClaim: jest.SpyInstance; + const dummyNodeManager = { setNode: jest.fn() } as unknown as NodeManager; beforeAll(async () => { const globalKeyPair = await testUtils.setupGlobalKeypair(); const claim = await claimsUtils.createClaim({ @@ -142,7 +144,7 @@ describe('identitiesClaim', () => { nodeGraph, logger: logger.getChild('nodeConnectionManager'), }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); const clientService = { identitiesClaim: identitiesClaim({ authenticate, diff --git a/tests/client/service/nodesAdd.test.ts b/tests/client/service/nodesAdd.test.ts index e0a07e171..94d925acc 100644 --- a/tests/client/service/nodesAdd.test.ts +++ b/tests/client/service/nodesAdd.test.ts @@ -104,7 +104,6 @@ describe('nodesAdd', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -113,6 +112,8 @@ describe('nodesAdd', () => { sigchain, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); const clientService = { nodesAdd: nodesAdd({ authenticate, diff --git a/tests/client/service/nodesClaim.test.ts b/tests/client/service/nodesClaim.test.ts index bc04e2ae6..47102fe1a 100644 --- a/tests/client/service/nodesClaim.test.ts +++ b/tests/client/service/nodesClaim.test.ts @@ -134,7 +134,6 @@ describe('nodesClaim', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -143,6 +142,8 @@ describe('nodesClaim', () => { nodeConnectionManager, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); notificationsManager = await NotificationsManager.createNotificationsManager({ acl, diff --git a/tests/client/service/nodesFind.test.ts b/tests/client/service/nodesFind.test.ts index b01e157a1..21372cb4c 100644 --- a/tests/client/service/nodesFind.test.ts +++ b/tests/client/service/nodesFind.test.ts @@ -1,4 +1,5 @@ import type { Host, Port } from '@/network/types'; +import type NodeManager from '@/nodes/NodeManager'; import fs from 'fs'; import path from 'path'; import os from 'os'; @@ -108,7 +109,7 @@ describe('nodesFind', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: {} as NodeManager }); const clientService = { nodesFind: nodesFind({ authenticate, diff --git a/tests/client/service/nodesPing.test.ts b/tests/client/service/nodesPing.test.ts index d4954bb4a..6fd489d36 100644 --- a/tests/client/service/nodesPing.test.ts +++ b/tests/client/service/nodesPing.test.ts @@ -109,7 +109,6 @@ describe('nodesPing', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -118,6 +117,7 @@ describe('nodesPing', () => { sigchain, logger, }); + await nodeConnectionManager.start({ nodeManager }); const clientService = { nodesPing: nodesPing({ authenticate, diff --git a/tests/client/service/notificationsClear.test.ts b/tests/client/service/notificationsClear.test.ts index d8572c584..c2a1c5cd3 100644 --- a/tests/client/service/notificationsClear.test.ts +++ b/tests/client/service/notificationsClear.test.ts @@ -113,7 +113,6 @@ describe('notificationsClear', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -122,6 +121,8 @@ describe('notificationsClear', () => { sigchain, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); notificationsManager = await NotificationsManager.createNotificationsManager({ acl, diff --git a/tests/client/service/notificationsRead.test.ts b/tests/client/service/notificationsRead.test.ts index d78bb5eaa..24b8b9542 100644 --- a/tests/client/service/notificationsRead.test.ts +++ b/tests/client/service/notificationsRead.test.ts @@ -188,7 +188,6 @@ describe('notificationsRead', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -197,6 +196,8 @@ describe('notificationsRead', () => { sigchain, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); notificationsManager = await NotificationsManager.createNotificationsManager({ acl, diff --git a/tests/client/service/notificationsSend.test.ts b/tests/client/service/notificationsSend.test.ts index 7709f7b47..220edfe83 100644 --- a/tests/client/service/notificationsSend.test.ts +++ b/tests/client/service/notificationsSend.test.ts @@ -122,7 +122,6 @@ describe('notificationsSend', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -131,6 +130,8 @@ describe('notificationsSend', () => { sigchain, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); notificationsManager = await NotificationsManager.createNotificationsManager({ acl, diff --git a/tests/discovery/Discovery.test.ts b/tests/discovery/Discovery.test.ts index 1b6e0e120..da9acd92b 100644 --- a/tests/discovery/Discovery.test.ts +++ b/tests/discovery/Discovery.test.ts @@ -138,7 +138,6 @@ describe('Discovery', () => { connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -147,6 +146,8 @@ describe('Discovery', () => { nodeConnectionManager, logger: logger.getChild('nodeManager'), }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); // Set up other gestalt nodeA = await PolykeyAgent.createPolykeyAgent({ password: password, @@ -202,6 +203,7 @@ describe('Discovery', () => { await nodeA.stop(); await nodeB.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await nodeGraph.stop(); await proxy.stop(); await sigchain.stop(); diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index 5ef4ed470..35c084fa9 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -237,8 +237,6 @@ describe('${NodeConnection.name} test', () => { proxy: serverProxy, logger, }); - await serverNodeConnectionManager.start(); - serverNodeManager = new NodeManager({ db: serverDb, sigchain: serverSigchain, @@ -247,6 +245,8 @@ describe('${NodeConnection.name} test', () => { nodeConnectionManager: serverNodeConnectionManager, logger: logger, }); + await serverNodeManager.start(); + await serverNodeConnectionManager.start({ nodeManager: serverNodeManager }); serverVaultManager = await VaultManager.createVaultManager({ keyManager: serverKeyManager, vaultsPath: serverVaultsPath, @@ -355,6 +355,7 @@ describe('${NodeConnection.name} test', () => { await serverNodeGraph.stop(); await serverNodeGraph.destroy(); await serverNodeConnectionManager.stop(); + await serverNodeManager.stop(); await serverNotificationsManager.stop(); await serverNotificationsManager.destroy(); await agentTestUtils.closeTestAgentServer(agentServer); diff --git a/tests/nodes/NodeConnectionManager.general.test.ts b/tests/nodes/NodeConnectionManager.general.test.ts index d13c838de..6231e5dcc 100644 --- a/tests/nodes/NodeConnectionManager.general.test.ts +++ b/tests/nodes/NodeConnectionManager.general.test.ts @@ -1,5 +1,6 @@ import type { NodeAddress, NodeBucket, NodeId, SeedNodes } from '@/nodes/types'; import type { Host, Port } from '@/network/types'; +import type NodeManager from '@/nodes/NodeManager'; import fs from 'fs'; import path from 'path'; import os from 'os'; @@ -124,6 +125,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keysUtils, 'generateDeterministicKeyPair', ); + const dummyNodeManager = { setNode: jest.fn() } as unknown as NodeManager; beforeAll(async () => { mockedGenerateDeterministicKeyPair.mockImplementation((bits, _) => { @@ -232,7 +234,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); try { // Case 1: node already exists in the local node graph (no contact required) const nodeId = nodeId1; @@ -259,7 +261,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); try { // Case 2: node can be found on the remote node const nodeId = nodeId1; @@ -300,7 +302,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); try { // Case 3: node exhausts all contacts and cannot find node const nodeId = nodeId1; @@ -354,7 +356,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { logger: logger.getChild('NodeConnectionManager'), }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); const targetNodeId = serverPKAgent.keyManager.getNodeId(); await nodeGraph.setNode(targetNodeId, { host: serverPKAgent.proxy.getProxyHost(), @@ -424,7 +426,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // To test this we need to... // 2. call relayHolePunchMessage // 3. check that the relevant call was made. @@ -461,7 +463,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // To test this we need to... // 2. call relayHolePunchMessage // 3. check that the relevant call was made. diff --git a/tests/nodes/NodeConnectionManager.lifecycle.test.ts b/tests/nodes/NodeConnectionManager.lifecycle.test.ts index 5871fa4d3..979403ec3 100644 --- a/tests/nodes/NodeConnectionManager.lifecycle.test.ts +++ b/tests/nodes/NodeConnectionManager.lifecycle.test.ts @@ -1,10 +1,6 @@ -import type { - NodeAddress, - NodeId, - NodeIdString, - SeedNodes, -} from '@/nodes/types'; +import type { NodeId, NodeIdString, SeedNodes } from '@/nodes/types'; import type { Host, Port } from '@/network/types'; +import type NodeManager from 'nodes/NodeManager'; import fs from 'fs'; import path from 'path'; import os from 'os'; @@ -91,6 +87,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keysUtils, 'generateDeterministicKeyPair', ); + const dummyNodeManager = { setNode: jest.fn() } as unknown as NodeManager; beforeAll(async () => { mockedGenerateDeterministicKeyPair.mockImplementation((bits, _) => { @@ -202,7 +199,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; // @ts-ignore: kidnap connectionLocks @@ -227,7 +224,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; // @ts-ignore: kidnap connectionLocks @@ -261,7 +258,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; // @ts-ignore: kidnap connectionLocks @@ -289,7 +286,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; @@ -342,7 +339,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { connConnectTime: 500, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // Add the dummy node await nodeGraph.setNode(dummyNodeId, { host: '125.0.0.1' as Host, @@ -382,7 +379,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore accessing protected NodeConnectionMap const connections = nodeConnectionManager.connections; expect(connections.size).toBe(0); @@ -408,7 +405,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore accessing protected NodeConnectionMap const connections = nodeConnectionManager.connections; // @ts-ignore: kidnap connectionLocks @@ -441,7 +438,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; // @ts-ignore: kidnap connectionLocks @@ -474,7 +471,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // Do testing // set up connections await nodeConnectionManager.withConnF(remoteNodeId1, nop); @@ -506,32 +503,6 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { }); // New ping tests - test('should ping node', async () => { - // NodeConnectionManager under test - let nodeConnectionManager: NodeConnectionManager | undefined; - try { - nodeConnectionManager = new NodeConnectionManager({ - keyManager, - nodeGraph, - proxy, - logger: nodeConnectionManagerLogger, - }); - await nodeConnectionManager.start(); - // @ts-ignore: kidnap connections - const connections = nodeConnectionManager.connections; - await expect(nodeConnectionManager.pingNode(remoteNodeId1)).resolves.toBe( - true, - ); - const finalConnLock = connections.get( - remoteNodeId1.toString() as NodeIdString, - ); - // Check entry is in map and lock is released - expect(finalConnLock).toBeDefined(); - expect(finalConnLock?.lock.isLocked()).toBeFalsy(); - } finally { - await nodeConnectionManager?.stop(); - } - }); test('should ping node with address', async () => { // NodeConnectionManager under test let nodeConnectionManager: NodeConnectionManager | undefined; @@ -542,33 +513,12 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); - const remoteNodeAddress1: NodeAddress = { - host: remoteNode1.proxy.getProxyHost(), - port: remoteNode1.proxy.getProxyPort(), - }; - await nodeConnectionManager.pingNode(remoteNodeId1, remoteNodeAddress1); - } finally { - await nodeConnectionManager?.stop(); - } - }); - test('should ping node with address when connection exists', async () => { - // NodeConnectionManager under test - let nodeConnectionManager: NodeConnectionManager | undefined; - try { - nodeConnectionManager = new NodeConnectionManager({ - keyManager, - nodeGraph, - proxy, - logger: nodeConnectionManagerLogger, - }); - await nodeConnectionManager.start(); - const remoteNodeAddress1: NodeAddress = { - host: remoteNode1.proxy.getProxyHost(), - port: remoteNode1.proxy.getProxyPort(), - }; - await nodeConnectionManager.withConnF(remoteNodeId1, nop); - await nodeConnectionManager.pingNode(remoteNodeId1, remoteNodeAddress1); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); + await nodeConnectionManager.pingNode( + remoteNodeId1, + remoteNode1.proxy.getProxyHost(), + remoteNode1.proxy.getProxyPort(), + ); } finally { await nodeConnectionManager?.stop(); } @@ -583,36 +533,14 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // Pinging node expect( await nodeConnectionManager.pingNode( remoteNodeId1, - { host: '127.1.2.3' as Host, port: 55555 as Port }, - timerStart(1000), - ), - ).toEqual(false); - } finally { - await nodeConnectionManager?.stop(); - } - }); - test('should fail to ping node with wrong address when connection exists', async () => { - // NodeConnectionManager under test - let nodeConnectionManager: NodeConnectionManager | undefined; - try { - nodeConnectionManager = new NodeConnectionManager({ - keyManager, - nodeGraph, - proxy, - logger: nodeConnectionManagerLogger, - }); - await nodeConnectionManager.start(); - await nodeConnectionManager.withConnF(remoteNodeId1, nop); - expect( - await nodeConnectionManager.pingNode( - remoteNodeId1, - { host: '127.1.2.3' as Host, port: 55555 as Port }, + '127.1.2.3' as Host, + 55555 as Port, timerStart(1000), ), ).toEqual(false); @@ -630,20 +558,13 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); - const remoteNodeAddress1: NodeAddress = { - host: remoteNode1.proxy.getProxyHost(), - port: remoteNode1.proxy.getProxyPort(), - }; - const remoteNodeAddress2: NodeAddress = { - host: remoteNode2.proxy.getProxyHost(), - port: remoteNode2.proxy.getProxyPort(), - }; + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); expect( await nodeConnectionManager.pingNode( remoteNodeId1, - remoteNodeAddress2, + remoteNode2.proxy.getProxyHost(), + remoteNode2.proxy.getProxyPort(), timerStart(1000), ), ).toEqual(false); @@ -651,7 +572,8 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { expect( await nodeConnectionManager.pingNode( remoteNodeId2, - remoteNodeAddress1, + remoteNode1.proxy.getProxyHost(), + remoteNode1.proxy.getProxyPort(), timerStart(1000), ), ).toEqual(false); diff --git a/tests/nodes/NodeConnectionManager.seednodes.test.ts b/tests/nodes/NodeConnectionManager.seednodes.test.ts index b5ecf3e3c..ec7d6ee44 100644 --- a/tests/nodes/NodeConnectionManager.seednodes.test.ts +++ b/tests/nodes/NodeConnectionManager.seednodes.test.ts @@ -1,5 +1,6 @@ import type { NodeId, SeedNodes } from '@/nodes/types'; import type { Host, Port } from '@/network/types'; +import type NodeManager from 'nodes/NodeManager'; import fs from 'fs'; import path from 'path'; import os from 'os'; @@ -77,6 +78,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { keysUtils, 'generateDeterministicKeyPair', ); + const dummyNodeManager = { setNode: jest.fn() } as unknown as NodeManager; beforeAll(async () => { mockedGenerateDeterministicKeyPair.mockImplementation((bits, _) => { @@ -187,7 +189,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { seedNodes: dummySeedNodes, logger: logger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); const seedNodes = nodeConnectionManager.getSeedNodes(); expect(seedNodes).toContainEqual(nodeId1); expect(seedNodes).toContainEqual(nodeId2); @@ -210,7 +212,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { seedNodes: dummySeedNodes, logger: logger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); try { const seedNodes = nodeConnectionManager.getSeedNodes(); expect(seedNodes).toHaveLength(3); @@ -248,7 +250,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { host: serverHost, port: serverPort, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); await nodeConnectionManager.syncNodeGraph(); expect(await nodeGraph.getNode(nodeId1)).toBeDefined(); expect(await nodeGraph.getNode(nodeId2)).toBeDefined(); @@ -290,7 +292,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { connConnectTime: 500, logger: logger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // This should complete without error await nodeConnectionManager.syncNodeGraph(); // Information on remotes are found diff --git a/tests/nodes/NodeConnectionManager.termination.test.ts b/tests/nodes/NodeConnectionManager.termination.test.ts index 3fa14f66c..0422cf223 100644 --- a/tests/nodes/NodeConnectionManager.termination.test.ts +++ b/tests/nodes/NodeConnectionManager.termination.test.ts @@ -1,6 +1,7 @@ import type { AddressInfo } from 'net'; import type { NodeId, NodeIdString, SeedNodes } from '@/nodes/types'; import type { Host, Port, TLSConfig } from '@/network/types'; +import type NodeManager from '@/nodes/NodeManager'; import net from 'net'; import fs from 'fs'; import path from 'path'; @@ -85,6 +86,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keysUtils, 'generateDeterministicKeyPair', ); + const dummyNodeManager = { setNode: jest.fn() } as unknown as NodeManager; beforeEach(async () => { mockedGenerateDeterministicKeyPair.mockImplementation((bits, _) => { @@ -247,7 +249,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { logger: logger, connConnectTime: 2000, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // Attempt a connection await expect( @@ -287,7 +289,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { logger: logger, connConnectTime: 2000, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // Attempt a connection const resultP = nodeConnectionManager.withConnF(dummyNodeId, async () => { @@ -330,7 +332,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { logger: logger, connConnectTime: 2000, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // Attempt a connection const connectionAttemptP = nodeConnectionManager.withConnF( @@ -373,7 +375,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { logger: logger, connConnectTime: 2000, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; @@ -430,7 +432,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { logger: logger, connConnectTime: 2000, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; @@ -509,7 +511,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { logger: logger, connConnectTime: 2000, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; @@ -581,7 +583,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { logger: logger, connConnectTime: 2000, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; @@ -658,7 +660,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { logger: logger, connConnectTime: 2000, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; @@ -735,7 +737,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { logger: logger, connConnectTime: 2000, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnapping connection map const connections = nodeConnectionManager.connections; diff --git a/tests/nodes/NodeConnectionManager.timeout.test.ts b/tests/nodes/NodeConnectionManager.timeout.test.ts index 7b93b596d..494350f52 100644 --- a/tests/nodes/NodeConnectionManager.timeout.test.ts +++ b/tests/nodes/NodeConnectionManager.timeout.test.ts @@ -1,5 +1,6 @@ import type { NodeId, NodeIdString, SeedNodes } from '@/nodes/types'; import type { Host, Port } from '@/network/types'; +import type NodeManager from 'nodes/NodeManager'; import fs from 'fs'; import path from 'path'; import os from 'os'; @@ -78,6 +79,7 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { keysUtils, 'generateDeterministicKeyPair', ); + const dummyNodeManager = { setNode: jest.fn() } as unknown as NodeManager; beforeAll(async () => { mockedGenerateDeterministicKeyPair.mockImplementation((bits, _) => { @@ -189,7 +191,7 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { connTimeoutTime: 500, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; // @ts-ignore: kidnap connections @@ -226,7 +228,7 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { connTimeoutTime: 1000, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; // @ts-ignore: kidnap connections @@ -278,7 +280,7 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { proxy, logger: nodeConnectionManagerLogger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); // @ts-ignore: kidnap connections const connections = nodeConnectionManager.connections; // @ts-ignore: kidnap connections diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index 4e4c2f62b..605490dbf 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -116,7 +116,6 @@ describe(`${NodeManager.name} test`, () => { proxy, logger, }); - await nodeConnectionManager.start(); }); afterEach(async () => { mockedPingNode.mockClear(); @@ -169,6 +168,8 @@ describe(`${NodeManager.name} test`, () => { nodeConnectionManager, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); // Set server node offline await server.stop(); @@ -240,6 +241,8 @@ describe(`${NodeManager.name} test`, () => { nodeConnectionManager, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); // We want to get the public key of the server const key = await nodeManager.getPublicKey(serverNodeId); @@ -425,6 +428,8 @@ describe(`${NodeManager.name} test`, () => { nodeConnectionManager, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); await nodeGraph.setNode(xNodeId, xNodeAddress); @@ -445,17 +450,23 @@ describe(`${NodeManager.name} test`, () => { nodeConnectionManager: {} as NodeConnectionManager, logger, }); - const localNodeId = keyManager.getNodeId(); - const bucketIndex = 100; - const nodeId = nodesTestUtils.generateNodeIdForBucket( - localNodeId, - bucketIndex, - ); - await nodeManager.setNode(nodeId, {} as NodeAddress); + try { + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); + const localNodeId = keyManager.getNodeId(); + const bucketIndex = 100; + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + ); + await nodeManager.setNode(nodeId, {} as NodeAddress); - // Checking bucket - const bucket = await nodeManager.getBucket(bucketIndex); - expect(bucket).toHaveLength(1); + // Checking bucket + const bucket = await nodeManager.getBucket(bucketIndex); + expect(bucket).toHaveLength(1); + } finally { + await nodeManager.stop(); + } }); test('should update a node if node exists', async () => { const nodeManager = new NodeManager({ @@ -466,29 +477,35 @@ describe(`${NodeManager.name} test`, () => { nodeConnectionManager: {} as NodeConnectionManager, logger, }); - const localNodeId = keyManager.getNodeId(); - const bucketIndex = 100; - const nodeId = nodesTestUtils.generateNodeIdForBucket( - localNodeId, - bucketIndex, - ); - await nodeManager.setNode(nodeId, { - host: '' as Host, - port: 11111 as Port, - }); + try { + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); + const localNodeId = keyManager.getNodeId(); + const bucketIndex = 100; + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + ); + await nodeManager.setNode(nodeId, { + host: '' as Host, + port: 11111 as Port, + }); - const nodeData = (await nodeGraph.getNode(nodeId))!; - await sleep(1100); + const nodeData = (await nodeGraph.getNode(nodeId))!; + await sleep(1100); - // Should update the node - await nodeManager.setNode(nodeId, { - host: '' as Host, - port: 22222 as Port, - }); + // Should update the node + await nodeManager.setNode(nodeId, { + host: '' as Host, + port: 22222 as Port, + }); - const newNodeData = (await nodeGraph.getNode(nodeId))!; - expect(newNodeData.address.port).not.toEqual(nodeData.address.port); - expect(newNodeData.lastUpdated).not.toEqual(nodeData.lastUpdated); + const newNodeData = (await nodeGraph.getNode(nodeId))!; + expect(newNodeData.address.port).not.toEqual(nodeData.address.port); + expect(newNodeData.lastUpdated).not.toEqual(nodeData.lastUpdated); + } finally { + await nodeManager.stop(); + } }); test('should not add node if bucket is full and old node is alive', async () => { const nodeManager = new NodeManager({ @@ -499,40 +516,46 @@ describe(`${NodeManager.name} test`, () => { nodeConnectionManager: {} as NodeConnectionManager, logger, }); - const localNodeId = keyManager.getNodeId(); - const bucketIndex = 100; - // Creating 20 nodes in bucket - for (let i = 1; i <= 20; i++) { + try { + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); + const localNodeId = keyManager.getNodeId(); + const bucketIndex = 100; + // Creating 20 nodes in bucket + for (let i = 1; i <= 20; i++) { + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + i, + ); + await nodeManager.setNode(nodeId, { port: i } as NodeAddress); + } const nodeId = nodesTestUtils.generateNodeIdForBucket( localNodeId, bucketIndex, - i, ); - await nodeManager.setNode(nodeId, { port: i } as NodeAddress); + // Mocking ping + const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); + nodeManagerPingMock.mockResolvedValue(true); + const oldestNodeId = (await nodeGraph.getOldestNode(bucketIndex)).pop(); + const oldestNode = await nodeGraph.getNode(oldestNodeId!); + // Waiting for a second to tick over + await sleep(1500); + // Adding a new node with bucket full + await nodeManager.setNode(nodeId, { port: 55555 } as NodeAddress, true); + // Bucket still contains max nodes + const bucket = await nodeManager.getBucket(bucketIndex); + expect(bucket).toHaveLength(nodeGraph.nodeBucketLimit); + // New node was not added + const node = await nodeGraph.getNode(nodeId); + expect(node).toBeUndefined(); + // Oldest node was updated + const oldestNodeNew = await nodeGraph.getNode(oldestNodeId!); + expect(oldestNodeNew!.lastUpdated).not.toEqual(oldestNode!.lastUpdated); + nodeManagerPingMock.mockRestore(); + } finally { + await nodeManager.stop(); } - const nodeId = nodesTestUtils.generateNodeIdForBucket( - localNodeId, - bucketIndex, - ); - // Mocking ping - const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); - nodeManagerPingMock.mockResolvedValue(true); - const oldestNodeId = (await nodeGraph.getOldestNode(bucketIndex)).pop(); - const oldestNode = await nodeGraph.getNode(oldestNodeId!); - // Waiting for a second to tick over - await sleep(1100); - // Adding a new node with bucket full - await nodeManager.setNode(nodeId, { port: 55555 } as NodeAddress); - // Bucket still contains max nodes - const bucket = await nodeManager.getBucket(bucketIndex); - expect(bucket).toHaveLength(nodeGraph.nodeBucketLimit); - // New node was not added - const node = await nodeGraph.getNode(nodeId); - expect(node).toBeUndefined(); - // Oldest node was updated - const oldestNodeNew = await nodeGraph.getNode(oldestNodeId!); - expect(oldestNodeNew!.lastUpdated).not.toEqual(oldestNode!.lastUpdated); - nodeManagerPingMock.mockRestore(); }); test('should add node if bucket is full, old node is alive and force is set', async () => { const nodeManager = new NodeManager({ @@ -543,37 +566,48 @@ describe(`${NodeManager.name} test`, () => { nodeConnectionManager: {} as NodeConnectionManager, logger, }); - const localNodeId = keyManager.getNodeId(); - const bucketIndex = 100; - // Creating 20 nodes in bucket - for (let i = 1; i <= 20; i++) { + try { + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); + const localNodeId = keyManager.getNodeId(); + const bucketIndex = 100; + // Creating 20 nodes in bucket + for (let i = 1; i <= 20; i++) { + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + i, + ); + await nodeManager.setNode(nodeId, { port: i } as NodeAddress); + } const nodeId = nodesTestUtils.generateNodeIdForBucket( localNodeId, bucketIndex, - i, ); - await nodeManager.setNode(nodeId, { port: i } as NodeAddress); + // Mocking ping + const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); + nodeManagerPingMock.mockResolvedValue(true); + const oldestNodeId = (await nodeGraph.getOldestNode(bucketIndex)).pop(); + // Adding a new node with bucket full + await nodeManager.setNode( + nodeId, + { port: 55555 } as NodeAddress, + false, + true, + ); + // Bucket still contains max nodes + const bucket = await nodeManager.getBucket(bucketIndex); + expect(bucket).toHaveLength(nodeGraph.nodeBucketLimit); + // New node was added + const node = await nodeGraph.getNode(nodeId); + expect(node).toBeDefined(); + // Oldest node was removed + const oldestNodeNew = await nodeGraph.getNode(oldestNodeId!); + expect(oldestNodeNew).toBeUndefined(); + nodeManagerPingMock.mockRestore(); + } finally { + await nodeManager.stop(); } - const nodeId = nodesTestUtils.generateNodeIdForBucket( - localNodeId, - bucketIndex, - ); - // Mocking ping - const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); - nodeManagerPingMock.mockResolvedValue(true); - const oldestNodeId = (await nodeGraph.getOldestNode(bucketIndex)).pop(); - // Adding a new node with bucket full - await nodeManager.setNode(nodeId, { port: 55555 } as NodeAddress, true); - // Bucket still contains max nodes - const bucket = await nodeManager.getBucket(bucketIndex); - expect(bucket).toHaveLength(nodeGraph.nodeBucketLimit); - // New node was added - const node = await nodeGraph.getNode(nodeId); - expect(node).toBeDefined(); - // Oldest node was removed - const oldestNodeNew = await nodeGraph.getNode(oldestNodeId!); - expect(oldestNodeNew).toBeUndefined(); - nodeManagerPingMock.mockRestore(); }); test('should add node if bucket is full and old node is dead', async () => { const nodeManager = new NodeManager({ @@ -584,41 +618,54 @@ describe(`${NodeManager.name} test`, () => { nodeConnectionManager: {} as NodeConnectionManager, logger, }); - const localNodeId = keyManager.getNodeId(); - const bucketIndex = 100; - // Creating 20 nodes in bucket - for (let i = 1; i <= 20; i++) { + try { + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); + const localNodeId = keyManager.getNodeId(); + const bucketIndex = 100; + // Creating 20 nodes in bucket + for (let i = 1; i <= 20; i++) { + const nodeId = nodesTestUtils.generateNodeIdForBucket( + localNodeId, + bucketIndex, + i, + ); + await nodeManager.setNode(nodeId, { port: i } as NodeAddress); + } const nodeId = nodesTestUtils.generateNodeIdForBucket( localNodeId, bucketIndex, - i, ); - await nodeManager.setNode(nodeId, { port: i } as NodeAddress); + // Mocking ping + const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); + nodeManagerPingMock.mockResolvedValue(false); + const oldestNodeId = (await nodeGraph.getOldestNode(bucketIndex)).pop(); + // Adding a new node with bucket full + await nodeManager.setNode(nodeId, { port: 55555 } as NodeAddress, true); + // New node was added + const node = await nodeGraph.getNode(nodeId); + expect(node).toBeDefined(); + // Oldest node was removed + const oldestNodeNew = await nodeGraph.getNode(oldestNodeId!); + expect(oldestNodeNew).toBeUndefined(); + nodeManagerPingMock.mockRestore(); + } finally { + await nodeManager.stop(); } - const nodeId = nodesTestUtils.generateNodeIdForBucket( - localNodeId, - bucketIndex, - ); - // Mocking ping - const nodeManagerPingMock = jest.spyOn(NodeManager.prototype, 'pingNode'); - nodeManagerPingMock.mockResolvedValue(false); - const oldestNodeId = (await nodeGraph.getOldestNode(bucketIndex)).pop(); - // Adding a new node with bucket full - await nodeManager.setNode(nodeId, { port: 55555 } as NodeAddress, true); - // Bucket still contains max nodes - const bucket = await nodeManager.getBucket(bucketIndex); - expect(bucket).toHaveLength(nodeGraph.nodeBucketLimit); - // New node was added - const node = await nodeGraph.getNode(nodeId); - expect(node).toBeDefined(); - // Oldest node was removed - const oldestNodeNew = await nodeGraph.getNode(oldestNodeId!); - expect(oldestNodeNew).toBeUndefined(); - nodeManagerPingMock.mockRestore(); }); test('should add node when an incoming connection is established', async () => { let server: PolykeyAgent | undefined; + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph, + nodeConnectionManager: {} as NodeConnectionManager, + logger, + }); try { + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); server = await PolykeyAgent.createPolykeyAgent({ password: 'password', nodePath: path.join(dataDir, 'server'), @@ -655,101 +702,90 @@ describe(`${NodeManager.name} test`, () => { // Clean up await server?.stop(); await server?.destroy(); + await nodeManager.stop(); } }); test('should not add nodes to full bucket if pings succeeds', async () => { - const tempNodeGraph = await NodeGraph.createNodeGraph({ - db, - keyManager, - logger, - }); mockedPingNode.mockImplementation(async (_) => true); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, - nodeGraph: tempNodeGraph, + nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, logger, }); - await nodeManager.start(); - const nodeId = keyManager.getNodeId(); - const address = { host: localhost, port }; - // Let's fill a bucket - for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { - const newNode = generateNodeIdForBucket(nodeId, 100, i); - await nodeManager.setNode(newNode, address); - } - - // Helpers - const listBucket = async (bucketIndex: number) => { - const bucket = await nodeManager.getBucket(bucketIndex); - return bucket?.map(([nodeId]) => nodesUtils.encodeNodeId(nodeId)); - }; + try { + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); + const nodeId = keyManager.getNodeId(); + const address = { host: localhost, port }; + // Let's fill a bucket + for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { + const newNode = generateNodeIdForBucket(nodeId, 100, i); + await nodeManager.setNode(newNode, address); + } - // Pings succeed, node not added - mockedPingNode.mockImplementation(async (_) => true); - const newNode = generateNodeIdForBucket(nodeId, 100, 21); - await nodeManager.setNode(newNode, address); - expect(await listBucket(100)).not.toContain( - nodesUtils.encodeNodeId(newNode), - ); + // Helpers + const listBucket = async (bucketIndex: number) => { + const bucket = await nodeManager.getBucket(bucketIndex); + return bucket?.map(([nodeId]) => nodesUtils.encodeNodeId(nodeId)); + }; - // Clean up - await nodeManager.queueDrained(); - await nodeManager.stop(); - await tempNodeGraph.stop(); - await tempNodeGraph.destroy(); + // Pings succeed, node not added + mockedPingNode.mockImplementation(async (_) => true); + const newNode = generateNodeIdForBucket(nodeId, 100, 21); + await nodeManager.setNode(newNode, address); + expect(await listBucket(100)).not.toContain( + nodesUtils.encodeNodeId(newNode), + ); + } finally { + await nodeManager.stop(); + } }); test('should add nodes to full bucket if pings fail', async () => { - const tempNodeGraph = await NodeGraph.createNodeGraph({ - db, - keyManager, - logger, - }); mockedPingNode.mockImplementation(async (_) => true); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, - nodeGraph: tempNodeGraph, + nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, logger, }); await nodeManager.start(); - const nodeId = keyManager.getNodeId(); - const address = { host: localhost, port }; - // Let's fill a bucket - for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { - const newNode = generateNodeIdForBucket(nodeId, 100, i); - await nodeManager.setNode(newNode, address); - } + try { + await nodeConnectionManager.start({ nodeManager }); + const nodeId = keyManager.getNodeId(); + const address = { host: localhost, port }; + // Let's fill a bucket + for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { + const newNode = generateNodeIdForBucket(nodeId, 100, i); + await nodeManager.setNode(newNode, address); + } - // Helpers - const listBucket = async (bucketIndex: number) => { - const bucket = await nodeManager.getBucket(bucketIndex); - return bucket?.map(([nodeId]) => nodesUtils.encodeNodeId(nodeId)); - }; - - // Pings fail, new nodes get added - mockedPingNode.mockImplementation(async (_) => false); - const newNode1 = generateNodeIdForBucket(nodeId, 100, 22); - const newNode2 = generateNodeIdForBucket(nodeId, 100, 23); - const newNode3 = generateNodeIdForBucket(nodeId, 100, 24); - await nodeManager.setNode(newNode1, address); - await nodeManager.setNode(newNode2, address); - await nodeManager.setNode(newNode3, address); - await nodeManager.queueDrained(); - const list = await listBucket(100); - expect(list).toContain(nodesUtils.encodeNodeId(newNode1)); - expect(list).toContain(nodesUtils.encodeNodeId(newNode2)); - expect(list).toContain(nodesUtils.encodeNodeId(newNode3)); - - // Clean up - await nodeManager.queueDrained(); - await nodeManager.stop(); - await tempNodeGraph.stop(); - await tempNodeGraph.destroy(); + // Helpers + const listBucket = async (bucketIndex: number) => { + const bucket = await nodeManager.getBucket(bucketIndex); + return bucket?.map(([nodeId]) => nodesUtils.encodeNodeId(nodeId)); + }; + + // Pings fail, new nodes get added + mockedPingNode.mockImplementation(async (_) => false); + const newNode1 = generateNodeIdForBucket(nodeId, 100, 22); + const newNode2 = generateNodeIdForBucket(nodeId, 100, 23); + const newNode3 = generateNodeIdForBucket(nodeId, 100, 24); + await nodeManager.setNode(newNode1, address); + await nodeManager.setNode(newNode2, address); + await nodeManager.setNode(newNode3, address); + await nodeManager.queueDrained(); + const list = await listBucket(100); + expect(list).toContain(nodesUtils.encodeNodeId(newNode1)); + expect(list).toContain(nodesUtils.encodeNodeId(newNode2)); + expect(list).toContain(nodesUtils.encodeNodeId(newNode3)); + } finally { + await nodeManager.stop(); + } }); test('should not block when bucket is full', async () => { const tempNodeGraph = await NodeGraph.createNodeGraph({ @@ -767,72 +803,65 @@ describe(`${NodeManager.name} test`, () => { logger, }); await nodeManager.start(); - const nodeId = keyManager.getNodeId(); - const address = { host: localhost, port }; - // Let's fill a bucket - for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { - const newNode = generateNodeIdForBucket(nodeId, 100, i); - await nodeManager.setNode(newNode, address); - } + try { + await nodeConnectionManager.start({ nodeManager }); + const nodeId = keyManager.getNodeId(); + const address = { host: localhost, port }; + // Let's fill a bucket + for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { + const newNode = generateNodeIdForBucket(nodeId, 100, i); + await nodeManager.setNode(newNode, address); + } - // Set node does not block - const delayPing = promise(); - mockedPingNode.mockImplementation(async (_) => { - await delayPing.p; - return true; - }); - const newNode4 = generateNodeIdForBucket(nodeId, 100, 25); - await expect( - nodeManager.setNode(newNode4, address), - ).resolves.toBeUndefined(); - delayPing.resolveP(null); - await nodeManager.queueDrained(); - - // Clean up - await nodeManager.queueDrained(); - await nodeManager.stop(); - await tempNodeGraph.stop(); - await tempNodeGraph.destroy(); + // Set node does not block + const delayPing = promise(); + mockedPingNode.mockImplementation(async (_) => { + await delayPing.p; + return true; + }); + const newNode4 = generateNodeIdForBucket(nodeId, 100, 25); + await expect( + nodeManager.setNode(newNode4, address), + ).resolves.toBeUndefined(); + delayPing.resolveP(null); + await nodeManager.queueDrained(); + } finally { + await nodeManager.stop(); + await tempNodeGraph.stop(); + await tempNodeGraph.destroy(); + } }); test('should block when blocking is set to true', async () => { - const tempNodeGraph = await NodeGraph.createNodeGraph({ - db, - keyManager, - logger, - }); mockedPingNode.mockImplementation(async (_) => true); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, - nodeGraph: tempNodeGraph, + nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, logger, }); await nodeManager.start(); - const nodeId = keyManager.getNodeId(); - const address = { host: localhost, port }; - // Let's fill a bucket - for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { - const newNode = generateNodeIdForBucket(nodeId, 100, i); - await nodeManager.setNode(newNode, address); - } + try { + await nodeConnectionManager.start({ nodeManager }); + const nodeId = keyManager.getNodeId(); + const address = { host: localhost, port }; + // Let's fill a bucket + for (let i = 0; i < nodeGraph.nodeBucketLimit; i++) { + const newNode = generateNodeIdForBucket(nodeId, 100, i); + await nodeManager.setNode(newNode, address); + } - // Set node can block - mockedPingNode.mockClear(); - mockedPingNode.mockImplementation(async (_) => { - return true; - }); - const newNode5 = generateNodeIdForBucket(nodeId, 100, 25); - await expect( - nodeManager.setNode(newNode5, address, true), - ).resolves.toBeUndefined(); - expect(mockedPingNode).toBeCalled(); - - // CLean up - await nodeManager.queueDrained(); - await nodeManager.stop(); - await tempNodeGraph.stop(); - await tempNodeGraph.destroy(); + // Set node can block + mockedPingNode.mockClear(); + mockedPingNode.mockImplementation(async () => true); + const newNode5 = generateNodeIdForBucket(nodeId, 100, 25); + await expect( + nodeManager.setNode(newNode5, address, true), + ).resolves.toBeUndefined(); + expect(mockedPingNode).toBeCalled(); + } finally { + await nodeManager.stop(); + } }); }); diff --git a/tests/notifications/NotificationsManager.test.ts b/tests/notifications/NotificationsManager.test.ts index 37be01f56..b382ea49d 100644 --- a/tests/notifications/NotificationsManager.test.ts +++ b/tests/notifications/NotificationsManager.test.ts @@ -118,7 +118,6 @@ describe('NotificationsManager', () => { proxy, logger, }); - await nodeConnectionManager.start(); nodeManager = new NodeManager({ db, keyManager, @@ -127,6 +126,8 @@ describe('NotificationsManager', () => { nodeGraph, logger, }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); // Set up node for receiving notifications receiver = await PolykeyAgent.createPolykeyAgent({ password: password, diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index f37dfba38..5236215b0 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -7,6 +7,7 @@ import type { } from '@/vaults/types'; import type NotificationsManager from '@/notifications/NotificationsManager'; import type { Host, Port, TLSConfig } from '@/network/types'; +import type NodeManager from '@/nodes/NodeManager'; import fs from 'fs'; import os from 'os'; import path from 'path'; @@ -493,7 +494,7 @@ describe('VaultManager', () => { logger: logger.getChild('Remote Keynode 1'), nodePath: path.join(allDataDir, 'remoteKeynode1'), networkConfig: { - proxyHost: '127.0.0.1' as Host, + proxyHost: localHost, }, }); remoteKeynode1Id = remoteKeynode1.keyManager.getNodeId(); @@ -503,7 +504,7 @@ describe('VaultManager', () => { logger: logger.getChild('Remote Keynode 2'), nodePath: path.join(allDataDir, 'remoteKeynode2'), networkConfig: { - proxyHost: '127.0.0.1' as Host, + proxyHost: localHost, }, }); remoteKeynode2Id = remoteKeynode2.keyManager.getNodeId(); @@ -581,7 +582,9 @@ describe('VaultManager', () => { proxy, logger, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ + nodeManager: { setNode: jest.fn() } as unknown as NodeManager, + }); await nodeGraph.setNode(remoteKeynode1Id, { host: remoteKeynode1.proxy.getProxyHost(), @@ -1454,7 +1457,7 @@ describe('VaultManager', () => { password: 'password', nodePath: path.join(dataDir, 'remoteNode'), networkConfig: { - proxyHost: '127.0.0.1' as Host, + proxyHost: localHost, }, logger, }); @@ -1496,7 +1499,9 @@ describe('VaultManager', () => { proxy, connConnectTime: 1000, }); - await nodeConnectionManager.start(); + await nodeConnectionManager.start({ + nodeManager: { setNode: jest.fn() } as unknown as NodeManager, + }); const vaultManager = await VaultManager.createVaultManager({ vaultsPath, keyManager, From 04091f269285f1a081180a3f6a295698b1a4cd94 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 8 Apr 2022 18:28:22 +1000 Subject: [PATCH 091/137] feat: implemented `NodeManager.refreshBucket()` This method preforms the kademlia `refreshBucket` operation. It selects a random node within the bucket and preforms a search for that node. The process exchanges node information with any nodes it connects to. #345 --- src/nodes/NodeManager.ts | 28 ++++++++++++++++++++++++-- src/nodes/utils.ts | 42 +++++++++++++++++++++++++++++++++++++++ tests/nodes/utils.test.ts | 18 +++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index f94c5315d..61fac9838 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -5,11 +5,17 @@ import type KeyManager from '../keys/KeyManager'; import type { PublicKeyPem } from '../keys/types'; import type Sigchain from '../sigchain/Sigchain'; import type { ChainData, ChainDataEncoded } from '../sigchain/types'; -import type { NodeId, NodeAddress, NodeBucket } from '../nodes/types'; +import type { + NodeId, + NodeAddress, + NodeBucket, + NodeBucketIndex, +} from '../nodes/types'; import type { ClaimEncoded } from '../claims/types'; import type { Timer } from '../types'; import Logger from '@matrixai/logger'; import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; +import { IdInternal } from '@matrixai/id'; import * as nodesErrors from './errors'; import * as nodesUtils from './utils'; import * as networkUtils from '../network/utils'; @@ -514,7 +520,7 @@ class NodeManager { // return await this.nodeGraph.getAllBuckets(tran); // } - // FIXME + // FIXME potentially confusing name, should we rename this to renewBuckets? /** * To be called on key renewal. Re-orders all nodes in all buckets with respect * to the new node ID. @@ -609,6 +615,24 @@ class NodeManager { public async queueDrained(): Promise { await this.setNodeQueueEmpty; } + + /** + * Kademlia refresh bucket operation. + * It picks a random node within a bucket and does a search for that node. + * Connections during the search will will share node information with other + * nodes. + * @param bucketIndex + */ + private async refreshBucket(bucketIndex: NodeBucketIndex) { + // We need to generate a random nodeId for this bucket + const nodeId = this.keyManager.getNodeId(); + const bucketRandomNodeId = nodesUtils.generateRandomNodeIdForBucket( + nodeId, + bucketIndex, + ); + // We then need to start a findNode procedure + await this.nodeConnectionManager.findNode(bucketRandomNodeId); + } } export default NodeManager; diff --git a/src/nodes/utils.ts b/src/nodes/utils.ts index 76bb4058a..c61a6cd58 100644 --- a/src/nodes/utils.ts +++ b/src/nodes/utils.ts @@ -7,6 +7,7 @@ import type { import { IdInternal } from '@matrixai/id'; import lexi from 'lexicographic-integer'; import { bytes2BigInt, bufferSplit } from '../utils'; +import * as keysUtils from '../keys/utils'; // FIXME: const prefixBuffer = Buffer.from([33]); @@ -283,6 +284,44 @@ function bucketSortByDistance( } } +function generateRandomDistanceForBucket(bucketIndex: NodeBucketIndex): NodeId { + const buffer = keysUtils.getRandomBytesSync(32); + // Calculate the most significant byte for bucket + const base = bucketIndex / 8; + const mSigByte = Math.floor(base); + const mSigBit = (base - mSigByte) * 8 + 1; + const mSigByteIndex = buffer.length - mSigByte - 1; + // Creating masks + // AND mask should look like 0b00011111 + // OR mask should look like 0b00010000 + const shift = 8 - mSigBit; + const andMask = 0b11111111 >>> shift; + const orMask = 0b10000000 >>> shift; + let byte = buffer[mSigByteIndex]; + byte = byte & andMask; // Forces 0 for bits above bucket bit + byte = byte | orMask; // Forces 1 in the desired bucket bit + buffer[mSigByteIndex] = byte; + // Zero out byte 'above' mSigByte + for (let byteIndex = 0; byteIndex < mSigByteIndex; byteIndex++) { + buffer[byteIndex] = 0; + } + return IdInternal.fromBuffer(buffer); +} + +function xOrNodeId(node1: NodeId, node2: NodeId): NodeId { + const xOrNodeArray = node1.map((byte, i) => byte ^ node2[i]); + const xOrNodeBuffer = Buffer.from(xOrNodeArray); + return IdInternal.fromBuffer(xOrNodeBuffer); +} + +function generateRandomNodeIdForBucket( + nodeId: NodeId, + bucket: NodeBucketIndex, +): NodeId { + const randomDistanceForBucket = generateRandomDistanceForBucket(bucket); + return xOrNodeId(nodeId, randomDistanceForBucket); +} + export { prefixBuffer, encodeNodeId, @@ -299,4 +338,7 @@ export { parseLastUpdatedBucketDbKey, nodeDistance, bucketSortByDistance, + generateRandomDistanceForBucket, + xOrNodeId, + generateRandomNodeIdForBucket, }; diff --git a/tests/nodes/utils.test.ts b/tests/nodes/utils.test.ts index 59d565812..c87a82f26 100644 --- a/tests/nodes/utils.test.ts +++ b/tests/nodes/utils.test.ts @@ -171,4 +171,22 @@ describe('nodes/utils', () => { i++; } }); + test('should generate random distance for a bucket', async () => { + // Const baseNodeId = testNodesUtils.generateRandomNodeId(); + const zeroNodeId = IdInternal.fromBuffer(Buffer.alloc(32, 0)); + for (let i = 0; i < 255; i++) { + const randomDistance = nodesUtils.generateRandomDistanceForBucket(i); + expect(nodesUtils.bucketIndex(zeroNodeId, randomDistance)).toEqual(i); + } + }); + test('should generate random NodeId for a bucket', async () => { + const baseNodeId = testNodesUtils.generateRandomNodeId(); + for (let i = 0; i < 255; i++) { + const randomDistance = nodesUtils.generateRandomNodeIdForBucket( + baseNodeId, + i, + ); + expect(nodesUtils.bucketIndex(baseNodeId, randomDistance)).toEqual(i); + } + }); }); From 4dec90bd704d922cf8b1874462b75d9a0ca88eb6 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Mon, 11 Apr 2022 16:52:13 +1000 Subject: [PATCH 092/137] feat: implemented no activity timers and queuing for `refreshBucket` Added queuing for `refreshBucket`. This means that buckets will be refreshed one at a time sequentially. This is to avoid doing a lot of costly refreshing all at once. Added no activity for buckets. If a bucket hasn't been touched for a while, 1 hour by default, it will add a refresh bucket operation to the queue. Timers are disabled for buckets already in the queue. Only 1 timer is used for all buckets since only one of them can have the shortest timer and that's all we really care about. #345 --- src/nodes/NodeManager.ts | 168 +++++++++++++++++++++++++++++++- src/utils/utils.ts | 12 ++- tests/nodes/NodeManager.test.ts | 107 +++++++++++++++++++- 3 files changed, 278 insertions(+), 9 deletions(-) diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 61fac9838..233e1b316 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -13,9 +13,9 @@ import type { } from '../nodes/types'; import type { ClaimEncoded } from '../claims/types'; import type { Timer } from '../types'; +import type { PromiseType } from '../utils/utils'; import Logger from '@matrixai/logger'; import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; -import { IdInternal } from '@matrixai/id'; import * as nodesErrors from './errors'; import * as nodesUtils from './utils'; import * as networkUtils from '../network/utils'; @@ -24,7 +24,7 @@ import * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb'; import * as claimsErrors from '../claims/errors'; import * as sigchainUtils from '../sigchain/utils'; import * as claimsUtils from '../claims/utils'; -import { timerStart } from '../utils/utils'; +import { promise, timerStart } from '../utils/utils'; interface NodeManager extends StartStop {} @StartStop() @@ -47,6 +47,16 @@ class NodeManager { protected setNodeQueueRunner: Promise; protected setNodeQueueEmpty: Promise; protected setNodeQueueDrained: () => void; + // Refresh bucket timer + protected refreshBucketDeadlineMap: Map = new Map(); + protected refreshBucketTimer: NodeJS.Timer; + protected refreshBucketNext: NodeBucketIndex; + public readonly refreshBucketTimerDefault; + protected refreshBucketQueue: Set = new Set(); + protected refreshBucketQueueRunning: boolean = false; + protected refreshBucketQueueRunner: Promise; + protected refreshBucketQueuePlug_: PromiseType; + protected refreshBucketQueueDrained_: PromiseType; constructor({ db, @@ -54,6 +64,7 @@ class NodeManager { sigchain, nodeConnectionManager, nodeGraph, + refreshBucketTimerDefault = 3600000, // 1 hour in milliseconds logger, }: { db: DB; @@ -61,6 +72,7 @@ class NodeManager { sigchain: Sigchain; nodeConnectionManager: NodeConnectionManager; nodeGraph: NodeGraph; + refreshBucketTimerDefault?: number; logger?: Logger; }) { this.logger = logger ?? new Logger(this.constructor.name); @@ -69,17 +81,22 @@ class NodeManager { this.sigchain = sigchain; this.nodeConnectionManager = nodeConnectionManager; this.nodeGraph = nodeGraph; + this.refreshBucketTimerDefault = refreshBucketTimerDefault; } public async start() { this.logger.info(`Starting ${this.constructor.name}`); this.setNodeQueueRunner = this.startSetNodeQueue(); + this.startRefreshBucketTimers(); + this.refreshBucketQueueRunner = this.startRefreshBucketQueue(); this.logger.info(`Started ${this.constructor.name}`); } public async stop() { this.logger.info(`Stopping ${this.constructor.name}`); await this.stopSetNodeQueue(); + await this.stopRefreshBucketTimers(); + await this.stopRefreshBucketQueue(); this.logger.info(`Stopped ${this.constructor.name}`); } @@ -419,6 +436,8 @@ class NodeManager { // Either already exists or has room in the bucket // We want to add or update the node await this.nodeGraph.setNode(nodeId, nodeAddress, tran); + // Updating the refreshBucket timer + this.refreshBucketUpdateDeadline(bucketIndex); } else { // We want to add a node but the bucket is full // We need to ping the oldest node @@ -434,6 +453,8 @@ class NodeManager { ); await this.nodeGraph.unsetNode(oldNodeId, tran); await this.nodeGraph.setNode(nodeId, nodeAddress, tran); + // Updating the refreshBucket timer + this.refreshBucketUpdateDeadline(bucketIndex); return; } if (blocking) { @@ -491,6 +512,8 @@ class NodeManager { ); const node = (await this.nodeGraph.getNode(nodeId))!; await this.nodeGraph.setNode(nodeId, node.address); + // Updating the refreshBucket timer + this.refreshBucketUpdateDeadline(bucketIndex); } else { this.logger.debug(`Ping failed for ${nodesUtils.encodeNodeId(nodeId)}`); // Otherwise we remove the node @@ -502,6 +525,8 @@ class NodeManager { if (count < this.nodeGraph.nodeBucketLimit) { this.logger.debug(`Bucket ${bucketIndex} now has room, adding new node`); await this.nodeGraph.setNode(nodeId, nodeAddress); + // Updating the refreshBucket timer + this.refreshBucketUpdateDeadline(bucketIndex); } } @@ -623,7 +648,7 @@ class NodeManager { * nodes. * @param bucketIndex */ - private async refreshBucket(bucketIndex: NodeBucketIndex) { + public async refreshBucket(bucketIndex: NodeBucketIndex) { // We need to generate a random nodeId for this bucket const nodeId = this.keyManager.getNodeId(); const bucketRandomNodeId = nodesUtils.generateRandomNodeIdForBucket( @@ -633,6 +658,143 @@ class NodeManager { // We then need to start a findNode procedure await this.nodeConnectionManager.findNode(bucketRandomNodeId); } + + // Refresh bucket activity timer methods + + private startRefreshBucketTimers() { + // Setting initial bucket to refresh + this.refreshBucketNext = 0; + // Setting initial deadline + this.refreshBucketTimerReset(this.refreshBucketTimerDefault); + + for ( + let bucketIndex = 0; + bucketIndex < this.nodeGraph.nodeIdBits; + bucketIndex++ + ) { + const deadline = Date.now() + this.refreshBucketTimerDefault; + this.refreshBucketDeadlineMap.set(bucketIndex, deadline); + } + } + + private async stopRefreshBucketTimers() { + clearTimeout(this.refreshBucketTimer); + } + + private refreshBucketTimerReset(timeout: number) { + clearTimeout(this.refreshBucketTimer); + this.refreshBucketTimer = setTimeout(() => { + this.refreshBucketRefreshTimer(); + }, timeout); + } + + public refreshBucketUpdateDeadline(bucketIndex: NodeBucketIndex) { + // Update the map deadline + this.refreshBucketDeadlineMap.set( + bucketIndex, + Date.now() + this.refreshBucketTimerDefault, + ); + // If the bucket was pending a refresh we remove it + this.refreshBucketQueueRemove(bucketIndex); + if (bucketIndex === this.refreshBucketNext) { + // Bucket is same as next bucket, this affects the timer + this.refreshBucketRefreshTimer(); + } + } + + private refreshBucketRefreshTimer() { + // Getting new closest deadline + let closestBucket = this.refreshBucketNext; + let closestDeadline = Date.now() + this.refreshBucketTimerDefault; + const now = Date.now(); + for (const [bucketIndex, deadline] of this.refreshBucketDeadlineMap) { + // Skip any queued buckets marked by 0 deadline + if (deadline === 0) continue; + if (deadline <= now) { + // Deadline for this has already passed, we add it to the queue + this.refreshBucketQueueAdd(bucketIndex); + continue; + } + if (deadline < closestDeadline) { + closestBucket = bucketIndex; + closestDeadline = deadline; + } + } + // Working out time left + const timeout = closestDeadline - Date.now(); + this.logger.debug( + `Refreshing refreshBucket timer with new timeout ${timeout}`, + ); + // Updating timer and next + this.refreshBucketNext = closestBucket; + this.refreshBucketTimerReset(timeout); + } + + // Refresh bucket async queue methods + + public refreshBucketQueueAdd(bucketIndex: NodeBucketIndex) { + this.logger.debug(`Adding bucket ${bucketIndex} to queue`); + this.refreshBucketDeadlineMap.set(bucketIndex, 0); + this.refreshBucketQueue.add(bucketIndex); + this.refreshBucketQueueUnplug(); + } + + public refreshBucketQueueRemove(bucketIndex: NodeBucketIndex) { + this.logger.debug(`Removing bucket ${bucketIndex} from queue`); + this.refreshBucketQueue.delete(bucketIndex); + } + + public async refreshBucketQueueDrained() { + await this.refreshBucketQueueDrained_.p; + } + + private async startRefreshBucketQueue(): Promise { + this.refreshBucketQueueRunning = true; + this.refreshBucketQueuePlug(); + let iterator: IterableIterator | undefined; + const pace = async () => { + // Wait for plug + await this.refreshBucketQueuePlug_.p; + if (iterator == null) { + iterator = this.refreshBucketQueue[Symbol.iterator](); + } + return this.refreshBucketQueueRunning; + }; + while (await pace()) { + const bucketIndex: NodeBucketIndex = iterator?.next().value; + if (bucketIndex == null) { + // Iterator is empty, plug and continue + iterator = undefined; + this.refreshBucketQueuePlug(); + continue; + } + // Do the job + this.logger.debug( + `processing refreshBucket for bucket ${bucketIndex}, ${this.refreshBucketQueue.size} left in queue`, + ); + await this.refreshBucket(bucketIndex); + // Remove from queue and update bucket deadline + this.refreshBucketQueue.delete(bucketIndex); + this.refreshBucketUpdateDeadline(bucketIndex); + } + this.logger.debug('startRefreshBucketQueue has ended'); + } + + private async stopRefreshBucketQueue(): Promise { + // Flag end and await queue finish + this.refreshBucketQueueRunning = false; + this.refreshBucketQueueUnplug(); + } + + private refreshBucketQueuePlug() { + this.refreshBucketQueuePlug_ = promise(); + this.refreshBucketQueueDrained_?.resolveP(); + } + + private refreshBucketQueueUnplug() { + this.refreshBucketQueueDrained_ = promise(); + this.refreshBucketQueuePlug_?.resolveP(); + } } export default NodeManager; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 7c623e8dd..0b99a8a43 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -170,14 +170,16 @@ function promisify< }; } -/** - * Deconstructed promise - */ -function promise(): { +export type PromiseType = { p: Promise; resolveP: (value: T | PromiseLike) => void; rejectP: (reason?: any) => void; -} { +}; + +/** + * Deconstructed promise + */ +function promise(): PromiseType { let resolveP, rejectP; const p = new Promise((resolve, reject) => { resolveP = resolve; diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index 605490dbf..04880a0ff 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -24,7 +24,7 @@ import { generateNodeIdForBucket } from './utils'; describe(`${NodeManager.name} test`, () => { const password = 'password'; - const logger = new Logger(`${NodeManager.name} test`, LogLevel.DEBUG, [ + const logger = new Logger(`${NodeManager.name} test`, LogLevel.WARN, [ new StreamHandler(), ]); let dataDir: string; @@ -864,4 +864,109 @@ describe(`${NodeManager.name} test`, () => { await nodeManager.stop(); } }); + test('should update deadline when updating a bucket', async () => { + const refreshBucketTimeout = 100000; + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph, + nodeConnectionManager: dummyNodeConnectionManager, + refreshBucketTimerDefault: refreshBucketTimeout, + logger, + }); + const mockRefreshBucket = jest.spyOn( + NodeManager.prototype, + 'refreshBucket', + ); + try { + mockRefreshBucket.mockImplementation(async () => {}); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); + // @ts-ignore: kidnap map + const deadlineMap = nodeManager.refreshBucketDeadlineMap; + // Getting starting value + const bucket = 0; + const startingDeadline = deadlineMap.get(bucket); + const nodeId = nodesTestUtils.generateNodeIdForBucket( + keyManager.getNodeId(), + bucket, + ); + await sleep(1000); + await nodeManager.setNode(nodeId, {} as NodeAddress); + // Deadline should be updated + const newDeadline = deadlineMap.get(bucket); + expect(newDeadline).not.toEqual(startingDeadline); + } finally { + mockRefreshBucket.mockRestore(); + await nodeManager.stop(); + } + }); + test('should add buckets to the queue when exceeding deadline', async () => { + const refreshBucketTimeout = 100; + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph, + nodeConnectionManager: dummyNodeConnectionManager, + refreshBucketTimerDefault: refreshBucketTimeout, + logger, + }); + const mockRefreshBucket = jest.spyOn( + NodeManager.prototype, + 'refreshBucket', + ); + const mockRefreshBucketQueueAdd = jest.spyOn( + NodeManager.prototype, + 'refreshBucketQueueAdd', + ); + try { + mockRefreshBucket.mockImplementation(async () => {}); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); + // Getting starting value + expect(mockRefreshBucketQueueAdd).toHaveBeenCalledTimes(0); + await sleep(200); + expect(mockRefreshBucketQueueAdd).toHaveBeenCalledTimes(256); + } finally { + mockRefreshBucketQueueAdd.mockRestore(); + mockRefreshBucket.mockRestore(); + await nodeManager.stop(); + } + }); + test('should digest queue to refresh buckets', async () => { + const refreshBucketTimeout = 1000000; + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph, + nodeConnectionManager: dummyNodeConnectionManager, + refreshBucketTimerDefault: refreshBucketTimeout, + logger, + }); + const mockRefreshBucket = jest.spyOn( + NodeManager.prototype, + 'refreshBucket', + ); + try { + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); + mockRefreshBucket.mockImplementation(async () => {}); + nodeManager.refreshBucketQueueAdd(1); + nodeManager.refreshBucketQueueAdd(2); + nodeManager.refreshBucketQueueAdd(3); + nodeManager.refreshBucketQueueAdd(4); + nodeManager.refreshBucketQueueAdd(5); + await nodeManager.refreshBucketQueueDrained(); + expect(mockRefreshBucket).toHaveBeenCalledTimes(5); + + // Add buckets to queue + // check if refresh buckets was called + } finally { + mockRefreshBucket.mockRestore(); + await nodeManager.stop(); + } + }); }); From ee53cfad3eb09486a4835d721fd1a933947d43c9 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Mon, 11 Apr 2022 18:04:26 +1000 Subject: [PATCH 093/137] feat: refreshing buckets when entering network `nodeConnectionManager.syncNodeGraph` now refreshes all buckets above the closest node as per the kademlia spec. This means adding a lot of buckets to the refresh bucket queue when an agent is started. #345 --- src/nodes/NodeConnectionManager.ts | 18 +++- src/nodes/NodeGraph.ts | 8 +- src/nodes/NodeManager.ts | 2 +- .../NodeConnectionManager.seednodes.test.ts | 98 ++++++++++++++++++- 4 files changed, 114 insertions(+), 12 deletions(-) diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 544fd5687..fb4f04e79 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -590,9 +590,21 @@ class NodeConnectionManager { timer, ); for (const [nodeId, nodeData] of nodes) { - // FIXME: this should be the `nodeManager.setNode` - // FIXME: no tran needed - await this.nodeGraph.setNode(nodeId, nodeData.address); + // FIXME: needs to ping the node right? we want to be non-blocking + try { + // FIXME: no tran needed + await this.nodeManager?.setNode(nodeId, nodeData.address); + } catch (e) { + if (!(e instanceof nodesErrors.ErrorNodeGraphSameNodeId)) throw e; + } + } + // Refreshing every bucket above the closest node + const [closestNode] = ( + await this.nodeGraph.getClosestNodes(this.keyManager.getNodeId(), 1) + ).pop()!; + const [bucketIndex] = this.nodeGraph.bucketIndex(closestNode); + for (let i = bucketIndex; i < this.nodeGraph.nodeIdBits; i++) { + this.nodeManager?.refreshBucketQueueAdd(i); } } } diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index d7437b389..3baf60299 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -697,10 +697,10 @@ class NodeGraph { // 2. iterate over 0 ---> T-1 // 3. iterate over T+1 ---> K // Need to work out the relevant bucket to start from - const startingBucket = nodesUtils.bucketIndex( - this.keyManager.getNodeId(), - nodeId, - ); + const localNodeId = this.keyManager.getNodeId(); + const startingBucket = localNodeId.equals(nodeId) + ? 0 + : nodesUtils.bucketIndex(this.keyManager.getNodeId(), nodeId); // Getting the whole target's bucket first const nodeIds: NodeBucket = await this.getBucket( startingBucket, diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 233e1b316..37fdf3cf0 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -115,7 +115,7 @@ class NodeManager { // We need to attempt a connection using the proxies // For now we will just do a forward connect + relay message const targetAddress = - address ?? (await this.nodeConnectionManager.findNode(nodeId)); + address ?? (await this.nodeConnectionManager.findNode(nodeId))!; const targetHost = await networkUtils.resolveHost(targetAddress.host); return await this.nodeConnectionManager.pingNode( nodeId, diff --git a/tests/nodes/NodeConnectionManager.seednodes.test.ts b/tests/nodes/NodeConnectionManager.seednodes.test.ts index ec7d6ee44..4d47afb0c 100644 --- a/tests/nodes/NodeConnectionManager.seednodes.test.ts +++ b/tests/nodes/NodeConnectionManager.seednodes.test.ts @@ -1,12 +1,13 @@ import type { NodeId, SeedNodes } from '@/nodes/types'; import type { Host, Port } from '@/network/types'; -import type NodeManager from 'nodes/NodeManager'; +import type { Sigchain } from '@/sigchain'; import fs from 'fs'; import path from 'path'; import os from 'os'; import { DB } from '@matrixai/db'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; +import NodeManager from '@/nodes/NodeManager'; import PolykeyAgent from '@/PolykeyAgent'; import KeyManager from '@/keys/KeyManager'; import NodeGraph from '@/nodes/NodeGraph'; @@ -78,7 +79,10 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { keysUtils, 'generateDeterministicKeyPair', ); - const dummyNodeManager = { setNode: jest.fn() } as unknown as NodeManager; + const dummyNodeManager = { + setNode: jest.fn(), + refreshBucketQueueAdd: jest.fn(), + } as unknown as NodeManager; beforeAll(async () => { mockedGenerateDeterministicKeyPair.mockImplementation((bits, _) => { @@ -225,6 +229,12 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { }); test('should synchronise nodeGraph', async () => { let nodeConnectionManager: NodeConnectionManager | undefined; + let nodeManager: NodeManager | undefined; + const mockedRefreshBucket = jest.spyOn( + NodeManager.prototype, + 'refreshBucket', + ); + mockedRefreshBucket.mockImplementation(async () => {}); try { const seedNodes: SeedNodes = {}; seedNodes[nodesUtils.encodeNodeId(remoteNodeId1)] = { @@ -242,6 +252,15 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { seedNodes, logger: logger, }); + nodeManager = new NodeManager({ + db, + keyManager, + logger, + nodeConnectionManager, + nodeGraph, + sigchain: {} as Sigchain, + }); + await nodeManager.start(); await remoteNode1.nodeGraph.setNode(nodeId1, { host: serverHost, port: serverPort, @@ -250,17 +269,77 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { host: serverHost, port: serverPort, }); - await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); + await nodeConnectionManager.start({ nodeManager }); await nodeConnectionManager.syncNodeGraph(); expect(await nodeGraph.getNode(nodeId1)).toBeDefined(); expect(await nodeGraph.getNode(nodeId2)).toBeDefined(); expect(await nodeGraph.getNode(dummyNodeId)).toBeUndefined(); } finally { + mockedRefreshBucket.mockRestore(); + await nodeManager?.stop(); + await nodeConnectionManager?.stop(); + } + }); + test('should call refreshBucket when syncing nodeGraph', async () => { + let nodeConnectionManager: NodeConnectionManager | undefined; + let nodeManager: NodeManager | undefined; + const mockedRefreshBucket = jest.spyOn( + NodeManager.prototype, + 'refreshBucket', + ); + mockedRefreshBucket.mockImplementation(async () => {}); + try { + const seedNodes: SeedNodes = {}; + seedNodes[nodesUtils.encodeNodeId(remoteNodeId1)] = { + host: remoteNode1.proxy.getProxyHost(), + port: remoteNode1.proxy.getProxyPort(), + }; + seedNodes[nodesUtils.encodeNodeId(remoteNodeId2)] = { + host: remoteNode2.proxy.getProxyHost(), + port: remoteNode2.proxy.getProxyPort(), + }; + nodeConnectionManager = new NodeConnectionManager({ + keyManager, + nodeGraph, + proxy, + seedNodes, + logger: logger, + }); + nodeManager = new NodeManager({ + db, + keyManager, + logger, + nodeConnectionManager, + nodeGraph, + sigchain: {} as Sigchain, + }); + await nodeManager.start(); + await remoteNode1.nodeGraph.setNode(nodeId1, { + host: serverHost, + port: serverPort, + }); + await remoteNode2.nodeGraph.setNode(nodeId2, { + host: serverHost, + port: serverPort, + }); + await nodeConnectionManager.start({ nodeManager }); + await nodeConnectionManager.syncNodeGraph(); + await nodeManager.refreshBucketQueueDrained(); + expect(mockedRefreshBucket).toHaveBeenCalled(); + } finally { + mockedRefreshBucket.mockRestore(); + await nodeManager?.stop(); await nodeConnectionManager?.stop(); } }); test('should handle an offline seed node when synchronising nodeGraph', async () => { let nodeConnectionManager: NodeConnectionManager | undefined; + let nodeManager: NodeManager | undefined; + const mockedRefreshBucket = jest.spyOn( + NodeManager.prototype, + 'refreshBucket', + ); + mockedRefreshBucket.mockImplementation(async () => {}); try { const seedNodes: SeedNodes = {}; seedNodes[nodesUtils.encodeNodeId(remoteNodeId1)] = { @@ -292,14 +371,25 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { connConnectTime: 500, logger: logger, }); - await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); + nodeManager = new NodeManager({ + db, + keyManager, + logger, + nodeConnectionManager, + nodeGraph, + sigchain: {} as Sigchain, + }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); // This should complete without error await nodeConnectionManager.syncNodeGraph(); // Information on remotes are found expect(await nodeGraph.getNode(nodeId1)).toBeDefined(); expect(await nodeGraph.getNode(nodeId2)).toBeDefined(); } finally { + mockedRefreshBucket.mockRestore(); await nodeConnectionManager?.stop(); + await nodeManager?.stop(); } }); }); From 6302b0d239ee27284c3fb21dfc4f4a796d56e525 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 14 Apr 2022 12:08:25 +1000 Subject: [PATCH 094/137] feat: abort controller support for `NodeManager.refreshBucket` Added support to cancel out of a `refreshBucket` operation. This is to allow faster stopping of the `NodeManager` by aborting out of a slow `refreshBucket` operation. This has been implemented with the `AbortController`/`AbortSignal` API. This is not fully supported by Node14 so we're using the `node-abort-controller` to provide functionality for now. #345 --- package.json | 1 + src/nodes/NodeConnectionManager.ts | 19 +++++++++++--- src/nodes/NodeManager.ts | 23 ++++++++++++++--- src/nodes/errors.ts | 6 +++++ tests/nodes/NodeManager.test.ts | 40 ++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index dc5780c81..0b34498f5 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "jose": "^4.3.6", "lexicographic-integer": "^1.1.0", "multiformats": "^9.4.8", + "node-abort-controller": "^3.0.1", "node-forge": "^0.10.0", "pako": "^1.0.11", "prompts": "^2.4.1", diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index fb4f04e79..f7ea93732 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -16,6 +16,7 @@ import type { } from './types'; import { withF } from '@matrixai/resources'; import type NodeManager from './NodeManager'; +import type { AbortSignal } from 'node-abort-controller'; import Logger from '@matrixai/logger'; import { ready, StartStop } from '@matrixai/async-init/dist/StartStop'; import { IdInternal } from '@matrixai/id'; @@ -383,16 +384,21 @@ class NodeConnectionManager { * Retrieves the node address. If an entry doesn't exist in the db, then * proceeds to locate it using Kademlia. * @param targetNodeId Id of the node we are tying to find - * @param tran + * @param options */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) - public async findNode(targetNodeId: NodeId): Promise { + public async findNode( + targetNodeId: NodeId, + options: { signal?: AbortSignal } = {}, + ): Promise { + const { signal } = { ...options }; // First check if we already have an existing ID -> address record - let address = (await this.nodeGraph.getNode(targetNodeId))?.address; // Otherwise, attempt to locate it by contacting network if (address == null) { - address = await this.getClosestGlobalNodes(targetNodeId); + address = await this.getClosestGlobalNodes(targetNodeId, undefined, { + signal, + }); // TODO: This currently just does one iteration // If not found in this single iteration, we throw an exception if (address == null) { @@ -418,13 +424,16 @@ class NodeConnectionManager { * @param targetNodeId ID of the node attempting to be found (i.e. attempting * to find its IP address and port) * @param timer Connection timeout timer + * @param options * @returns whether the target node was located in the process */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) public async getClosestGlobalNodes( targetNodeId: NodeId, timer?: Timer, + options: { signal?: AbortSignal } = {}, ): Promise { + const { signal } = { ...options }; // Let foundTarget: boolean = false; let foundAddress: NodeAddress | undefined = undefined; // Get the closest alpha nodes to the target node (set as shortlist) @@ -445,6 +454,7 @@ class NodeConnectionManager { const contacted: { [nodeId: string]: boolean } = {}; // Iterate until we've found and contacted k nodes while (Object.keys(contacted).length <= this.nodeGraph.nodeBucketLimit) { + if (signal?.aborted) throw new nodesErrors.ErrorNodeAborted(); // While (!foundTarget) { // Remove the node from the front of the array const nextNode = shortlist.shift(); @@ -479,6 +489,7 @@ class NodeConnectionManager { // Check to see if any of these are the target node. At the same time, add // them to the shortlist for (const [nodeId, nodeData] of foundClosest) { + if (signal?.aborted) throw new nodesErrors.ErrorNodeAborted(); // Ignore a`ny nodes that have been contacted if (contacted[nodeId]) { continue; diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 37fdf3cf0..2d1fc8240 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -14,8 +14,10 @@ import type { import type { ClaimEncoded } from '../claims/types'; import type { Timer } from '../types'; import type { PromiseType } from '../utils/utils'; +import type { AbortSignal } from 'node-abort-controller'; import Logger from '@matrixai/logger'; import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; +import { AbortController } from 'node-abort-controller'; import * as nodesErrors from './errors'; import * as nodesUtils from './utils'; import * as networkUtils from '../network/utils'; @@ -57,6 +59,7 @@ class NodeManager { protected refreshBucketQueueRunner: Promise; protected refreshBucketQueuePlug_: PromiseType; protected refreshBucketQueueDrained_: PromiseType; + protected refreshBucketQueueAbortController: AbortController; constructor({ db, @@ -647,8 +650,13 @@ class NodeManager { * Connections during the search will will share node information with other * nodes. * @param bucketIndex + * @param options */ - public async refreshBucket(bucketIndex: NodeBucketIndex) { + public async refreshBucket( + bucketIndex: NodeBucketIndex, + options: { signal?: AbortSignal } = {}, + ) { + const { signal } = { ...options }; // We need to generate a random nodeId for this bucket const nodeId = this.keyManager.getNodeId(); const bucketRandomNodeId = nodesUtils.generateRandomNodeIdForBucket( @@ -656,7 +664,7 @@ class NodeManager { bucketIndex, ); // We then need to start a findNode procedure - await this.nodeConnectionManager.findNode(bucketRandomNodeId); + await this.nodeConnectionManager.findNode(bucketRandomNodeId, { signal }); } // Refresh bucket activity timer methods @@ -752,6 +760,7 @@ class NodeManager { this.refreshBucketQueueRunning = true; this.refreshBucketQueuePlug(); let iterator: IterableIterator | undefined; + this.refreshBucketQueueAbortController = new AbortController(); const pace = async () => { // Wait for plug await this.refreshBucketQueuePlug_.p; @@ -772,7 +781,14 @@ class NodeManager { this.logger.debug( `processing refreshBucket for bucket ${bucketIndex}, ${this.refreshBucketQueue.size} left in queue`, ); - await this.refreshBucket(bucketIndex); + try { + await this.refreshBucket(bucketIndex, { + signal: this.refreshBucketQueueAbortController.signal, + }); + } catch (e) { + if (e instanceof nodesErrors.ErrorNodeAborted) break; + throw e; + } // Remove from queue and update bucket deadline this.refreshBucketQueue.delete(bucketIndex); this.refreshBucketUpdateDeadline(bucketIndex); @@ -782,6 +798,7 @@ class NodeManager { private async stopRefreshBucketQueue(): Promise { // Flag end and await queue finish + this.refreshBucketQueueAbortController.abort(); this.refreshBucketQueueRunning = false; this.refreshBucketQueueUnplug(); } diff --git a/src/nodes/errors.ts b/src/nodes/errors.ts index 863e19a37..a98fbcaa6 100644 --- a/src/nodes/errors.ts +++ b/src/nodes/errors.ts @@ -2,6 +2,11 @@ import { ErrorPolykey, sysexits } from '../errors'; class ErrorNodes extends ErrorPolykey {} +class ErrorNodeAborted extends ErrorNodes { + description = 'Operation was aborted'; + exitCode = sysexits.USAGE; +} + class ErrorNodeManagerNotRunning extends ErrorNodes { static description = 'NodeManager is not running'; exitCode = sysexits.USAGE; @@ -79,6 +84,7 @@ class ErrorNodeConnectionHostWildcard extends ErrorNodes { export { ErrorNodes, + ErrorNodeAborted, ErrorNodeManagerNotRunning, ErrorNodeGraphRunning, ErrorNodeGraphNotRunning, diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index 04880a0ff..b83be35d8 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -19,6 +19,7 @@ import * as claimsUtils from '@/claims/utils'; import { promise, promisify, sleep } from '@/utils'; import * as nodesUtils from '@/nodes/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as nodesErrors from '@/nodes/errors'; import * as nodesTestUtils from './utils'; import { generateNodeIdForBucket } from './utils'; @@ -969,4 +970,43 @@ describe(`${NodeManager.name} test`, () => { await nodeManager.stop(); } }); + test('should abort refreshBucket queue when stopping', async () => { + const refreshBucketTimeout = 1000000; + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph, + nodeConnectionManager: dummyNodeConnectionManager, + refreshBucketTimerDefault: refreshBucketTimeout, + logger, + }); + const mockRefreshBucket = jest.spyOn( + NodeManager.prototype, + 'refreshBucket', + ); + try { + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); + mockRefreshBucket.mockImplementation( + async (bucket, options: { signal?: AbortSignal } = {}) => { + const { signal } = { ...options }; + const prom = promise(); + signal?.addEventListener('abort', () => + prom.rejectP(new nodesErrors.ErrorNodeAborted()), + ); + await prom.p; + }, + ); + nodeManager.refreshBucketQueueAdd(1); + nodeManager.refreshBucketQueueAdd(2); + nodeManager.refreshBucketQueueAdd(3); + nodeManager.refreshBucketQueueAdd(4); + nodeManager.refreshBucketQueueAdd(5); + await nodeManager.stop(); + } finally { + mockRefreshBucket.mockRestore(); + await nodeManager.stop(); + } + }); }); From c88bb817182e8563af094da59aab0cf40721f688 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 19 Apr 2022 13:14:35 +1000 Subject: [PATCH 095/137] fix: `setNode` no longer adds node twice when `force` is true #322 --- src/nodes/NodeManager.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 2d1fc8240..747ffe4b3 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -459,8 +459,7 @@ class NodeManager { // Updating the refreshBucket timer this.refreshBucketUpdateDeadline(bucketIndex); return; - } - if (blocking) { + } else if (blocking) { this.logger.debug( `Bucket was full and blocking was true, garbage collecting old nodes to add ${nodesUtils.encodeNodeId( nodeId, From 17396ab9fe2d9cf7276460bdce86655897a9f1b2 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Thu, 21 Apr 2022 14:52:22 +1000 Subject: [PATCH 096/137] feat: generic `SetNodeQueue` class for queuing `setNode` operations `NodeManager.setNode` and `NodeConnectionManager.syncNodeGraph` now utilise a single, shared queue to asynchronously add nodes to the node graph without blocking the main loop. These methods are both blocking by default but can be made non-blocking by setting the `block` parameter to false. #322 --- src/PolykeyAgent.ts | 29 ++++- src/bootstrap/utils.ts | 4 + src/nodes/NodeConnectionManager.ts | 62 +++++---- src/nodes/NodeManager.ts | 120 ++---------------- src/nodes/SetNodeQueue.ts | 107 ++++++++++++++++ src/nodes/errors.ts | 6 + tests/agent/GRPCClientAgent.test.ts | 7 + tests/agent/service/notificationsSend.test.ts | 8 ++ .../gestaltsDiscoveryByIdentity.test.ts | 9 ++ .../service/gestaltsDiscoveryByNode.test.ts | 9 ++ .../gestaltsGestaltTrustByIdentity.test.ts | 15 ++- .../gestaltsGestaltTrustByNode.test.ts | 15 ++- tests/client/service/identitiesClaim.test.ts | 10 +- tests/client/service/nodesAdd.test.ts | 9 ++ tests/client/service/nodesClaim.test.ts | 13 +- tests/client/service/nodesFind.test.ts | 8 ++ tests/client/service/nodesPing.test.ts | 9 ++ .../client/service/notificationsClear.test.ts | 9 ++ .../client/service/notificationsRead.test.ts | 11 +- .../client/service/notificationsSend.test.ts | 11 +- tests/discovery/Discovery.test.ts | 15 ++- tests/nodes/NodeConnection.test.ts | 7 + .../NodeConnectionManager.general.test.ts | 13 ++ .../NodeConnectionManager.lifecycle.test.ts | 19 +++ .../NodeConnectionManager.seednodes.test.ts | 25 ++++ .../NodeConnectionManager.termination.test.ts | 10 ++ .../NodeConnectionManager.timeout.test.ts | 4 + tests/nodes/NodeManager.test.ts | 71 ++++++++++- .../NotificationsManager.test.ts | 7 + tests/vaults/VaultManager.test.ts | 3 + 30 files changed, 494 insertions(+), 151 deletions(-) create mode 100644 src/nodes/SetNodeQueue.ts diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index ddc7ca2cd..2b8951d91 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -34,6 +34,7 @@ import * as errors from './errors'; import * as utils from './utils'; import * as keysUtils from './keys/utils'; import * as nodesUtils from './nodes/utils'; +import SetNodeQueue from './nodes/SetNodeQueue'; type NetworkConfig = { forwardHost?: Host; @@ -87,6 +88,7 @@ class PolykeyAgent { gestaltGraph, proxy, nodeGraph, + setNodeQueue, nodeConnectionManager, nodeManager, discovery, @@ -132,6 +134,7 @@ class PolykeyAgent { gestaltGraph?: GestaltGraph; proxy?: Proxy; nodeGraph?: NodeGraph; + setNodeQueue?: SetNodeQueue; nodeConnectionManager?: NodeConnectionManager; nodeManager?: NodeManager; discovery?: Discovery; @@ -281,12 +284,18 @@ class PolykeyAgent { keyManager, logger: logger.getChild(NodeGraph.name), })); + setNodeQueue = + setNodeQueue ?? + new SetNodeQueue({ + logger: logger.getChild(SetNodeQueue.name), + }); nodeConnectionManager = nodeConnectionManager ?? new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, seedNodes, ...nodeConnectionManagerConfig_, logger: logger.getChild(NodeConnectionManager.name), @@ -299,6 +308,7 @@ class PolykeyAgent { keyManager, nodeGraph, nodeConnectionManager, + setNodeQueue, logger: logger.getChild(NodeManager.name), }); await nodeManager.start(); @@ -385,6 +395,7 @@ class PolykeyAgent { gestaltGraph, proxy, nodeGraph, + setNodeQueue, nodeConnectionManager, nodeManager, discovery, @@ -417,6 +428,7 @@ class PolykeyAgent { public readonly gestaltGraph: GestaltGraph; public readonly proxy: Proxy; public readonly nodeGraph: NodeGraph; + public readonly setNodeQueue: SetNodeQueue; public readonly nodeConnectionManager: NodeConnectionManager; public readonly nodeManager: NodeManager; public readonly discovery: Discovery; @@ -441,6 +453,7 @@ class PolykeyAgent { gestaltGraph, proxy, nodeGraph, + setNodeQueue, nodeConnectionManager, nodeManager, discovery, @@ -464,6 +477,7 @@ class PolykeyAgent { gestaltGraph: GestaltGraph; proxy: Proxy; nodeGraph: NodeGraph; + setNodeQueue: SetNodeQueue; nodeConnectionManager: NodeConnectionManager; nodeManager: NodeManager; discovery: Discovery; @@ -489,6 +503,7 @@ class PolykeyAgent { this.proxy = proxy; this.discovery = discovery; this.nodeGraph = nodeGraph; + this.setNodeQueue = setNodeQueue; this.nodeConnectionManager = nodeConnectionManager; this.nodeManager = nodeManager; this.vaultManager = vaultManager; @@ -562,10 +577,14 @@ class PolykeyAgent { ); // Reverse connection was established and authenticated, // add it to the node graph - await this.nodeManager.setNode(data.remoteNodeId, { - host: data.remoteHost, - port: data.remotePort, - }); + await this.nodeManager.setNode( + data.remoteNodeId, + { + host: data.remoteHost, + port: data.remotePort, + }, + false, + ); } }, ); @@ -647,6 +666,7 @@ class PolykeyAgent { proxyPort: networkConfig_.proxyPort, tlsConfig, }); + await this.setNodeQueue.start(); await this.nodeManager.start(); await this.nodeConnectionManager.start({ nodeManager: this.nodeManager }); await this.nodeGraph.start({ fresh }); @@ -704,6 +724,7 @@ class PolykeyAgent { await this.nodeConnectionManager.stop(); await this.nodeGraph.stop(); await this.nodeManager.stop(); + await this.setNodeQueue.stop(); await this.proxy.stop(); await this.grpcServerAgent.stop(); await this.grpcServerClient.stop(); diff --git a/src/bootstrap/utils.ts b/src/bootstrap/utils.ts index 422709b01..09aff4586 100644 --- a/src/bootstrap/utils.ts +++ b/src/bootstrap/utils.ts @@ -4,6 +4,7 @@ import path from 'path'; import Logger from '@matrixai/logger'; import { DB } from '@matrixai/db'; import * as bootstrapErrors from './errors'; +import SetNodeQueue from '../nodes/SetNodeQueue'; import { IdentitiesManager } from '../identities'; import { SessionManager } from '../sessions'; import { Status } from '../status'; @@ -141,10 +142,12 @@ async function bootstrapState({ keyManager, logger: logger.getChild(NodeGraph.name), }); + const setNodeQueue = new SetNodeQueue({ logger }); const nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, logger: logger.getChild(NodeConnectionManager.name), }); const nodeManager = new NodeManager({ @@ -153,6 +156,7 @@ async function bootstrapState({ nodeGraph, nodeConnectionManager, sigchain, + setNodeQueue, logger: logger.getChild(NodeManager.name), }); const notificationsManager = diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index f7ea93732..7d6b5d694 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -4,6 +4,7 @@ import type Proxy from '../network/Proxy'; import type { Host, Hostname, Port } from '../network/types'; import type { Timer } from '../types'; import type NodeGraph from './NodeGraph'; +import type SetNodeQueue from './SetNodeQueue'; import type { NodeAddress, NodeData, @@ -60,6 +61,7 @@ class NodeConnectionManager { protected nodeGraph: NodeGraph; protected keyManager: KeyManager; protected proxy: Proxy; + protected setNodeQueue: SetNodeQueue; // NodeManager has to be passed in during start to allow co-dependency protected nodeManager: NodeManager | undefined; protected seedNodes: SeedNodes; @@ -80,6 +82,7 @@ class NodeConnectionManager { keyManager, nodeGraph, proxy, + setNodeQueue, seedNodes = {}, initialClosestNodes = 3, connConnectTime = 20000, @@ -89,6 +92,7 @@ class NodeConnectionManager { nodeGraph: NodeGraph; keyManager: KeyManager; proxy: Proxy; + setNodeQueue: SetNodeQueue; seedNodes?: SeedNodes; initialClosestNodes?: number; connConnectTime?: number; @@ -99,6 +103,7 @@ class NodeConnectionManager { this.keyManager = keyManager; this.nodeGraph = nodeGraph; this.proxy = proxy; + this.setNodeQueue = setNodeQueue; this.seedNodes = seedNodes; this.initialClosestNodes = initialClosestNodes; this.connConnectTime = connConnectTime; @@ -301,7 +306,7 @@ class NodeConnectionManager { }); // We can assume connection was established and destination was valid, // we can add the target to the nodeGraph - await this.nodeManager?.setNode(targetNodeId, targetAddress); + await this.nodeManager?.setNode(targetNodeId, targetAddress, false); // Creating TTL timeout const timeToLiveTimer = setTimeout(async () => { await this.destroyConnection(targetNodeId); @@ -574,18 +579,12 @@ class NodeConnectionManager { /** * Perform an initial database synchronisation: get k of the closest nodes * from each seed node and add them to this database - * For now, we also attempt to establish a connection to each of them. - * If these nodes are offline, this will impose a performance penalty, - * so we should investigate performing this in the background if possible. - * Alternatively, we can also just add the nodes to our database without - * establishing connection. - * This has been removed from start() as there's a chicken-egg scenario - * where we require the NodeGraph instance to be created in order to get - * connections. - * @param timer Connection timeout timer + * Establish a proxy connection to each node before adding it + * By default this operation is blocking, set `block` to false to make it + * non-blocking */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) - public async syncNodeGraph(timer?: Timer) { + public async syncNodeGraph(block: boolean = true, timer?: Timer) { for (const seedNodeId of this.getSeedNodes()) { // Check if the connection is viable try { @@ -594,28 +593,43 @@ class NodeConnectionManager { if (e instanceof nodesErrors.ErrorNodeConnectionTimeout) continue; throw e; } - const nodes = await this.getRemoteNodeClosestNodes( seedNodeId, this.keyManager.getNodeId(), timer, ); for (const [nodeId, nodeData] of nodes) { - // FIXME: needs to ping the node right? we want to be non-blocking - try { - // FIXME: no tran needed - await this.nodeManager?.setNode(nodeId, nodeData.address); - } catch (e) { - if (!(e instanceof nodesErrors.ErrorNodeGraphSameNodeId)) throw e; + if (!block) { + this.setNodeQueue.queueSetNode(() => + this.nodeManager!.setNode(nodeId, nodeData.address), + ); + } else { + try { + // FIXME: no tran neededawait this.nodeManager?.setNode(nodeId, nodeData.address); + } catch (e) { + if (!(e instanceof nodesErrors.ErrorNodeGraphSameNodeId)) throw e; + } } } // Refreshing every bucket above the closest node - const [closestNode] = ( - await this.nodeGraph.getClosestNodes(this.keyManager.getNodeId(), 1) - ).pop()!; - const [bucketIndex] = this.nodeGraph.bucketIndex(closestNode); - for (let i = bucketIndex; i < this.nodeGraph.nodeIdBits; i++) { - this.nodeManager?.refreshBucketQueueAdd(i); + if (!block) { + this.setNodeQueue.queueSetNode(async () => { + const [closestNode] = ( + await this.nodeGraph.getClosestNodes(this.keyManager.getNodeId(), 1) + ).pop()!; + const [bucketIndex] = this.nodeGraph.bucketIndex(closestNode); + for (let i = bucketIndex; i < this.nodeGraph.nodeIdBits; i++) { + this.nodeManager?.refreshBucketQueueAdd(i); + } + }); + } else { + const [closestNode] = ( + await this.nodeGraph.getClosestNodes(this.keyManager.getNodeId(), 1) + ).pop()!; + const [bucketIndex] = this.nodeGraph.bucketIndex(closestNode); + for (let i = bucketIndex; i < this.nodeGraph.nodeIdBits; i++) { + this.nodeManager?.refreshBucketQueueAdd(i); + } } } } diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 747ffe4b3..2bc76bccb 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -1,6 +1,7 @@ import type { DB, DBTransaction } from '@matrixai/db'; import type NodeConnectionManager from './NodeConnectionManager'; import type NodeGraph from './NodeGraph'; +import type SetNodeQueue from './SetNodeQueue'; import type KeyManager from '../keys/KeyManager'; import type { PublicKeyPem } from '../keys/types'; import type Sigchain from '../sigchain/Sigchain'; @@ -37,18 +38,7 @@ class NodeManager { protected keyManager: KeyManager; protected nodeConnectionManager: NodeConnectionManager; protected nodeGraph: NodeGraph; - // SetNodeQueue - protected endQueue: boolean = false; - protected setNodeQueue: Array<{ - nodeId: NodeId; - nodeAddress: NodeAddress; - timeout?: number; - }> = []; - protected setNodeQueuePlug: Promise; - protected setNodeQueueUnplug: (() => void) | undefined; - protected setNodeQueueRunner: Promise; - protected setNodeQueueEmpty: Promise; - protected setNodeQueueDrained: () => void; + protected setNodeQueue: SetNodeQueue; // Refresh bucket timer protected refreshBucketDeadlineMap: Map = new Map(); protected refreshBucketTimer: NodeJS.Timer; @@ -67,6 +57,7 @@ class NodeManager { sigchain, nodeConnectionManager, nodeGraph, + setNodeQueue, refreshBucketTimerDefault = 3600000, // 1 hour in milliseconds logger, }: { @@ -75,6 +66,7 @@ class NodeManager { sigchain: Sigchain; nodeConnectionManager: NodeConnectionManager; nodeGraph: NodeGraph; + setNodeQueue: SetNodeQueue; refreshBucketTimerDefault?: number; logger?: Logger; }) { @@ -84,12 +76,12 @@ class NodeManager { this.sigchain = sigchain; this.nodeConnectionManager = nodeConnectionManager; this.nodeGraph = nodeGraph; + this.setNodeQueue = setNodeQueue; this.refreshBucketTimerDefault = refreshBucketTimerDefault; } public async start() { this.logger.info(`Starting ${this.constructor.name}`); - this.setNodeQueueRunner = this.startSetNodeQueue(); this.startRefreshBucketTimers(); this.refreshBucketQueueRunner = this.startRefreshBucketQueue(); this.logger.info(`Started ${this.constructor.name}`); @@ -97,7 +89,6 @@ class NodeManager { public async stop() { this.logger.info(`Stopping ${this.constructor.name}`); - await this.stopSetNodeQueue(); await this.stopRefreshBucketTimers(); await this.stopRefreshBucketQueue(); this.logger.info(`Stopped ${this.constructor.name}`); @@ -400,11 +391,12 @@ class NodeManager { } /** - * Adds a node to the node graph. This assumes that you have already authenticated the node. - * Updates the node if the node already exists. + * Adds a node to the node graph. This assumes that you have already authenticated the node + * Updates the node if the node already exists + * This operation is blocking by default - set `block` to false to make it non-blocking * @param nodeId - Id of the node we wish to add * @param nodeAddress - Expected address of the node we want to add - * @param blocking - Flag for if the operation should block or utilize the async queue + * @param block - Flag for if the operation should block or utilize the async queue * @param force - Flag for if we want to add the node without authenticating or if the bucket is full. * This will drop the oldest node in favor of the new. * @param timeout Connection timeout timeout @@ -414,7 +406,7 @@ class NodeManager { public async setNode( nodeId: NodeId, nodeAddress: NodeAddress, - blocking: boolean = false, + block: boolean = true, force: boolean = false, timeout?: number, tran: DBTransaction, @@ -459,7 +451,7 @@ class NodeManager { // Updating the refreshBucket timer this.refreshBucketUpdateDeadline(bucketIndex); return; - } else if (blocking) { + } else if (block) { this.logger.debug( `Bucket was full and blocking was true, garbage collecting old nodes to add ${nodesUtils.encodeNodeId( nodeId, @@ -478,7 +470,9 @@ class NodeManager { )} to queue`, ); // Re-attempt this later asynchronously by adding the the queue - this.queueSetNode(nodeId, nodeAddress, timeout); + this.setNodeQueue.queueSetNode(() => + this.setNode(nodeId, nodeAddress, true, false, timeout), + ); } } } @@ -557,92 +551,6 @@ class NodeManager { // Return await this.nodeGraph.refreshBuckets(tran); } - // SetNode queue - - /** - * This adds a setNode operation to the queue - */ - private queueSetNode( - nodeId: NodeId, - nodeAddress: NodeAddress, - timeout?: number, - ): void { - this.logger.debug(`Adding ${nodesUtils.encodeNodeId(nodeId)} to queue`); - this.setNodeQueue.push({ - nodeId, - nodeAddress, - timeout, - }); - this.unplugQueue(); - } - - /** - * This starts the process of digesting the queue - */ - private async startSetNodeQueue(): Promise { - this.logger.debug('Starting setNodeQueue'); - this.plugQueue(); - // While queue hasn't ended - while (true) { - // Wait for queue to be unplugged - await this.setNodeQueuePlug; - if (this.endQueue) break; - const job = this.setNodeQueue.shift(); - if (job == null) { - // If the queue is empty then we pause the queue - this.plugQueue(); - continue; - } - // Process the job - this.logger.debug( - `SetNodeQueue processing job for: ${nodesUtils.encodeNodeId( - job.nodeId, - )}`, - ); - await this.setNode(job.nodeId, job.nodeAddress, true, false, job.timeout); - } - this.logger.debug('SetNodeQueue has ended'); - } - - private async stopSetNodeQueue(): Promise { - this.logger.debug('Stopping setNodeQueue'); - // Tell the queue runner to end - this.endQueue = true; - this.unplugQueue(); - // Wait for runner to finish it's current job - await this.setNodeQueueRunner; - } - - private plugQueue(): void { - if (this.setNodeQueueUnplug == null) { - this.logger.debug('Plugging setNodeQueue'); - // Pausing queue - this.setNodeQueuePlug = new Promise((resolve) => { - this.setNodeQueueUnplug = resolve; - }); - // Signaling queue is empty - if (this.setNodeQueueDrained != null) this.setNodeQueueDrained(); - } - } - - private unplugQueue(): void { - if (this.setNodeQueueUnplug != null) { - this.logger.debug('Unplugging setNodeQueue'); - // Starting queue - this.setNodeQueueUnplug(); - this.setNodeQueueUnplug = undefined; - // Signalling queue is running - this.setNodeQueueEmpty = new Promise((resolve) => { - this.setNodeQueueDrained = resolve; - }); - } - } - - @ready(new nodesErrors.ErrorNodeManagerNotRunning()) - public async queueDrained(): Promise { - await this.setNodeQueueEmpty; - } - /** * Kademlia refresh bucket operation. * It picks a random node within a bucket and does a search for that node. diff --git a/src/nodes/SetNodeQueue.ts b/src/nodes/SetNodeQueue.ts new file mode 100644 index 000000000..a405c3418 --- /dev/null +++ b/src/nodes/SetNodeQueue.ts @@ -0,0 +1,107 @@ +import Logger from '@matrixai/logger'; +import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; +import * as nodesErrors from './errors'; + +interface SetNodeQueue extends StartStop {} +@StartStop() +class SetNodeQueue { + protected logger: Logger; + protected endQueue: boolean = false; + protected setNodeQueue: Array<() => Promise> = []; + protected setNodeQueuePlug: Promise; + protected setNodeQueueUnplug: (() => void) | undefined; + protected setNodeQueueRunner: Promise; + protected setNodeQueueEmpty: Promise; + protected setNodeQueueDrained: () => void; + + constructor({ logger }: { logger?: Logger }) { + this.logger = logger ?? new Logger(this.constructor.name); + } + + public async start() { + this.logger.info(`Starting ${this.constructor.name}`); + this.setNodeQueueRunner = this.startSetNodeQueue(); + this.logger.info(`Started ${this.constructor.name}`); + } + + public async stop() { + this.logger.info(`Stopping ${this.constructor.name}`); + await this.stopSetNodeQueue(); + this.logger.info(`Stopped ${this.constructor.name}`); + } + + /** + * This adds a setNode operation to the queue + */ + public queueSetNode(f: () => Promise): void { + this.setNodeQueue.push(f); + this.unplugQueue(); + } + + /** + * This starts the process of digesting the queue + */ + private async startSetNodeQueue(): Promise { + this.logger.debug('Starting setNodeQueue'); + this.plugQueue(); + // While queue hasn't ended + while (true) { + // Wait for queue to be unplugged + await this.setNodeQueuePlug; + if (this.endQueue) break; + const job = this.setNodeQueue.shift(); + if (job == null) { + // If the queue is empty then we pause the queue + this.plugQueue(); + continue; + } + try { + await job(); + } catch (e) { + if (!(e instanceof nodesErrors.ErrorNodeGraphSameNodeId)) throw e; + } + } + this.logger.debug('setNodeQueue has ended'); + } + + private async stopSetNodeQueue(): Promise { + this.logger.debug('Stopping setNodeQueue'); + // Tell the queue runner to end + this.endQueue = true; + this.unplugQueue(); + // Wait for runner to finish it's current job + await this.setNodeQueueRunner; + } + + private plugQueue(): void { + if (this.setNodeQueueUnplug == null) { + this.logger.debug('Plugging setNodeQueue'); + // Pausing queue + this.setNodeQueuePlug = new Promise((resolve) => { + this.setNodeQueueUnplug = resolve; + }); + // Signaling queue is empty + if (this.setNodeQueueDrained != null) this.setNodeQueueDrained(); + } + } + + private unplugQueue(): void { + if (this.setNodeQueueUnplug != null) { + this.logger.debug('Unplugging setNodeQueue'); + // Starting queue + this.setNodeQueueUnplug(); + this.setNodeQueueUnplug = undefined; + // Signalling queue is running + this.setNodeQueueEmpty = new Promise((resolve) => { + this.setNodeQueueDrained = resolve; + }); + } + } + + @ready(new nodesErrors.ErrorSetNodeQueueNotRunning()) + public async queueDrained(): Promise { + await this.setNodeQueueEmpty; + } +} + +export default SetNodeQueue; diff --git a/src/nodes/errors.ts b/src/nodes/errors.ts index a98fbcaa6..159021b9c 100644 --- a/src/nodes/errors.ts +++ b/src/nodes/errors.ts @@ -12,6 +12,11 @@ class ErrorNodeManagerNotRunning extends ErrorNodes { exitCode = sysexits.USAGE; } +class ErrorSetNodeQueueNotRunning extends ErrorNodes { + static description = 'SetNodeQueue is not running'; + exitCode = sysexits.USAGE; +} + class ErrorNodeGraphRunning extends ErrorNodes { static description = 'NodeGraph is running'; exitCode = sysexits.USAGE; @@ -86,6 +91,7 @@ export { ErrorNodes, ErrorNodeAborted, ErrorNodeManagerNotRunning, + ErrorSetNodeQueueNotRunning, ErrorNodeGraphRunning, ErrorNodeGraphNotRunning, ErrorNodeGraphDestroyed, diff --git a/tests/agent/GRPCClientAgent.test.ts b/tests/agent/GRPCClientAgent.test.ts index 5cc38708a..2a9644055 100644 --- a/tests/agent/GRPCClientAgent.test.ts +++ b/tests/agent/GRPCClientAgent.test.ts @@ -22,6 +22,7 @@ import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as agentErrors from '@/agent/errors'; import * as keysUtils from '@/keys/utils'; import { timerStart } from '@/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testAgentUtils from './utils'; describe(GRPCClientAgent.name, () => { @@ -49,6 +50,7 @@ describe(GRPCClientAgent.name, () => { let keyManager: KeyManager; let vaultManager: VaultManager; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let sigchain: Sigchain; @@ -110,10 +112,12 @@ describe(GRPCClientAgent.name, () => { keyManager, logger, }); + setNodeQueue = new SetNodeQueue({ logger }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, logger, }); nodeManager = new NodeManager({ @@ -122,8 +126,10 @@ describe(GRPCClientAgent.name, () => { keyManager: keyManager, nodeGraph: nodeGraph, nodeConnectionManager: nodeConnectionManager, + setNodeQueue, logger: logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = @@ -178,6 +184,7 @@ describe(GRPCClientAgent.name, () => { await sigchain.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); + await setNodeQueue.stop(); await nodeGraph.stop(); await gestaltGraph.stop(); await acl.stop(); diff --git a/tests/agent/service/notificationsSend.test.ts b/tests/agent/service/notificationsSend.test.ts index 46a9aa07e..9425743b8 100644 --- a/tests/agent/service/notificationsSend.test.ts +++ b/tests/agent/service/notificationsSend.test.ts @@ -27,6 +27,7 @@ import * as notificationsPB from '@/proto/js/polykey/v1/notifications/notificati import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import * as notificationsUtils from '@/notifications/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import { expectRemoteError } from '../../utils'; @@ -40,6 +41,7 @@ describe('notificationsSend', () => { let senderKeyManager: KeyManager; let dataDir: string; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let notificationsManager: NotificationsManager; @@ -109,10 +111,14 @@ describe('notificationsSend', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -123,8 +129,10 @@ describe('notificationsSend', () => { nodeGraph, nodeConnectionManager, sigchain, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = diff --git a/tests/client/service/gestaltsDiscoveryByIdentity.test.ts b/tests/client/service/gestaltsDiscoveryByIdentity.test.ts index a9a4d7a17..6fec772c1 100644 --- a/tests/client/service/gestaltsDiscoveryByIdentity.test.ts +++ b/tests/client/service/gestaltsDiscoveryByIdentity.test.ts @@ -24,6 +24,7 @@ import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as identitiesPB from '@/proto/js/polykey/v1/identities/identities_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; describe('gestaltsDiscoveryByIdentity', () => { @@ -59,6 +60,7 @@ describe('gestaltsDiscoveryByIdentity', () => { let gestaltGraph: GestaltGraph; let identitiesManager: IdentitiesManager; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let sigchain: Sigchain; @@ -125,10 +127,14 @@ describe('gestaltsDiscoveryByIdentity', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -139,8 +145,10 @@ describe('gestaltsDiscoveryByIdentity', () => { nodeConnectionManager, nodeGraph, sigchain, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); discovery = await Discovery.createDiscovery({ @@ -179,6 +187,7 @@ describe('gestaltsDiscoveryByIdentity', () => { await nodeGraph.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); + await setNodeQueue.stop(); await sigchain.stop(); await proxy.stop(); await identitiesManager.stop(); diff --git a/tests/client/service/gestaltsDiscoveryByNode.test.ts b/tests/client/service/gestaltsDiscoveryByNode.test.ts index e34f5f8ed..1e97b6250 100644 --- a/tests/client/service/gestaltsDiscoveryByNode.test.ts +++ b/tests/client/service/gestaltsDiscoveryByNode.test.ts @@ -25,6 +25,7 @@ import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import * as testNodesUtils from '../../nodes/utils'; @@ -60,6 +61,7 @@ describe('gestaltsDiscoveryByNode', () => { let gestaltGraph: GestaltGraph; let identitiesManager: IdentitiesManager; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let sigchain: Sigchain; @@ -126,10 +128,14 @@ describe('gestaltsDiscoveryByNode', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -140,8 +146,10 @@ describe('gestaltsDiscoveryByNode', () => { nodeConnectionManager, nodeGraph, sigchain, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); discovery = await Discovery.createDiscovery({ @@ -180,6 +188,7 @@ describe('gestaltsDiscoveryByNode', () => { await nodeGraph.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); + await setNodeQueue.stop(); await sigchain.stop(); await proxy.stop(); await identitiesManager.stop(); diff --git a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts index 949a5f5e4..17de35e72 100644 --- a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts +++ b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts @@ -31,6 +31,7 @@ import * as gestaltsErrors from '@/gestalts/errors'; import * as keysUtils from '@/keys/utils'; import * as clientUtils from '@/client/utils/utils'; import * as nodesUtils from '@/nodes/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import TestProvider from '../../identities/TestProvider'; import { expectRemoteError } from '../../utils'; @@ -115,6 +116,7 @@ describe('gestaltsGestaltTrustByIdentity', () => { let discovery: Discovery; let gestaltGraph: GestaltGraph; let identitiesManager: IdentitiesManager; + let setNodeQueue: SetNodeQueue; let nodeManager: NodeManager; let nodeConnectionManager: NodeConnectionManager; let nodeGraph: NodeGraph; @@ -191,10 +193,14 @@ describe('gestaltsGestaltTrustByIdentity', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -202,11 +208,13 @@ describe('gestaltsGestaltTrustByIdentity', () => { nodeManager = new NodeManager({ db, keyManager, - sigchain, - nodeGraph, nodeConnectionManager, - logger: logger.getChild('nodeManager'), + nodeGraph, + sigchain, + setNodeQueue, + logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); await nodeManager.setNode(nodesUtils.decodeNodeId(nodeId)!, { @@ -250,6 +258,7 @@ describe('gestaltsGestaltTrustByIdentity', () => { await discovery.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); + await setNodeQueue.stop(); await nodeGraph.stop(); await proxy.stop(); await sigchain.stop(); diff --git a/tests/client/service/gestaltsGestaltTrustByNode.test.ts b/tests/client/service/gestaltsGestaltTrustByNode.test.ts index d8ecae06e..5a409c120 100644 --- a/tests/client/service/gestaltsGestaltTrustByNode.test.ts +++ b/tests/client/service/gestaltsGestaltTrustByNode.test.ts @@ -33,6 +33,7 @@ import * as claimsUtils from '@/claims/utils'; import * as keysUtils from '@/keys/utils'; import * as clientUtils from '@/client/utils/utils'; import * as nodesUtils from '@/nodes/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import TestProvider from '../../identities/TestProvider'; @@ -114,6 +115,7 @@ describe('gestaltsGestaltTrustByNode', () => { let discovery: Discovery; let gestaltGraph: GestaltGraph; let identitiesManager: IdentitiesManager; + let setNodeQueue: SetNodeQueue; let nodeManager: NodeManager; let nodeConnectionManager: NodeConnectionManager; let nodeGraph: NodeGraph; @@ -190,10 +192,14 @@ describe('gestaltsGestaltTrustByNode', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -201,11 +207,13 @@ describe('gestaltsGestaltTrustByNode', () => { nodeManager = new NodeManager({ db, keyManager, - sigchain, - nodeGraph, nodeConnectionManager, - logger: logger.getChild('nodeManager'), + nodeGraph, + sigchain, + setNodeQueue, + logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); await nodeManager.setNode(nodesUtils.decodeNodeId(nodeId)!, { @@ -249,6 +257,7 @@ describe('gestaltsGestaltTrustByNode', () => { await discovery.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); + await setNodeQueue.stop(); await nodeGraph.stop(); await proxy.stop(); await sigchain.stop(); diff --git a/tests/client/service/identitiesClaim.test.ts b/tests/client/service/identitiesClaim.test.ts index f03e1be07..5038821e9 100644 --- a/tests/client/service/identitiesClaim.test.ts +++ b/tests/client/service/identitiesClaim.test.ts @@ -26,6 +26,7 @@ import * as keysUtils from '@/keys/utils'; import * as claimsUtils from '@/claims/utils'; import * as nodesUtils from '@/nodes/utils'; import * as validationErrors from '@/validation/errors'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import TestProvider from '../../identities/TestProvider'; import { expectRemoteError } from '../../utils'; @@ -86,6 +87,7 @@ describe('identitiesClaim', () => { let testProvider: TestProvider; let identitiesManager: IdentitiesManager; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let sigchain: Sigchain; let proxy: Proxy; @@ -137,13 +139,18 @@ describe('identitiesClaim', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ connConnectTime: 2000, proxy, keyManager, nodeGraph, - logger: logger.getChild('nodeConnectionManager'), + setNodeQueue, + logger: logger.getChild('NodeConnectionManager'), }); + await setNodeQueue.start(); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); const clientService = { identitiesClaim: identitiesClaim({ @@ -172,6 +179,7 @@ describe('identitiesClaim', () => { await grpcClient.destroy(); await grpcServer.stop(); await nodeConnectionManager.stop(); + await setNodeQueue.stop(); await nodeGraph.stop(); await sigchain.stop(); await proxy.stop(); diff --git a/tests/client/service/nodesAdd.test.ts b/tests/client/service/nodesAdd.test.ts index 94d925acc..e6d037034 100644 --- a/tests/client/service/nodesAdd.test.ts +++ b/tests/client/service/nodesAdd.test.ts @@ -22,6 +22,7 @@ import * as nodesUtils from '@/nodes/utils'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import { expectRemoteError } from '../../utils'; @@ -50,6 +51,7 @@ describe('nodesAdd', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let sigchain: Sigchain; @@ -96,10 +98,14 @@ describe('nodesAdd', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -110,8 +116,10 @@ describe('nodesAdd', () => { nodeConnectionManager, nodeGraph, sigchain, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const clientService = { @@ -140,6 +148,7 @@ describe('nodesAdd', () => { await grpcServer.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await setNodeQueue.stop(); await sigchain.stop(); await proxy.stop(); await db.stop(); diff --git a/tests/client/service/nodesClaim.test.ts b/tests/client/service/nodesClaim.test.ts index 47102fe1a..21b6a4a5a 100644 --- a/tests/client/service/nodesClaim.test.ts +++ b/tests/client/service/nodesClaim.test.ts @@ -24,6 +24,7 @@ import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; describe('nodesClaim', () => { @@ -75,6 +76,7 @@ describe('nodesClaim', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let notificationsManager: NotificationsManager; @@ -126,10 +128,14 @@ describe('nodesClaim', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -137,11 +143,13 @@ describe('nodesClaim', () => { nodeManager = new NodeManager({ db, keyManager, - sigchain, - nodeGraph, nodeConnectionManager, + nodeGraph, + sigchain, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = @@ -179,6 +187,7 @@ describe('nodesClaim', () => { await grpcClient.destroy(); await grpcServer.stop(); await nodeConnectionManager.stop(); + await setNodeQueue.stop(); await nodeGraph.stop(); await notificationsManager.stop(); await sigchain.stop(); diff --git a/tests/client/service/nodesFind.test.ts b/tests/client/service/nodesFind.test.ts index 21372cb4c..095139160 100644 --- a/tests/client/service/nodesFind.test.ts +++ b/tests/client/service/nodesFind.test.ts @@ -20,6 +20,7 @@ import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import { expectRemoteError } from '../../utils'; @@ -56,6 +57,7 @@ describe('nodesFind', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let sigchain: Sigchain; let proxy: Proxy; @@ -101,14 +103,19 @@ describe('nodesFind', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); + await setNodeQueue.start(); await nodeConnectionManager.start({ nodeManager: {} as NodeManager }); const clientService = { nodesFind: nodesFind({ @@ -136,6 +143,7 @@ describe('nodesFind', () => { await sigchain.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await setNodeQueue.stop(); await proxy.stop(); await db.stop(); await keyManager.stop(); diff --git a/tests/client/service/nodesPing.test.ts b/tests/client/service/nodesPing.test.ts index 6fd489d36..bd1409b30 100644 --- a/tests/client/service/nodesPing.test.ts +++ b/tests/client/service/nodesPing.test.ts @@ -21,6 +21,7 @@ import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import { expectRemoteError } from '../../utils'; @@ -55,6 +56,7 @@ describe('nodesPing', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let sigchain: Sigchain; @@ -101,10 +103,14 @@ describe('nodesPing', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -115,8 +121,10 @@ describe('nodesPing', () => { nodeConnectionManager, nodeGraph, sigchain, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeConnectionManager.start({ nodeManager }); const clientService = { nodesPing: nodesPing({ @@ -144,6 +152,7 @@ describe('nodesPing', () => { await sigchain.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await setNodeQueue.stop(); await proxy.stop(); await db.stop(); await keyManager.stop(); diff --git a/tests/client/service/notificationsClear.test.ts b/tests/client/service/notificationsClear.test.ts index c2a1c5cd3..7020f7d84 100644 --- a/tests/client/service/notificationsClear.test.ts +++ b/tests/client/service/notificationsClear.test.ts @@ -21,6 +21,7 @@ import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_ import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as keysUtils from '@/keys/utils'; import * as clientUtils from '@/client/utils/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; describe('notificationsClear', () => { @@ -53,6 +54,7 @@ describe('notificationsClear', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let notificationsManager: NotificationsManager; @@ -105,10 +107,14 @@ describe('notificationsClear', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -119,8 +125,10 @@ describe('notificationsClear', () => { nodeConnectionManager, nodeGraph, sigchain, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = @@ -159,6 +167,7 @@ describe('notificationsClear', () => { await notificationsManager.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await setNodeQueue.stop(); await sigchain.stop(); await proxy.stop(); await acl.stop(); diff --git a/tests/client/service/notificationsRead.test.ts b/tests/client/service/notificationsRead.test.ts index 24b8b9542..0f5b80610 100644 --- a/tests/client/service/notificationsRead.test.ts +++ b/tests/client/service/notificationsRead.test.ts @@ -23,6 +23,7 @@ import * as notificationsPB from '@/proto/js/polykey/v1/notifications/notificati import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import * as clientUtils from '@/client/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import * as testNodesUtils from '../../nodes/utils'; @@ -128,6 +129,7 @@ describe('notificationsRead', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let notificationsManager: NotificationsManager; @@ -180,10 +182,14 @@ describe('notificationsRead', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -191,11 +197,13 @@ describe('notificationsRead', () => { nodeManager = new NodeManager({ db, keyManager, - nodeGraph, nodeConnectionManager, + nodeGraph, sigchain, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = @@ -235,6 +243,7 @@ describe('notificationsRead', () => { await sigchain.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await setNodeQueue.stop(); await proxy.stop(); await acl.stop(); await db.stop(); diff --git a/tests/client/service/notificationsSend.test.ts b/tests/client/service/notificationsSend.test.ts index 220edfe83..a0f471b58 100644 --- a/tests/client/service/notificationsSend.test.ts +++ b/tests/client/service/notificationsSend.test.ts @@ -24,6 +24,7 @@ import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import * as notificationsUtils from '@/notifications/utils'; import * as clientUtils from '@/client/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; describe('notificationsSend', () => { @@ -63,6 +64,7 @@ describe('notificationsSend', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let notificationsManager: NotificationsManager; @@ -114,10 +116,14 @@ describe('notificationsSend', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -125,11 +131,13 @@ describe('notificationsSend', () => { nodeManager = new NodeManager({ db, keyManager, - nodeGraph, nodeConnectionManager, + nodeGraph, sigchain, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = @@ -167,6 +175,7 @@ describe('notificationsSend', () => { await notificationsManager.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await setNodeQueue.stop(); await sigchain.stop(); await proxy.stop(); await acl.stop(); diff --git a/tests/discovery/Discovery.test.ts b/tests/discovery/Discovery.test.ts index da9acd92b..04f5b8236 100644 --- a/tests/discovery/Discovery.test.ts +++ b/tests/discovery/Discovery.test.ts @@ -21,6 +21,7 @@ import * as nodesUtils from '@/nodes/utils'; import * as claimsUtils from '@/claims/utils'; import * as discoveryErrors from '@/discovery/errors'; import * as keysUtils from '@/keys/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testNodesUtils from '../nodes/utils'; import * as testUtils from '../utils'; import TestProvider from '../identities/TestProvider'; @@ -47,6 +48,7 @@ describe('Discovery', () => { let gestaltGraph: GestaltGraph; let identitiesManager: IdentitiesManager; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let db: DB; @@ -130,10 +132,14 @@ describe('Discovery', () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -141,11 +147,13 @@ describe('Discovery', () => { nodeManager = new NodeManager({ db, keyManager, - sigchain, - nodeGraph, nodeConnectionManager, - logger: logger.getChild('nodeManager'), + nodeGraph, + sigchain, + setNodeQueue, + logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); // Set up other gestalt @@ -204,6 +212,7 @@ describe('Discovery', () => { await nodeB.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); + await setNodeQueue.stop(); await nodeGraph.stop(); await proxy.stop(); await sigchain.stop(); diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index 35c084fa9..99de0bbe8 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -34,6 +34,7 @@ import * as nodesUtils from '@/nodes/utils'; import * as agentErrors from '@/agent/errors'; import * as grpcUtils from '@/grpc/utils'; import { timerStart } from '@/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testNodesUtils from './utils'; import * as testUtils from '../utils'; import * as grpcTestUtils from '../grpc/utils'; @@ -84,6 +85,7 @@ describe('${NodeConnection.name} test', () => { let serverKeyManager: KeyManager; let serverVaultManager: VaultManager; let serverNodeGraph: NodeGraph; + let serverSetNodeQueue: SetNodeQueue; let serverNodeConnectionManager: NodeConnectionManager; let serverNodeManager: NodeManager; let serverSigchain: Sigchain; @@ -231,10 +233,12 @@ describe('${NodeConnection.name} test', () => { logger, }); + serverSetNodeQueue = new SetNodeQueue({ logger }); serverNodeConnectionManager = new NodeConnectionManager({ keyManager: serverKeyManager, nodeGraph: serverNodeGraph, proxy: serverProxy, + setNodeQueue: serverSetNodeQueue, logger, }); serverNodeManager = new NodeManager({ @@ -243,8 +247,10 @@ describe('${NodeConnection.name} test', () => { keyManager: serverKeyManager, nodeGraph: serverNodeGraph, nodeConnectionManager: serverNodeConnectionManager, + setNodeQueue: serverSetNodeQueue, logger: logger, }); + await serverSetNodeQueue.start(); await serverNodeManager.start(); await serverNodeConnectionManager.start({ nodeManager: serverNodeManager }); serverVaultManager = await VaultManager.createVaultManager({ @@ -356,6 +362,7 @@ describe('${NodeConnection.name} test', () => { await serverNodeGraph.destroy(); await serverNodeConnectionManager.stop(); await serverNodeManager.stop(); + await serverSetNodeQueue.stop(); await serverNotificationsManager.stop(); await serverNotificationsManager.destroy(); await agentTestUtils.closeTestAgentServer(agentServer); diff --git a/tests/nodes/NodeConnectionManager.general.test.ts b/tests/nodes/NodeConnectionManager.general.test.ts index 6231e5dcc..dd30f9049 100644 --- a/tests/nodes/NodeConnectionManager.general.test.ts +++ b/tests/nodes/NodeConnectionManager.general.test.ts @@ -20,6 +20,7 @@ import * as keysUtils from '@/keys/utils'; import * as grpcUtils from '@/grpc/utils'; import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testNodesUtils from './utils'; describe(`${NodeConnectionManager.name} general test`, () => { @@ -76,6 +77,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { let db: DB; let proxy: Proxy; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let remoteNode1: PolykeyAgent; let remoteNode2: PolykeyAgent; @@ -191,6 +193,10 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); + await setNodeQueue.start(); const tlsConfig = { keyPrivatePem: keyManager.getRootKeyPairPem().privateKey, certChainPem: keysUtils.certToPem(keyManager.getRootCert()), @@ -216,6 +222,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { }); afterEach(async () => { + await setNodeQueue.stop(); await nodeGraph.stop(); await nodeGraph.destroy(); await db.stop(); @@ -232,6 +239,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -259,6 +267,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -300,6 +309,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -353,6 +363,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: logger.getChild('NodeConnectionManager'), }); @@ -424,6 +435,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -461,6 +473,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); diff --git a/tests/nodes/NodeConnectionManager.lifecycle.test.ts b/tests/nodes/NodeConnectionManager.lifecycle.test.ts index 979403ec3..bf719789a 100644 --- a/tests/nodes/NodeConnectionManager.lifecycle.test.ts +++ b/tests/nodes/NodeConnectionManager.lifecycle.test.ts @@ -19,6 +19,7 @@ import * as nodesErrors from '@/nodes/errors'; import * as keysUtils from '@/keys/utils'; import * as grpcUtils from '@/grpc/utils'; import { timerStart } from '@/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; describe(`${NodeConnectionManager.name} lifecycle test`, () => { const logger = new Logger( @@ -76,6 +77,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { let proxy: Proxy; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let remoteNode1: PolykeyAgent; let remoteNode2: PolykeyAgent; @@ -154,6 +156,10 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, logger: logger.getChild('NodeGraph'), }); + setNodeQueue = new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }); + await setNodeQueue.start(); const tlsConfig = { keyPrivatePem: keyManager.getRootKeyPairPem().privateKey, certChainPem: keysUtils.certToPem(keyManager.getRootCert()), @@ -179,6 +185,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { }); afterEach(async () => { + await setNodeQueue.stop(); await nodeGraph.stop(); await nodeGraph.destroy(); await db.stop(); @@ -197,6 +204,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -222,6 +230,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -256,6 +265,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -284,6 +294,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -336,6 +347,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, connConnectTime: 500, logger: nodeConnectionManagerLogger, }); @@ -377,6 +389,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -403,6 +416,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -436,6 +450,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -469,6 +484,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -511,6 +527,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -531,6 +548,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -556,6 +574,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); diff --git a/tests/nodes/NodeConnectionManager.seednodes.test.ts b/tests/nodes/NodeConnectionManager.seednodes.test.ts index 4d47afb0c..ae186f451 100644 --- a/tests/nodes/NodeConnectionManager.seednodes.test.ts +++ b/tests/nodes/NodeConnectionManager.seednodes.test.ts @@ -17,6 +17,7 @@ import Proxy from '@/network/Proxy'; import * as nodesUtils from '@/nodes/utils'; import * as keysUtils from '@/keys/utils'; import * as grpcUtils from '@/grpc/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; describe(`${NodeConnectionManager.name} seed nodes test`, () => { const logger = new Logger( @@ -190,6 +191,9 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue: new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }), seedNodes: dummySeedNodes, logger: logger, }); @@ -213,6 +217,9 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue: new SetNodeQueue({ + logger: logger.getChild('SetNodeQueue'), + }), seedNodes: dummySeedNodes, logger: logger, }); @@ -230,6 +237,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { test('should synchronise nodeGraph', async () => { let nodeConnectionManager: NodeConnectionManager | undefined; let nodeManager: NodeManager | undefined; + let setNodeQueue: SetNodeQueue | undefined; const mockedRefreshBucket = jest.spyOn( NodeManager.prototype, 'refreshBucket', @@ -245,10 +253,12 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { host: remoteNode2.proxy.getProxyHost(), port: remoteNode2.proxy.getProxyPort(), }; + setNodeQueue = new SetNodeQueue({ logger }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, seedNodes, logger: logger, }); @@ -258,8 +268,10 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { logger, nodeConnectionManager, nodeGraph, + setNodeQueue, sigchain: {} as Sigchain, }); + await setNodeQueue.start(); await nodeManager.start(); await remoteNode1.nodeGraph.setNode(nodeId1, { host: serverHost, @@ -278,11 +290,13 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { mockedRefreshBucket.mockRestore(); await nodeManager?.stop(); await nodeConnectionManager?.stop(); + await setNodeQueue?.stop(); } }); test('should call refreshBucket when syncing nodeGraph', async () => { let nodeConnectionManager: NodeConnectionManager | undefined; let nodeManager: NodeManager | undefined; + let setNodeQueue: SetNodeQueue | undefined; const mockedRefreshBucket = jest.spyOn( NodeManager.prototype, 'refreshBucket', @@ -298,10 +312,12 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { host: remoteNode2.proxy.getProxyHost(), port: remoteNode2.proxy.getProxyPort(), }; + setNodeQueue = new SetNodeQueue({ logger }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, seedNodes, logger: logger, }); @@ -312,7 +328,9 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { nodeConnectionManager, nodeGraph, sigchain: {} as Sigchain, + setNodeQueue, }); + await setNodeQueue.start(); await nodeManager.start(); await remoteNode1.nodeGraph.setNode(nodeId1, { host: serverHost, @@ -330,11 +348,13 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { mockedRefreshBucket.mockRestore(); await nodeManager?.stop(); await nodeConnectionManager?.stop(); + await setNodeQueue?.stop(); } }); test('should handle an offline seed node when synchronising nodeGraph', async () => { let nodeConnectionManager: NodeConnectionManager | undefined; let nodeManager: NodeManager | undefined; + let setNodeQueue: SetNodeQueue | undefined; const mockedRefreshBucket = jest.spyOn( NodeManager.prototype, 'refreshBucket', @@ -363,10 +383,12 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { host: serverHost, port: serverPort, }); + setNodeQueue = new SetNodeQueue({ logger }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, + setNodeQueue, seedNodes, connConnectTime: 500, logger: logger, @@ -378,7 +400,9 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { nodeConnectionManager, nodeGraph, sigchain: {} as Sigchain, + setNodeQueue, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); // This should complete without error @@ -390,6 +414,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { mockedRefreshBucket.mockRestore(); await nodeConnectionManager?.stop(); await nodeManager?.stop(); + await setNodeQueue?.stop(); } }); }); diff --git a/tests/nodes/NodeConnectionManager.termination.test.ts b/tests/nodes/NodeConnectionManager.termination.test.ts index 0422cf223..89358557b 100644 --- a/tests/nodes/NodeConnectionManager.termination.test.ts +++ b/tests/nodes/NodeConnectionManager.termination.test.ts @@ -2,6 +2,7 @@ import type { AddressInfo } from 'net'; import type { NodeId, NodeIdString, SeedNodes } from '@/nodes/types'; import type { Host, Port, TLSConfig } from '@/network/types'; import type NodeManager from '@/nodes/NodeManager'; +import type SetNodeQueue from '@/nodes/SetNodeQueue'; import net from 'net'; import fs from 'fs'; import path from 'path'; @@ -246,6 +247,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue: {} as SetNodeQueue, logger: logger, connConnectTime: 2000, }); @@ -286,6 +288,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue: {} as SetNodeQueue, logger: logger, connConnectTime: 2000, }); @@ -329,6 +332,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue: {} as SetNodeQueue, logger: logger, connConnectTime: 2000, }); @@ -372,6 +376,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, + setNodeQueue: {} as SetNodeQueue, logger: logger, connConnectTime: 2000, }); @@ -429,6 +434,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, + setNodeQueue: {} as SetNodeQueue, logger: logger, connConnectTime: 2000, }); @@ -508,6 +514,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, + setNodeQueue: {} as SetNodeQueue, logger: logger, connConnectTime: 2000, }); @@ -580,6 +587,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, + setNodeQueue: {} as SetNodeQueue, logger: logger, connConnectTime: 2000, }); @@ -657,6 +665,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, + setNodeQueue: {} as SetNodeQueue, logger: logger, connConnectTime: 2000, }); @@ -734,6 +743,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, + setNodeQueue: {} as SetNodeQueue, logger: logger, connConnectTime: 2000, }); diff --git a/tests/nodes/NodeConnectionManager.timeout.test.ts b/tests/nodes/NodeConnectionManager.timeout.test.ts index 494350f52..e07958140 100644 --- a/tests/nodes/NodeConnectionManager.timeout.test.ts +++ b/tests/nodes/NodeConnectionManager.timeout.test.ts @@ -1,6 +1,7 @@ import type { NodeId, NodeIdString, SeedNodes } from '@/nodes/types'; import type { Host, Port } from '@/network/types'; import type NodeManager from 'nodes/NodeManager'; +import type SetNodeQueue from '@/nodes/SetNodeQueue'; import fs from 'fs'; import path from 'path'; import os from 'os'; @@ -188,6 +189,7 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue: {} as SetNodeQueue, connTimeoutTime: 500, logger: nodeConnectionManagerLogger, }); @@ -225,6 +227,7 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue: {} as SetNodeQueue, connTimeoutTime: 1000, logger: nodeConnectionManagerLogger, }); @@ -278,6 +281,7 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { keyManager, nodeGraph, proxy, + setNodeQueue: {} as SetNodeQueue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index b83be35d8..7815c34e0 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -20,6 +20,7 @@ import { promise, promisify, sleep } from '@/utils'; import * as nodesUtils from '@/nodes/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as nodesErrors from '@/nodes/errors'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as nodesTestUtils from './utils'; import { generateNodeIdForBucket } from './utils'; @@ -30,6 +31,7 @@ describe(`${NodeManager.name} test`, () => { ]); let dataDir: string; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let proxy: Proxy; let keyManager: KeyManager; @@ -111,9 +113,11 @@ describe(`${NodeManager.name} test`, () => { keyManager, logger, }); + setNodeQueue = new SetNodeQueue({ logger }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, + setNodeQueue, proxy, logger, }); @@ -122,6 +126,7 @@ describe(`${NodeManager.name} test`, () => { mockedPingNode.mockClear(); mockedPingNode.mockImplementation(async (_) => true); await nodeConnectionManager.stop(); + await setNodeQueue.stop(); await nodeGraph.stop(); await nodeGraph.destroy(); await sigchain.stop(); @@ -167,6 +172,7 @@ describe(`${NodeManager.name} test`, () => { keyManager, nodeGraph, nodeConnectionManager, + setNodeQueue, logger, }); await nodeManager.start(); @@ -240,6 +246,7 @@ describe(`${NodeManager.name} test`, () => { keyManager, nodeGraph, nodeConnectionManager, + setNodeQueue, logger, }); await nodeManager.start(); @@ -427,6 +434,7 @@ describe(`${NodeManager.name} test`, () => { keyManager, nodeGraph, nodeConnectionManager, + setNodeQueue, logger, }); await nodeManager.start(); @@ -443,15 +451,18 @@ describe(`${NodeManager.name} test`, () => { }); }); test('should add a node when bucket has room', async () => { + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, + setNodeQueue, logger, }); try { + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const localNodeId = keyManager.getNodeId(); @@ -467,18 +478,22 @@ describe(`${NodeManager.name} test`, () => { expect(bucket).toHaveLength(1); } finally { await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should update a node if node exists', async () => { + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, + setNodeQueue, logger, }); try { + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const localNodeId = keyManager.getNodeId(); @@ -506,18 +521,22 @@ describe(`${NodeManager.name} test`, () => { expect(newNodeData.lastUpdated).not.toEqual(nodeData.lastUpdated); } finally { await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should not add node if bucket is full and old node is alive', async () => { + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, + setNodeQueue, logger, }); try { + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const localNodeId = keyManager.getNodeId(); @@ -556,18 +575,22 @@ describe(`${NodeManager.name} test`, () => { nodeManagerPingMock.mockRestore(); } finally { await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should add node if bucket is full, old node is alive and force is set', async () => { + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, + setNodeQueue, logger, }); try { + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const localNodeId = keyManager.getNodeId(); @@ -608,18 +631,22 @@ describe(`${NodeManager.name} test`, () => { nodeManagerPingMock.mockRestore(); } finally { await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should add node if bucket is full and old node is dead', async () => { + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, + setNodeQueue, logger, }); try { + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const localNodeId = keyManager.getNodeId(); @@ -652,19 +679,23 @@ describe(`${NodeManager.name} test`, () => { nodeManagerPingMock.mockRestore(); } finally { await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should add node when an incoming connection is established', async () => { let server: PolykeyAgent | undefined; + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, + setNodeQueue, logger, }); try { + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); server = await PolykeyAgent.createPolykeyAgent({ @@ -704,19 +735,23 @@ describe(`${NodeManager.name} test`, () => { await server?.stop(); await server?.destroy(); await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should not add nodes to full bucket if pings succeeds', async () => { mockedPingNode.mockImplementation(async (_) => true); + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, + setNodeQueue, logger, }); try { + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const nodeId = keyManager.getNodeId(); @@ -742,18 +777,22 @@ describe(`${NodeManager.name} test`, () => { ); } finally { await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should add nodes to full bucket if pings fail', async () => { mockedPingNode.mockImplementation(async (_) => true); + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); try { await nodeConnectionManager.start({ nodeManager }); @@ -779,13 +818,14 @@ describe(`${NodeManager.name} test`, () => { await nodeManager.setNode(newNode1, address); await nodeManager.setNode(newNode2, address); await nodeManager.setNode(newNode3, address); - await nodeManager.queueDrained(); + await setNodeQueue.queueDrained(); const list = await listBucket(100); expect(list).toContain(nodesUtils.encodeNodeId(newNode1)); expect(list).toContain(nodesUtils.encodeNodeId(newNode2)); expect(list).toContain(nodesUtils.encodeNodeId(newNode3)); } finally { await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should not block when bucket is full', async () => { @@ -795,14 +835,17 @@ describe(`${NodeManager.name} test`, () => { logger, }); mockedPingNode.mockImplementation(async (_) => true); + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph: tempNodeGraph, nodeConnectionManager: dummyNodeConnectionManager, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); try { await nodeConnectionManager.start({ nodeManager }); @@ -821,27 +864,32 @@ describe(`${NodeManager.name} test`, () => { return true; }); const newNode4 = generateNodeIdForBucket(nodeId, 100, 25); + // Set manually to non-blocking await expect( - nodeManager.setNode(newNode4, address), + nodeManager.setNode(newNode4, address, false), ).resolves.toBeUndefined(); delayPing.resolveP(null); - await nodeManager.queueDrained(); + await setNodeQueue.queueDrained(); } finally { await nodeManager.stop(); + await setNodeQueue.stop(); await tempNodeGraph.stop(); await tempNodeGraph.destroy(); } }); test('should block when blocking is set to true', async () => { mockedPingNode.mockImplementation(async (_) => true); + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); try { await nodeConnectionManager.start({ nodeManager }); @@ -863,16 +911,19 @@ describe(`${NodeManager.name} test`, () => { expect(mockedPingNode).toBeCalled(); } finally { await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should update deadline when updating a bucket', async () => { const refreshBucketTimeout = 100000; + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, + setNodeQueue, refreshBucketTimerDefault: refreshBucketTimeout, logger, }); @@ -882,6 +933,7 @@ describe(`${NodeManager.name} test`, () => { ); try { mockRefreshBucket.mockImplementation(async () => {}); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); // @ts-ignore: kidnap map @@ -901,16 +953,19 @@ describe(`${NodeManager.name} test`, () => { } finally { mockRefreshBucket.mockRestore(); await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should add buckets to the queue when exceeding deadline', async () => { const refreshBucketTimeout = 100; + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, + setNodeQueue, refreshBucketTimerDefault: refreshBucketTimeout, logger, }); @@ -924,6 +979,7 @@ describe(`${NodeManager.name} test`, () => { ); try { mockRefreshBucket.mockImplementation(async () => {}); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); // Getting starting value @@ -934,16 +990,19 @@ describe(`${NodeManager.name} test`, () => { mockRefreshBucketQueueAdd.mockRestore(); mockRefreshBucket.mockRestore(); await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should digest queue to refresh buckets', async () => { const refreshBucketTimeout = 1000000; + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, + setNodeQueue, refreshBucketTimerDefault: refreshBucketTimeout, logger, }); @@ -952,6 +1011,7 @@ describe(`${NodeManager.name} test`, () => { 'refreshBucket', ); try { + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); mockRefreshBucket.mockImplementation(async () => {}); @@ -968,16 +1028,19 @@ describe(`${NodeManager.name} test`, () => { } finally { mockRefreshBucket.mockRestore(); await nodeManager.stop(); + await setNodeQueue.stop(); } }); test('should abort refreshBucket queue when stopping', async () => { const refreshBucketTimeout = 1000000; + const setNodeQueue = new SetNodeQueue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, + setNodeQueue, refreshBucketTimerDefault: refreshBucketTimeout, logger, }); @@ -986,6 +1049,7 @@ describe(`${NodeManager.name} test`, () => { 'refreshBucket', ); try { + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); mockRefreshBucket.mockImplementation( @@ -1007,6 +1071,7 @@ describe(`${NodeManager.name} test`, () => { } finally { mockRefreshBucket.mockRestore(); await nodeManager.stop(); + await setNodeQueue.stop(); } }); }); diff --git a/tests/notifications/NotificationsManager.test.ts b/tests/notifications/NotificationsManager.test.ts index b382ea49d..8a498fdb7 100644 --- a/tests/notifications/NotificationsManager.test.ts +++ b/tests/notifications/NotificationsManager.test.ts @@ -22,6 +22,7 @@ import * as notificationsErrors from '@/notifications/errors'; import * as vaultsUtils from '@/vaults/utils'; import * as nodesUtils from '@/nodes/utils'; import * as keysUtils from '@/keys/utils'; +import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../utils'; describe('NotificationsManager', () => { @@ -50,6 +51,7 @@ describe('NotificationsManager', () => { let acl: ACL; let db: DB; let nodeGraph: NodeGraph; + let setNodeQueue: SetNodeQueue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let keyManager: KeyManager; @@ -112,10 +114,12 @@ describe('NotificationsManager', () => { keyManager, logger, }); + setNodeQueue = new SetNodeQueue({ logger }); nodeConnectionManager = new NodeConnectionManager({ nodeGraph, keyManager, proxy, + setNodeQueue, logger, }); nodeManager = new NodeManager({ @@ -124,8 +128,10 @@ describe('NotificationsManager', () => { sigchain, nodeConnectionManager, nodeGraph, + setNodeQueue, logger, }); + await setNodeQueue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); // Set up node for receiving notifications @@ -147,6 +153,7 @@ describe('NotificationsManager', () => { }, global.defaultTimeout); afterAll(async () => { await receiver.stop(); + await setNodeQueue.stop(); await nodeConnectionManager.stop(); await nodeGraph.stop(); await proxy.stop(); diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index 5236215b0..46257fa33 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -8,6 +8,7 @@ import type { import type NotificationsManager from '@/notifications/NotificationsManager'; import type { Host, Port, TLSConfig } from '@/network/types'; import type NodeManager from '@/nodes/NodeManager'; +import type SetNodeQueue from '@/nodes/SetNodeQueue'; import fs from 'fs'; import os from 'os'; import path from 'path'; @@ -580,6 +581,7 @@ describe('VaultManager', () => { keyManager, nodeGraph, proxy, + setNodeQueue: {} as SetNodeQueue, logger, }); await nodeConnectionManager.start({ @@ -1497,6 +1499,7 @@ describe('VaultManager', () => { logger, nodeGraph, proxy, + setNodeQueue: {} as SetNodeQueue, connConnectTime: 1000, }); await nodeConnectionManager.start({ From 8deddc5d8eedaf168cf8c8a600edf97d4e2c86b7 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Thu, 21 Apr 2022 15:00:11 +1000 Subject: [PATCH 097/137] fix: `syncNodeGraph` during agent startup is now non-blocking #322 --- src/PolykeyAgent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index 2b8951d91..fd52b14b7 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -670,7 +670,7 @@ class PolykeyAgent { await this.nodeManager.start(); await this.nodeConnectionManager.start({ nodeManager: this.nodeManager }); await this.nodeGraph.start({ fresh }); - await this.nodeConnectionManager.syncNodeGraph(); + await this.nodeConnectionManager.syncNodeGraph(false); await this.discovery.start({ fresh }); await this.vaultManager.start({ fresh }); await this.notificationsManager.start({ fresh }); From 2782d8b9f657e01af0b1fb7f009606340df564b6 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Thu, 21 Apr 2022 16:35:32 +1000 Subject: [PATCH 098/137] refactor: renamed `SetNodeQueue` to `Queue` Renamed `queueStart` and `queuePush` since `Queue` is its own class now Simplified some logic using the `promise` utility --- package-lock.json | 5 + src/PolykeyAgent.ts | 32 ++--- src/bootstrap/utils.ts | 8 +- src/nodes/NodeConnectionManager.ts | 29 ++-- src/nodes/NodeManager.ts | 12 +- src/nodes/Queue.ts | 91 ++++++++++++ src/nodes/SetNodeQueue.ts | 107 -------------- src/nodes/errors.ts | 6 +- src/utils/utils.ts | 2 +- tests/agent/GRPCClientAgent.test.ts | 14 +- tests/agent/service/notificationsSend.test.ts | 14 +- .../gestaltsDiscoveryByIdentity.test.ts | 16 +-- .../service/gestaltsDiscoveryByNode.test.ts | 16 +-- .../gestaltsGestaltTrustByIdentity.test.ts | 16 +-- .../gestaltsGestaltTrustByNode.test.ts | 16 +-- tests/client/service/identitiesClaim.test.ts | 14 +- tests/client/service/nodesAdd.test.ts | 16 +-- tests/client/service/nodesClaim.test.ts | 16 +-- tests/client/service/nodesFind.test.ts | 14 +- tests/client/service/nodesPing.test.ts | 16 +-- .../client/service/notificationsClear.test.ts | 16 +-- .../client/service/notificationsRead.test.ts | 16 +-- .../client/service/notificationsSend.test.ts | 16 +-- tests/discovery/Discovery.test.ts | 16 +-- tests/nodes/NodeConnection.test.ts | 14 +- .../NodeConnectionManager.general.test.ts | 24 ++-- .../NodeConnectionManager.lifecycle.test.ts | 36 ++--- .../NodeConnectionManager.seednodes.test.ts | 46 +++--- .../NodeConnectionManager.termination.test.ts | 20 +-- .../NodeConnectionManager.timeout.test.ts | 8 +- tests/nodes/NodeManager.test.ts | 134 +++++++++--------- .../NotificationsManager.test.ts | 14 +- tests/vaults/VaultManager.test.ts | 6 +- 33 files changed, 405 insertions(+), 421 deletions(-) create mode 100644 src/nodes/Queue.ts delete mode 100644 src/nodes/SetNodeQueue.ts diff --git a/package-lock.json b/package-lock.json index 8674bf340..5658b4d4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15953,6 +15953,11 @@ } } }, + "node-abort-controller": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", + "integrity": "sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==" + }, "node-fetch": { "version": "2.6.7", "requires": { diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index fd52b14b7..d5817347b 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -8,6 +8,7 @@ import process from 'process'; import Logger from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { CreateDestroyStartStop } from '@matrixai/async-init/dist/CreateDestroyStartStop'; +import Queue from './nodes/Queue'; import * as networkUtils from './network/utils'; import KeyManager from './keys/KeyManager'; import Status from './status/Status'; @@ -34,7 +35,6 @@ import * as errors from './errors'; import * as utils from './utils'; import * as keysUtils from './keys/utils'; import * as nodesUtils from './nodes/utils'; -import SetNodeQueue from './nodes/SetNodeQueue'; type NetworkConfig = { forwardHost?: Host; @@ -88,7 +88,7 @@ class PolykeyAgent { gestaltGraph, proxy, nodeGraph, - setNodeQueue, + queue, nodeConnectionManager, nodeManager, discovery, @@ -134,7 +134,7 @@ class PolykeyAgent { gestaltGraph?: GestaltGraph; proxy?: Proxy; nodeGraph?: NodeGraph; - setNodeQueue?: SetNodeQueue; + queue?: Queue; nodeConnectionManager?: NodeConnectionManager; nodeManager?: NodeManager; discovery?: Discovery; @@ -284,10 +284,10 @@ class PolykeyAgent { keyManager, logger: logger.getChild(NodeGraph.name), })); - setNodeQueue = - setNodeQueue ?? - new SetNodeQueue({ - logger: logger.getChild(SetNodeQueue.name), + queue = + queue ?? + new Queue({ + logger: logger.getChild(Queue.name), }); nodeConnectionManager = nodeConnectionManager ?? @@ -295,7 +295,7 @@ class PolykeyAgent { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, seedNodes, ...nodeConnectionManagerConfig_, logger: logger.getChild(NodeConnectionManager.name), @@ -308,7 +308,7 @@ class PolykeyAgent { keyManager, nodeGraph, nodeConnectionManager, - setNodeQueue, + queue, logger: logger.getChild(NodeManager.name), }); await nodeManager.start(); @@ -395,7 +395,7 @@ class PolykeyAgent { gestaltGraph, proxy, nodeGraph, - setNodeQueue, + queue, nodeConnectionManager, nodeManager, discovery, @@ -428,7 +428,7 @@ class PolykeyAgent { public readonly gestaltGraph: GestaltGraph; public readonly proxy: Proxy; public readonly nodeGraph: NodeGraph; - public readonly setNodeQueue: SetNodeQueue; + public readonly queue: Queue; public readonly nodeConnectionManager: NodeConnectionManager; public readonly nodeManager: NodeManager; public readonly discovery: Discovery; @@ -453,7 +453,7 @@ class PolykeyAgent { gestaltGraph, proxy, nodeGraph, - setNodeQueue, + queue, nodeConnectionManager, nodeManager, discovery, @@ -477,7 +477,7 @@ class PolykeyAgent { gestaltGraph: GestaltGraph; proxy: Proxy; nodeGraph: NodeGraph; - setNodeQueue: SetNodeQueue; + queue: Queue; nodeConnectionManager: NodeConnectionManager; nodeManager: NodeManager; discovery: Discovery; @@ -503,7 +503,7 @@ class PolykeyAgent { this.proxy = proxy; this.discovery = discovery; this.nodeGraph = nodeGraph; - this.setNodeQueue = setNodeQueue; + this.queue = queue; this.nodeConnectionManager = nodeConnectionManager; this.nodeManager = nodeManager; this.vaultManager = vaultManager; @@ -666,7 +666,7 @@ class PolykeyAgent { proxyPort: networkConfig_.proxyPort, tlsConfig, }); - await this.setNodeQueue.start(); + await this.queue.start(); await this.nodeManager.start(); await this.nodeConnectionManager.start({ nodeManager: this.nodeManager }); await this.nodeGraph.start({ fresh }); @@ -724,7 +724,7 @@ class PolykeyAgent { await this.nodeConnectionManager.stop(); await this.nodeGraph.stop(); await this.nodeManager.stop(); - await this.setNodeQueue.stop(); + await this.queue.stop(); await this.proxy.stop(); await this.grpcServerAgent.stop(); await this.grpcServerClient.stop(); diff --git a/src/bootstrap/utils.ts b/src/bootstrap/utils.ts index 09aff4586..60844fc19 100644 --- a/src/bootstrap/utils.ts +++ b/src/bootstrap/utils.ts @@ -4,7 +4,7 @@ import path from 'path'; import Logger from '@matrixai/logger'; import { DB } from '@matrixai/db'; import * as bootstrapErrors from './errors'; -import SetNodeQueue from '../nodes/SetNodeQueue'; +import Queue from '../nodes/Queue'; import { IdentitiesManager } from '../identities'; import { SessionManager } from '../sessions'; import { Status } from '../status'; @@ -142,12 +142,12 @@ async function bootstrapState({ keyManager, logger: logger.getChild(NodeGraph.name), }); - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: logger.getChild(NodeConnectionManager.name), }); const nodeManager = new NodeManager({ @@ -156,7 +156,7 @@ async function bootstrapState({ nodeGraph, nodeConnectionManager, sigchain, - setNodeQueue, + queue, logger: logger.getChild(NodeManager.name), }); const notificationsManager = diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 7d6b5d694..e2c133a5f 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -4,7 +4,7 @@ import type Proxy from '../network/Proxy'; import type { Host, Hostname, Port } from '../network/types'; import type { Timer } from '../types'; import type NodeGraph from './NodeGraph'; -import type SetNodeQueue from './SetNodeQueue'; +import type Queue from './Queue'; import type { NodeAddress, NodeData, @@ -61,7 +61,7 @@ class NodeConnectionManager { protected nodeGraph: NodeGraph; protected keyManager: KeyManager; protected proxy: Proxy; - protected setNodeQueue: SetNodeQueue; + protected queue: Queue; // NodeManager has to be passed in during start to allow co-dependency protected nodeManager: NodeManager | undefined; protected seedNodes: SeedNodes; @@ -82,7 +82,7 @@ class NodeConnectionManager { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, seedNodes = {}, initialClosestNodes = 3, connConnectTime = 20000, @@ -92,7 +92,7 @@ class NodeConnectionManager { nodeGraph: NodeGraph; keyManager: KeyManager; proxy: Proxy; - setNodeQueue: SetNodeQueue; + queue: Queue; seedNodes?: SeedNodes; initialClosestNodes?: number; connConnectTime?: number; @@ -103,7 +103,7 @@ class NodeConnectionManager { this.keyManager = keyManager; this.nodeGraph = nodeGraph; this.proxy = proxy; - this.setNodeQueue = setNodeQueue; + this.queue = queue; this.seedNodes = seedNodes; this.initialClosestNodes = initialClosestNodes; this.connConnectTime = connConnectTime; @@ -600,7 +600,7 @@ class NodeConnectionManager { ); for (const [nodeId, nodeData] of nodes) { if (!block) { - this.setNodeQueue.queueSetNode(() => + this.queue.push(() => this.nodeManager!.setNode(nodeId, nodeData.address), ); } else { @@ -612,17 +612,7 @@ class NodeConnectionManager { } } // Refreshing every bucket above the closest node - if (!block) { - this.setNodeQueue.queueSetNode(async () => { - const [closestNode] = ( - await this.nodeGraph.getClosestNodes(this.keyManager.getNodeId(), 1) - ).pop()!; - const [bucketIndex] = this.nodeGraph.bucketIndex(closestNode); - for (let i = bucketIndex; i < this.nodeGraph.nodeIdBits; i++) { - this.nodeManager?.refreshBucketQueueAdd(i); - } - }); - } else { + const refreshBuckets = async () => { const [closestNode] = ( await this.nodeGraph.getClosestNodes(this.keyManager.getNodeId(), 1) ).pop()!; @@ -630,6 +620,11 @@ class NodeConnectionManager { for (let i = bucketIndex; i < this.nodeGraph.nodeIdBits; i++) { this.nodeManager?.refreshBucketQueueAdd(i); } + }; + if (!block) { + this.queue.push(refreshBuckets); + } else { + await refreshBuckets(); } } } diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 2bc76bccb..79f00637b 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -1,7 +1,7 @@ import type { DB, DBTransaction } from '@matrixai/db'; import type NodeConnectionManager from './NodeConnectionManager'; import type NodeGraph from './NodeGraph'; -import type SetNodeQueue from './SetNodeQueue'; +import type Queue from './Queue'; import type KeyManager from '../keys/KeyManager'; import type { PublicKeyPem } from '../keys/types'; import type Sigchain from '../sigchain/Sigchain'; @@ -38,7 +38,7 @@ class NodeManager { protected keyManager: KeyManager; protected nodeConnectionManager: NodeConnectionManager; protected nodeGraph: NodeGraph; - protected setNodeQueue: SetNodeQueue; + protected queue: Queue; // Refresh bucket timer protected refreshBucketDeadlineMap: Map = new Map(); protected refreshBucketTimer: NodeJS.Timer; @@ -57,7 +57,7 @@ class NodeManager { sigchain, nodeConnectionManager, nodeGraph, - setNodeQueue, + queue, refreshBucketTimerDefault = 3600000, // 1 hour in milliseconds logger, }: { @@ -66,7 +66,7 @@ class NodeManager { sigchain: Sigchain; nodeConnectionManager: NodeConnectionManager; nodeGraph: NodeGraph; - setNodeQueue: SetNodeQueue; + queue: Queue; refreshBucketTimerDefault?: number; logger?: Logger; }) { @@ -76,7 +76,7 @@ class NodeManager { this.sigchain = sigchain; this.nodeConnectionManager = nodeConnectionManager; this.nodeGraph = nodeGraph; - this.setNodeQueue = setNodeQueue; + this.queue = queue; this.refreshBucketTimerDefault = refreshBucketTimerDefault; } @@ -470,7 +470,7 @@ class NodeManager { )} to queue`, ); // Re-attempt this later asynchronously by adding the the queue - this.setNodeQueue.queueSetNode(() => + this.queue.push(() => this.setNode(nodeId, nodeAddress, true, false, timeout), ); } diff --git a/src/nodes/Queue.ts b/src/nodes/Queue.ts new file mode 100644 index 000000000..441165237 --- /dev/null +++ b/src/nodes/Queue.ts @@ -0,0 +1,91 @@ +import type { PromiseType } from '../utils'; +import Logger from '@matrixai/logger'; +import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; +import * as nodesErrors from './errors'; +import { promise } from '../utils'; + +interface Queue extends StartStop {} +@StartStop() +class Queue { + protected logger: Logger; + protected end: boolean = false; + protected queue: Array<() => Promise> = []; + protected runner: Promise; + protected plug_: PromiseType; + protected drained_: PromiseType; + + constructor({ logger }: { logger?: Logger }) { + this.logger = logger ?? new Logger(this.constructor.name); + } + + public async start() { + this.logger.info(`Starting ${this.constructor.name}`); + const start = async () => { + this.logger.debug('Starting queue'); + this.plug(); + const pace = async () => { + await this.plug_.p; + return !this.end; + }; + // While queue hasn't ended + while (await pace()) { + const job = this.queue.shift(); + if (job == null) { + // If the queue is empty then we pause the queue + this.plug(); + continue; + } + try { + await job(); + } catch (e) { + if (!(e instanceof nodesErrors.ErrorNodeGraphSameNodeId)) throw e; + } + } + this.logger.debug('queue has ended'); + }; + this.runner = start(); + this.logger.info(`Started ${this.constructor.name}`); + } + + public async stop() { + this.logger.info(`Stopping ${this.constructor.name}`); + this.logger.debug('Stopping queue'); + // Tell the queue runner to end + this.end = true; + this.unplug(); + // Wait for runner to finish it's current job + await this.runner; + this.logger.info(`Stopped ${this.constructor.name}`); + } + + /** + * This adds a setNode operation to the queue + */ + public push(f: () => Promise): void { + this.queue.push(f); + this.unplug(); + } + + @ready(new nodesErrors.ErrorQueueNotRunning()) + public async drained(): Promise { + await this.drained_.p; + } + + private plug(): void { + this.logger.debug('Plugging queue'); + // Pausing queue + this.plug_ = promise(); + // Signaling queue is empty + this.drained_.resolveP(); + } + + private unplug(): void { + this.logger.debug('Unplugging queue'); + // Starting queue + this.plug_.resolveP(); + // Signalling queue is running + this.drained_ = promise(); + } +} + +export default Queue; diff --git a/src/nodes/SetNodeQueue.ts b/src/nodes/SetNodeQueue.ts deleted file mode 100644 index a405c3418..000000000 --- a/src/nodes/SetNodeQueue.ts +++ /dev/null @@ -1,107 +0,0 @@ -import Logger from '@matrixai/logger'; -import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; -import * as nodesErrors from './errors'; - -interface SetNodeQueue extends StartStop {} -@StartStop() -class SetNodeQueue { - protected logger: Logger; - protected endQueue: boolean = false; - protected setNodeQueue: Array<() => Promise> = []; - protected setNodeQueuePlug: Promise; - protected setNodeQueueUnplug: (() => void) | undefined; - protected setNodeQueueRunner: Promise; - protected setNodeQueueEmpty: Promise; - protected setNodeQueueDrained: () => void; - - constructor({ logger }: { logger?: Logger }) { - this.logger = logger ?? new Logger(this.constructor.name); - } - - public async start() { - this.logger.info(`Starting ${this.constructor.name}`); - this.setNodeQueueRunner = this.startSetNodeQueue(); - this.logger.info(`Started ${this.constructor.name}`); - } - - public async stop() { - this.logger.info(`Stopping ${this.constructor.name}`); - await this.stopSetNodeQueue(); - this.logger.info(`Stopped ${this.constructor.name}`); - } - - /** - * This adds a setNode operation to the queue - */ - public queueSetNode(f: () => Promise): void { - this.setNodeQueue.push(f); - this.unplugQueue(); - } - - /** - * This starts the process of digesting the queue - */ - private async startSetNodeQueue(): Promise { - this.logger.debug('Starting setNodeQueue'); - this.plugQueue(); - // While queue hasn't ended - while (true) { - // Wait for queue to be unplugged - await this.setNodeQueuePlug; - if (this.endQueue) break; - const job = this.setNodeQueue.shift(); - if (job == null) { - // If the queue is empty then we pause the queue - this.plugQueue(); - continue; - } - try { - await job(); - } catch (e) { - if (!(e instanceof nodesErrors.ErrorNodeGraphSameNodeId)) throw e; - } - } - this.logger.debug('setNodeQueue has ended'); - } - - private async stopSetNodeQueue(): Promise { - this.logger.debug('Stopping setNodeQueue'); - // Tell the queue runner to end - this.endQueue = true; - this.unplugQueue(); - // Wait for runner to finish it's current job - await this.setNodeQueueRunner; - } - - private plugQueue(): void { - if (this.setNodeQueueUnplug == null) { - this.logger.debug('Plugging setNodeQueue'); - // Pausing queue - this.setNodeQueuePlug = new Promise((resolve) => { - this.setNodeQueueUnplug = resolve; - }); - // Signaling queue is empty - if (this.setNodeQueueDrained != null) this.setNodeQueueDrained(); - } - } - - private unplugQueue(): void { - if (this.setNodeQueueUnplug != null) { - this.logger.debug('Unplugging setNodeQueue'); - // Starting queue - this.setNodeQueueUnplug(); - this.setNodeQueueUnplug = undefined; - // Signalling queue is running - this.setNodeQueueEmpty = new Promise((resolve) => { - this.setNodeQueueDrained = resolve; - }); - } - } - - @ready(new nodesErrors.ErrorSetNodeQueueNotRunning()) - public async queueDrained(): Promise { - await this.setNodeQueueEmpty; - } -} - -export default SetNodeQueue; diff --git a/src/nodes/errors.ts b/src/nodes/errors.ts index 159021b9c..ad5b31c90 100644 --- a/src/nodes/errors.ts +++ b/src/nodes/errors.ts @@ -12,8 +12,8 @@ class ErrorNodeManagerNotRunning extends ErrorNodes { exitCode = sysexits.USAGE; } -class ErrorSetNodeQueueNotRunning extends ErrorNodes { - static description = 'SetNodeQueue is not running'; +class ErrorQueueNotRunning extends ErrorNodes { + static description = 'queue is not running'; exitCode = sysexits.USAGE; } @@ -91,7 +91,7 @@ export { ErrorNodes, ErrorNodeAborted, ErrorNodeManagerNotRunning, - ErrorSetNodeQueueNotRunning, + ErrorQueueNotRunning, ErrorNodeGraphRunning, ErrorNodeGraphNotRunning, ErrorNodeGraphDestroyed, diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 0b99a8a43..168825b32 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -179,7 +179,7 @@ export type PromiseType = { /** * Deconstructed promise */ -function promise(): PromiseType { +function promise(): PromiseType { let resolveP, rejectP; const p = new Promise((resolve, reject) => { resolveP = resolve; diff --git a/tests/agent/GRPCClientAgent.test.ts b/tests/agent/GRPCClientAgent.test.ts index 2a9644055..134273e30 100644 --- a/tests/agent/GRPCClientAgent.test.ts +++ b/tests/agent/GRPCClientAgent.test.ts @@ -6,6 +6,7 @@ import path from 'path'; import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; +import Queue from '@/nodes/Queue'; import GestaltGraph from '@/gestalts/GestaltGraph'; import ACL from '@/acl/ACL'; import KeyManager from '@/keys/KeyManager'; @@ -22,7 +23,6 @@ import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as agentErrors from '@/agent/errors'; import * as keysUtils from '@/keys/utils'; import { timerStart } from '@/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testAgentUtils from './utils'; describe(GRPCClientAgent.name, () => { @@ -50,7 +50,7 @@ describe(GRPCClientAgent.name, () => { let keyManager: KeyManager; let vaultManager: VaultManager; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let sigchain: Sigchain; @@ -112,12 +112,12 @@ describe(GRPCClientAgent.name, () => { keyManager, logger, }); - setNodeQueue = new SetNodeQueue({ logger }); + queue = new Queue({ logger }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger, }); nodeManager = new NodeManager({ @@ -126,10 +126,10 @@ describe(GRPCClientAgent.name, () => { keyManager: keyManager, nodeGraph: nodeGraph, nodeConnectionManager: nodeConnectionManager, - setNodeQueue, + queue, logger: logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = @@ -184,7 +184,7 @@ describe(GRPCClientAgent.name, () => { await sigchain.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await nodeGraph.stop(); await gestaltGraph.stop(); await acl.stop(); diff --git a/tests/agent/service/notificationsSend.test.ts b/tests/agent/service/notificationsSend.test.ts index 9425743b8..4e584f57c 100644 --- a/tests/agent/service/notificationsSend.test.ts +++ b/tests/agent/service/notificationsSend.test.ts @@ -8,6 +8,7 @@ import { createPrivateKey, createPublicKey } from 'crypto'; import { exportJWK, SignJWT } from 'jose'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; +import Queue from '@/nodes/Queue'; import KeyManager from '@/keys/KeyManager'; import GRPCServer from '@/grpc/GRPCServer'; import NodeConnectionManager from '@/nodes/NodeConnectionManager'; @@ -27,7 +28,6 @@ import * as notificationsPB from '@/proto/js/polykey/v1/notifications/notificati import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import * as notificationsUtils from '@/notifications/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import { expectRemoteError } from '../../utils'; @@ -41,7 +41,7 @@ describe('notificationsSend', () => { let senderKeyManager: KeyManager; let dataDir: string; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let notificationsManager: NotificationsManager; @@ -111,14 +111,14 @@ describe('notificationsSend', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -129,10 +129,10 @@ describe('notificationsSend', () => { nodeGraph, nodeConnectionManager, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = diff --git a/tests/client/service/gestaltsDiscoveryByIdentity.test.ts b/tests/client/service/gestaltsDiscoveryByIdentity.test.ts index 6fec772c1..f9789cb60 100644 --- a/tests/client/service/gestaltsDiscoveryByIdentity.test.ts +++ b/tests/client/service/gestaltsDiscoveryByIdentity.test.ts @@ -6,6 +6,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { Metadata } from '@grpc/grpc-js'; +import Queue from '@/nodes/Queue'; import GestaltGraph from '@/gestalts/GestaltGraph'; import ACL from '@/acl/ACL'; import KeyManager from '@/keys/KeyManager'; @@ -24,7 +25,6 @@ import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as identitiesPB from '@/proto/js/polykey/v1/identities/identities_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; describe('gestaltsDiscoveryByIdentity', () => { @@ -60,7 +60,7 @@ describe('gestaltsDiscoveryByIdentity', () => { let gestaltGraph: GestaltGraph; let identitiesManager: IdentitiesManager; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let sigchain: Sigchain; @@ -127,14 +127,14 @@ describe('gestaltsDiscoveryByIdentity', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -145,10 +145,10 @@ describe('gestaltsDiscoveryByIdentity', () => { nodeConnectionManager, nodeGraph, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); discovery = await Discovery.createDiscovery({ @@ -187,7 +187,7 @@ describe('gestaltsDiscoveryByIdentity', () => { await nodeGraph.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await sigchain.stop(); await proxy.stop(); await identitiesManager.stop(); diff --git a/tests/client/service/gestaltsDiscoveryByNode.test.ts b/tests/client/service/gestaltsDiscoveryByNode.test.ts index 1e97b6250..3c0f00b10 100644 --- a/tests/client/service/gestaltsDiscoveryByNode.test.ts +++ b/tests/client/service/gestaltsDiscoveryByNode.test.ts @@ -6,6 +6,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { Metadata } from '@grpc/grpc-js'; +import Queue from '@/nodes/Queue'; import GestaltGraph from '@/gestalts/GestaltGraph'; import ACL from '@/acl/ACL'; import KeyManager from '@/keys/KeyManager'; @@ -25,7 +26,6 @@ import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import * as testNodesUtils from '../../nodes/utils'; @@ -61,7 +61,7 @@ describe('gestaltsDiscoveryByNode', () => { let gestaltGraph: GestaltGraph; let identitiesManager: IdentitiesManager; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let sigchain: Sigchain; @@ -128,14 +128,14 @@ describe('gestaltsDiscoveryByNode', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -146,10 +146,10 @@ describe('gestaltsDiscoveryByNode', () => { nodeConnectionManager, nodeGraph, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); discovery = await Discovery.createDiscovery({ @@ -188,7 +188,7 @@ describe('gestaltsDiscoveryByNode', () => { await nodeGraph.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await sigchain.stop(); await proxy.stop(); await identitiesManager.stop(); diff --git a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts index 17de35e72..01a162e31 100644 --- a/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts +++ b/tests/client/service/gestaltsGestaltTrustByIdentity.test.ts @@ -9,6 +9,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { Metadata } from '@grpc/grpc-js'; +import Queue from '@/nodes/Queue'; import PolykeyAgent from '@/PolykeyAgent'; import KeyManager from '@/keys/KeyManager'; import Discovery from '@/discovery/Discovery'; @@ -31,7 +32,6 @@ import * as gestaltsErrors from '@/gestalts/errors'; import * as keysUtils from '@/keys/utils'; import * as clientUtils from '@/client/utils/utils'; import * as nodesUtils from '@/nodes/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import TestProvider from '../../identities/TestProvider'; import { expectRemoteError } from '../../utils'; @@ -116,7 +116,7 @@ describe('gestaltsGestaltTrustByIdentity', () => { let discovery: Discovery; let gestaltGraph: GestaltGraph; let identitiesManager: IdentitiesManager; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeManager: NodeManager; let nodeConnectionManager: NodeConnectionManager; let nodeGraph: NodeGraph; @@ -193,14 +193,14 @@ describe('gestaltsGestaltTrustByIdentity', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -211,10 +211,10 @@ describe('gestaltsGestaltTrustByIdentity', () => { nodeConnectionManager, nodeGraph, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); await nodeManager.setNode(nodesUtils.decodeNodeId(nodeId)!, { @@ -258,7 +258,7 @@ describe('gestaltsGestaltTrustByIdentity', () => { await discovery.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await nodeGraph.stop(); await proxy.stop(); await sigchain.stop(); diff --git a/tests/client/service/gestaltsGestaltTrustByNode.test.ts b/tests/client/service/gestaltsGestaltTrustByNode.test.ts index 5a409c120..df84503a7 100644 --- a/tests/client/service/gestaltsGestaltTrustByNode.test.ts +++ b/tests/client/service/gestaltsGestaltTrustByNode.test.ts @@ -10,6 +10,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { Metadata } from '@grpc/grpc-js'; +import Queue from '@/nodes/Queue'; import PolykeyAgent from '@/PolykeyAgent'; import KeyManager from '@/keys/KeyManager'; import Discovery from '@/discovery/Discovery'; @@ -33,7 +34,6 @@ import * as claimsUtils from '@/claims/utils'; import * as keysUtils from '@/keys/utils'; import * as clientUtils from '@/client/utils/utils'; import * as nodesUtils from '@/nodes/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import TestProvider from '../../identities/TestProvider'; @@ -115,7 +115,7 @@ describe('gestaltsGestaltTrustByNode', () => { let discovery: Discovery; let gestaltGraph: GestaltGraph; let identitiesManager: IdentitiesManager; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeManager: NodeManager; let nodeConnectionManager: NodeConnectionManager; let nodeGraph: NodeGraph; @@ -192,14 +192,14 @@ describe('gestaltsGestaltTrustByNode', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -210,10 +210,10 @@ describe('gestaltsGestaltTrustByNode', () => { nodeConnectionManager, nodeGraph, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); await nodeManager.setNode(nodesUtils.decodeNodeId(nodeId)!, { @@ -257,7 +257,7 @@ describe('gestaltsGestaltTrustByNode', () => { await discovery.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await nodeGraph.stop(); await proxy.stop(); await sigchain.stop(); diff --git a/tests/client/service/identitiesClaim.test.ts b/tests/client/service/identitiesClaim.test.ts index 5038821e9..3a17b79a8 100644 --- a/tests/client/service/identitiesClaim.test.ts +++ b/tests/client/service/identitiesClaim.test.ts @@ -9,6 +9,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { Metadata } from '@grpc/grpc-js'; +import Queue from '@/nodes/Queue'; import KeyManager from '@/keys/KeyManager'; import IdentitiesManager from '@/identities/IdentitiesManager'; import NodeConnectionManager from '@/nodes/NodeConnectionManager'; @@ -26,7 +27,6 @@ import * as keysUtils from '@/keys/utils'; import * as claimsUtils from '@/claims/utils'; import * as nodesUtils from '@/nodes/utils'; import * as validationErrors from '@/validation/errors'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import TestProvider from '../../identities/TestProvider'; import { expectRemoteError } from '../../utils'; @@ -87,7 +87,7 @@ describe('identitiesClaim', () => { let testProvider: TestProvider; let identitiesManager: IdentitiesManager; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let sigchain: Sigchain; let proxy: Proxy; @@ -139,18 +139,18 @@ describe('identitiesClaim', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ connConnectTime: 2000, proxy, keyManager, nodeGraph, - setNodeQueue, + queue, logger: logger.getChild('NodeConnectionManager'), }); - await setNodeQueue.start(); + await queue.start(); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); const clientService = { identitiesClaim: identitiesClaim({ @@ -179,7 +179,7 @@ describe('identitiesClaim', () => { await grpcClient.destroy(); await grpcServer.stop(); await nodeConnectionManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await nodeGraph.stop(); await sigchain.stop(); await proxy.stop(); diff --git a/tests/client/service/nodesAdd.test.ts b/tests/client/service/nodesAdd.test.ts index e6d037034..d912fb83a 100644 --- a/tests/client/service/nodesAdd.test.ts +++ b/tests/client/service/nodesAdd.test.ts @@ -5,6 +5,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { Metadata } from '@grpc/grpc-js'; +import Queue from '@/nodes/Queue'; import KeyManager from '@/keys/KeyManager'; import NodeConnectionManager from '@/nodes/NodeConnectionManager'; import NodeGraph from '@/nodes/NodeGraph'; @@ -22,7 +23,6 @@ import * as nodesUtils from '@/nodes/utils'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import { expectRemoteError } from '../../utils'; @@ -51,7 +51,7 @@ describe('nodesAdd', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let sigchain: Sigchain; @@ -98,14 +98,14 @@ describe('nodesAdd', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -116,10 +116,10 @@ describe('nodesAdd', () => { nodeConnectionManager, nodeGraph, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const clientService = { @@ -148,7 +148,7 @@ describe('nodesAdd', () => { await grpcServer.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await sigchain.stop(); await proxy.stop(); await db.stop(); diff --git a/tests/client/service/nodesClaim.test.ts b/tests/client/service/nodesClaim.test.ts index 21b6a4a5a..5e7dedc8d 100644 --- a/tests/client/service/nodesClaim.test.ts +++ b/tests/client/service/nodesClaim.test.ts @@ -7,6 +7,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { Metadata } from '@grpc/grpc-js'; +import Queue from '@/nodes/Queue'; import KeyManager from '@/keys/KeyManager'; import NotificationsManager from '@/notifications/NotificationsManager'; import ACL from '@/acl/ACL'; @@ -24,7 +25,6 @@ import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; describe('nodesClaim', () => { @@ -76,7 +76,7 @@ describe('nodesClaim', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let notificationsManager: NotificationsManager; @@ -128,14 +128,14 @@ describe('nodesClaim', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -146,10 +146,10 @@ describe('nodesClaim', () => { nodeConnectionManager, nodeGraph, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = @@ -187,7 +187,7 @@ describe('nodesClaim', () => { await grpcClient.destroy(); await grpcServer.stop(); await nodeConnectionManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await nodeGraph.stop(); await notificationsManager.stop(); await sigchain.stop(); diff --git a/tests/client/service/nodesFind.test.ts b/tests/client/service/nodesFind.test.ts index 095139160..4ff59d9f1 100644 --- a/tests/client/service/nodesFind.test.ts +++ b/tests/client/service/nodesFind.test.ts @@ -6,6 +6,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { Metadata } from '@grpc/grpc-js'; +import Queue from '@/nodes/Queue'; import KeyManager from '@/keys/KeyManager'; import NodeConnectionManager from '@/nodes/NodeConnectionManager'; import NodeGraph from '@/nodes/NodeGraph'; @@ -20,7 +21,6 @@ import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import { expectRemoteError } from '../../utils'; @@ -57,7 +57,7 @@ describe('nodesFind', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let sigchain: Sigchain; let proxy: Proxy; @@ -103,19 +103,19 @@ describe('nodesFind', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), }); - await setNodeQueue.start(); + await queue.start(); await nodeConnectionManager.start({ nodeManager: {} as NodeManager }); const clientService = { nodesFind: nodesFind({ @@ -143,7 +143,7 @@ describe('nodesFind', () => { await sigchain.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await proxy.stop(); await db.stop(); await keyManager.stop(); diff --git a/tests/client/service/nodesPing.test.ts b/tests/client/service/nodesPing.test.ts index bd1409b30..14f9cbcee 100644 --- a/tests/client/service/nodesPing.test.ts +++ b/tests/client/service/nodesPing.test.ts @@ -5,6 +5,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { Metadata } from '@grpc/grpc-js'; +import Queue from '@/nodes/Queue'; import KeyManager from '@/keys/KeyManager'; import NodeConnectionManager from '@/nodes/NodeConnectionManager'; import NodeGraph from '@/nodes/NodeGraph'; @@ -21,7 +22,6 @@ import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; import * as clientUtils from '@/client/utils/utils'; import * as keysUtils from '@/keys/utils'; import * as validationErrors from '@/validation/errors'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import { expectRemoteError } from '../../utils'; @@ -56,7 +56,7 @@ describe('nodesPing', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let sigchain: Sigchain; @@ -103,14 +103,14 @@ describe('nodesPing', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -121,10 +121,10 @@ describe('nodesPing', () => { nodeConnectionManager, nodeGraph, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeConnectionManager.start({ nodeManager }); const clientService = { nodesPing: nodesPing({ @@ -152,7 +152,7 @@ describe('nodesPing', () => { await sigchain.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await proxy.stop(); await db.stop(); await keyManager.stop(); diff --git a/tests/client/service/notificationsClear.test.ts b/tests/client/service/notificationsClear.test.ts index 7020f7d84..73a5e3597 100644 --- a/tests/client/service/notificationsClear.test.ts +++ b/tests/client/service/notificationsClear.test.ts @@ -5,6 +5,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { Metadata } from '@grpc/grpc-js'; import { DB } from '@matrixai/db'; +import Queue from '@/nodes/Queue'; import KeyManager from '@/keys/KeyManager'; import GRPCServer from '@/grpc/GRPCServer'; import NodeConnectionManager from '@/nodes/NodeConnectionManager'; @@ -21,7 +22,6 @@ import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_ import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as keysUtils from '@/keys/utils'; import * as clientUtils from '@/client/utils/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; describe('notificationsClear', () => { @@ -54,7 +54,7 @@ describe('notificationsClear', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let notificationsManager: NotificationsManager; @@ -107,14 +107,14 @@ describe('notificationsClear', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -125,10 +125,10 @@ describe('notificationsClear', () => { nodeConnectionManager, nodeGraph, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = @@ -167,7 +167,7 @@ describe('notificationsClear', () => { await notificationsManager.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await sigchain.stop(); await proxy.stop(); await acl.stop(); diff --git a/tests/client/service/notificationsRead.test.ts b/tests/client/service/notificationsRead.test.ts index 0f5b80610..d5688e6c5 100644 --- a/tests/client/service/notificationsRead.test.ts +++ b/tests/client/service/notificationsRead.test.ts @@ -6,6 +6,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { Metadata } from '@grpc/grpc-js'; import { DB } from '@matrixai/db'; +import Queue from '@/nodes/Queue'; import KeyManager from '@/keys/KeyManager'; import GRPCServer from '@/grpc/GRPCServer'; import NodeConnectionManager from '@/nodes/NodeConnectionManager'; @@ -23,7 +24,6 @@ import * as notificationsPB from '@/proto/js/polykey/v1/notifications/notificati import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import * as clientUtils from '@/client/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; import * as testNodesUtils from '../../nodes/utils'; @@ -129,7 +129,7 @@ describe('notificationsRead', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let notificationsManager: NotificationsManager; @@ -182,14 +182,14 @@ describe('notificationsRead', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -200,10 +200,10 @@ describe('notificationsRead', () => { nodeConnectionManager, nodeGraph, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = @@ -243,7 +243,7 @@ describe('notificationsRead', () => { await sigchain.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await proxy.stop(); await acl.stop(); await db.stop(); diff --git a/tests/client/service/notificationsSend.test.ts b/tests/client/service/notificationsSend.test.ts index a0f471b58..6a2489bdf 100644 --- a/tests/client/service/notificationsSend.test.ts +++ b/tests/client/service/notificationsSend.test.ts @@ -6,6 +6,7 @@ import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { Metadata } from '@grpc/grpc-js'; import { DB } from '@matrixai/db'; +import Queue from '@/nodes/Queue'; import KeyManager from '@/keys/KeyManager'; import GRPCServer from '@/grpc/GRPCServer'; import NodeConnectionManager from '@/nodes/NodeConnectionManager'; @@ -24,7 +25,6 @@ import * as keysUtils from '@/keys/utils'; import * as nodesUtils from '@/nodes/utils'; import * as notificationsUtils from '@/notifications/utils'; import * as clientUtils from '@/client/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../../utils'; describe('notificationsSend', () => { @@ -64,7 +64,7 @@ describe('notificationsSend', () => { const authToken = 'abc123'; let dataDir: string; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let notificationsManager: NotificationsManager; @@ -116,14 +116,14 @@ describe('notificationsSend', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -134,10 +134,10 @@ describe('notificationsSend', () => { nodeConnectionManager, nodeGraph, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); notificationsManager = @@ -175,7 +175,7 @@ describe('notificationsSend', () => { await notificationsManager.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await sigchain.stop(); await proxy.stop(); await acl.stop(); diff --git a/tests/discovery/Discovery.test.ts b/tests/discovery/Discovery.test.ts index 04f5b8236..a267cc7d8 100644 --- a/tests/discovery/Discovery.test.ts +++ b/tests/discovery/Discovery.test.ts @@ -6,6 +6,7 @@ import path from 'path'; import os from 'os'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; +import Queue from '@/nodes/Queue'; import PolykeyAgent from '@/PolykeyAgent'; import Discovery from '@/discovery/Discovery'; import GestaltGraph from '@/gestalts/GestaltGraph'; @@ -21,7 +22,6 @@ import * as nodesUtils from '@/nodes/utils'; import * as claimsUtils from '@/claims/utils'; import * as discoveryErrors from '@/discovery/errors'; import * as keysUtils from '@/keys/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testNodesUtils from '../nodes/utils'; import * as testUtils from '../utils'; import TestProvider from '../identities/TestProvider'; @@ -48,7 +48,7 @@ describe('Discovery', () => { let gestaltGraph: GestaltGraph; let identitiesManager: IdentitiesManager; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let db: DB; @@ -132,14 +132,14 @@ describe('Discovery', () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 2000, connTimeoutTime: 2000, logger: logger.getChild('NodeConnectionManager'), @@ -150,10 +150,10 @@ describe('Discovery', () => { nodeConnectionManager, nodeGraph, sigchain, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); // Set up other gestalt @@ -212,7 +212,7 @@ describe('Discovery', () => { await nodeB.stop(); await nodeConnectionManager.stop(); await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await nodeGraph.stop(); await proxy.stop(); await sigchain.stop(); diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index 99de0bbe8..725e6a684 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -34,7 +34,7 @@ import * as nodesUtils from '@/nodes/utils'; import * as agentErrors from '@/agent/errors'; import * as grpcUtils from '@/grpc/utils'; import { timerStart } from '@/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; +import Queue from '@/nodes/Queue'; import * as testNodesUtils from './utils'; import * as testUtils from '../utils'; import * as grpcTestUtils from '../grpc/utils'; @@ -85,7 +85,7 @@ describe('${NodeConnection.name} test', () => { let serverKeyManager: KeyManager; let serverVaultManager: VaultManager; let serverNodeGraph: NodeGraph; - let serverSetNodeQueue: SetNodeQueue; + let serverQueue: Queue; let serverNodeConnectionManager: NodeConnectionManager; let serverNodeManager: NodeManager; let serverSigchain: Sigchain; @@ -233,12 +233,12 @@ describe('${NodeConnection.name} test', () => { logger, }); - serverSetNodeQueue = new SetNodeQueue({ logger }); + serverQueue = new Queue({ logger }); serverNodeConnectionManager = new NodeConnectionManager({ keyManager: serverKeyManager, nodeGraph: serverNodeGraph, proxy: serverProxy, - setNodeQueue: serverSetNodeQueue, + queue: serverQueue, logger, }); serverNodeManager = new NodeManager({ @@ -247,10 +247,10 @@ describe('${NodeConnection.name} test', () => { keyManager: serverKeyManager, nodeGraph: serverNodeGraph, nodeConnectionManager: serverNodeConnectionManager, - setNodeQueue: serverSetNodeQueue, + queue: serverQueue, logger: logger, }); - await serverSetNodeQueue.start(); + await serverQueue.start(); await serverNodeManager.start(); await serverNodeConnectionManager.start({ nodeManager: serverNodeManager }); serverVaultManager = await VaultManager.createVaultManager({ @@ -362,7 +362,7 @@ describe('${NodeConnection.name} test', () => { await serverNodeGraph.destroy(); await serverNodeConnectionManager.stop(); await serverNodeManager.stop(); - await serverSetNodeQueue.stop(); + await serverQueue.stop(); await serverNotificationsManager.stop(); await serverNotificationsManager.destroy(); await agentTestUtils.closeTestAgentServer(agentServer); diff --git a/tests/nodes/NodeConnectionManager.general.test.ts b/tests/nodes/NodeConnectionManager.general.test.ts index dd30f9049..8905f8718 100644 --- a/tests/nodes/NodeConnectionManager.general.test.ts +++ b/tests/nodes/NodeConnectionManager.general.test.ts @@ -7,6 +7,7 @@ import os from 'os'; import { DB } from '@matrixai/db'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; +import Queue from '@/nodes/Queue'; import PolykeyAgent from '@/PolykeyAgent'; import KeyManager from '@/keys/KeyManager'; import NodeGraph from '@/nodes/NodeGraph'; @@ -20,7 +21,6 @@ import * as keysUtils from '@/keys/utils'; import * as grpcUtils from '@/grpc/utils'; import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testNodesUtils from './utils'; describe(`${NodeConnectionManager.name} general test`, () => { @@ -77,7 +77,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { let db: DB; let proxy: Proxy; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let remoteNode1: PolykeyAgent; let remoteNode2: PolykeyAgent; @@ -193,10 +193,10 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); - await setNodeQueue.start(); + await queue.start(); const tlsConfig = { keyPrivatePem: keyManager.getRootKeyPairPem().privateKey, certChainPem: keysUtils.certToPem(keyManager.getRootCert()), @@ -222,7 +222,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { }); afterEach(async () => { - await setNodeQueue.stop(); + await queue.stop(); await nodeGraph.stop(); await nodeGraph.destroy(); await db.stop(); @@ -239,7 +239,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -267,7 +267,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -309,7 +309,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -363,7 +363,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: logger.getChild('NodeConnectionManager'), }); @@ -435,7 +435,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -473,7 +473,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); diff --git a/tests/nodes/NodeConnectionManager.lifecycle.test.ts b/tests/nodes/NodeConnectionManager.lifecycle.test.ts index bf719789a..69b21c099 100644 --- a/tests/nodes/NodeConnectionManager.lifecycle.test.ts +++ b/tests/nodes/NodeConnectionManager.lifecycle.test.ts @@ -8,6 +8,7 @@ import { DB } from '@matrixai/db'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { withF } from '@matrixai/resources'; import { IdInternal } from '@matrixai/id'; +import Queue from '@/nodes/Queue'; import PolykeyAgent from '@/PolykeyAgent'; import KeyManager from '@/keys/KeyManager'; import NodeGraph from '@/nodes/NodeGraph'; @@ -19,7 +20,6 @@ import * as nodesErrors from '@/nodes/errors'; import * as keysUtils from '@/keys/utils'; import * as grpcUtils from '@/grpc/utils'; import { timerStart } from '@/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; describe(`${NodeConnectionManager.name} lifecycle test`, () => { const logger = new Logger( @@ -77,7 +77,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { let proxy: Proxy; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let remoteNode1: PolykeyAgent; let remoteNode2: PolykeyAgent; @@ -156,10 +156,10 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, logger: logger.getChild('NodeGraph'), }); - setNodeQueue = new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue = new Queue({ + logger: logger.getChild('queue'), }); - await setNodeQueue.start(); + await queue.start(); const tlsConfig = { keyPrivatePem: keyManager.getRootKeyPairPem().privateKey, certChainPem: keysUtils.certToPem(keyManager.getRootCert()), @@ -185,7 +185,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { }); afterEach(async () => { - await setNodeQueue.stop(); + await queue.stop(); await nodeGraph.stop(); await nodeGraph.destroy(); await db.stop(); @@ -204,7 +204,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -230,7 +230,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -265,7 +265,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -294,7 +294,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -347,7 +347,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, connConnectTime: 500, logger: nodeConnectionManagerLogger, }); @@ -389,7 +389,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -416,7 +416,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -450,7 +450,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -484,7 +484,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -527,7 +527,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -548,7 +548,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); @@ -574,7 +574,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue, + queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); diff --git a/tests/nodes/NodeConnectionManager.seednodes.test.ts b/tests/nodes/NodeConnectionManager.seednodes.test.ts index ae186f451..d433dcbd1 100644 --- a/tests/nodes/NodeConnectionManager.seednodes.test.ts +++ b/tests/nodes/NodeConnectionManager.seednodes.test.ts @@ -17,7 +17,7 @@ import Proxy from '@/network/Proxy'; import * as nodesUtils from '@/nodes/utils'; import * as keysUtils from '@/keys/utils'; import * as grpcUtils from '@/grpc/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; +import Queue from '@/nodes/Queue'; describe(`${NodeConnectionManager.name} seed nodes test`, () => { const logger = new Logger( @@ -191,8 +191,8 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue: new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue: new Queue({ + logger: logger.getChild('queue'), }), seedNodes: dummySeedNodes, logger: logger, @@ -217,8 +217,8 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue: new SetNodeQueue({ - logger: logger.getChild('SetNodeQueue'), + queue: new Queue({ + logger: logger.getChild('queue'), }), seedNodes: dummySeedNodes, logger: logger, @@ -237,7 +237,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { test('should synchronise nodeGraph', async () => { let nodeConnectionManager: NodeConnectionManager | undefined; let nodeManager: NodeManager | undefined; - let setNodeQueue: SetNodeQueue | undefined; + let queue: Queue | undefined; const mockedRefreshBucket = jest.spyOn( NodeManager.prototype, 'refreshBucket', @@ -253,12 +253,12 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { host: remoteNode2.proxy.getProxyHost(), port: remoteNode2.proxy.getProxyPort(), }; - setNodeQueue = new SetNodeQueue({ logger }); + queue = new Queue({ logger }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, seedNodes, logger: logger, }); @@ -268,10 +268,10 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { logger, nodeConnectionManager, nodeGraph, - setNodeQueue, + queue, sigchain: {} as Sigchain, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await remoteNode1.nodeGraph.setNode(nodeId1, { host: serverHost, @@ -290,13 +290,13 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { mockedRefreshBucket.mockRestore(); await nodeManager?.stop(); await nodeConnectionManager?.stop(); - await setNodeQueue?.stop(); + await queue?.stop(); } }); test('should call refreshBucket when syncing nodeGraph', async () => { let nodeConnectionManager: NodeConnectionManager | undefined; let nodeManager: NodeManager | undefined; - let setNodeQueue: SetNodeQueue | undefined; + let queue: Queue | undefined; const mockedRefreshBucket = jest.spyOn( NodeManager.prototype, 'refreshBucket', @@ -312,12 +312,12 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { host: remoteNode2.proxy.getProxyHost(), port: remoteNode2.proxy.getProxyPort(), }; - setNodeQueue = new SetNodeQueue({ logger }); + queue = new Queue({ logger }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, seedNodes, logger: logger, }); @@ -328,9 +328,9 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { nodeConnectionManager, nodeGraph, sigchain: {} as Sigchain, - setNodeQueue, + queue, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await remoteNode1.nodeGraph.setNode(nodeId1, { host: serverHost, @@ -348,13 +348,13 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { mockedRefreshBucket.mockRestore(); await nodeManager?.stop(); await nodeConnectionManager?.stop(); - await setNodeQueue?.stop(); + await queue?.stop(); } }); test('should handle an offline seed node when synchronising nodeGraph', async () => { let nodeConnectionManager: NodeConnectionManager | undefined; let nodeManager: NodeManager | undefined; - let setNodeQueue: SetNodeQueue | undefined; + let queue: Queue | undefined; const mockedRefreshBucket = jest.spyOn( NodeManager.prototype, 'refreshBucket', @@ -383,12 +383,12 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { host: serverHost, port: serverPort, }); - setNodeQueue = new SetNodeQueue({ logger }); + queue = new Queue({ logger }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, proxy, - setNodeQueue, + queue, seedNodes, connConnectTime: 500, logger: logger, @@ -400,9 +400,9 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { nodeConnectionManager, nodeGraph, sigchain: {} as Sigchain, - setNodeQueue, + queue, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); // This should complete without error @@ -414,7 +414,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { mockedRefreshBucket.mockRestore(); await nodeConnectionManager?.stop(); await nodeManager?.stop(); - await setNodeQueue?.stop(); + await queue?.stop(); } }); }); diff --git a/tests/nodes/NodeConnectionManager.termination.test.ts b/tests/nodes/NodeConnectionManager.termination.test.ts index 89358557b..c26a93c03 100644 --- a/tests/nodes/NodeConnectionManager.termination.test.ts +++ b/tests/nodes/NodeConnectionManager.termination.test.ts @@ -2,7 +2,7 @@ import type { AddressInfo } from 'net'; import type { NodeId, NodeIdString, SeedNodes } from '@/nodes/types'; import type { Host, Port, TLSConfig } from '@/network/types'; import type NodeManager from '@/nodes/NodeManager'; -import type SetNodeQueue from '@/nodes/SetNodeQueue'; +import type Queue from '@/nodes/Queue'; import net from 'net'; import fs from 'fs'; import path from 'path'; @@ -247,7 +247,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, logger: logger, connConnectTime: 2000, }); @@ -288,7 +288,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, logger: logger, connConnectTime: 2000, }); @@ -332,7 +332,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, logger: logger, connConnectTime: 2000, }); @@ -376,7 +376,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, logger: logger, connConnectTime: 2000, }); @@ -434,7 +434,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, logger: logger, connConnectTime: 2000, }); @@ -514,7 +514,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, logger: logger, connConnectTime: 2000, }); @@ -587,7 +587,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, logger: logger, connConnectTime: 2000, }); @@ -665,7 +665,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, logger: logger, connConnectTime: 2000, }); @@ -743,7 +743,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { keyManager, nodeGraph, proxy: defaultProxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, logger: logger, connConnectTime: 2000, }); diff --git a/tests/nodes/NodeConnectionManager.timeout.test.ts b/tests/nodes/NodeConnectionManager.timeout.test.ts index e07958140..3f73a1a39 100644 --- a/tests/nodes/NodeConnectionManager.timeout.test.ts +++ b/tests/nodes/NodeConnectionManager.timeout.test.ts @@ -1,7 +1,7 @@ import type { NodeId, NodeIdString, SeedNodes } from '@/nodes/types'; import type { Host, Port } from '@/network/types'; import type NodeManager from 'nodes/NodeManager'; -import type SetNodeQueue from '@/nodes/SetNodeQueue'; +import type Queue from '@/nodes/Queue'; import fs from 'fs'; import path from 'path'; import os from 'os'; @@ -189,7 +189,7 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, connTimeoutTime: 500, logger: nodeConnectionManagerLogger, }); @@ -227,7 +227,7 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, connTimeoutTime: 1000, logger: nodeConnectionManagerLogger, }); @@ -281,7 +281,7 @@ describe(`${NodeConnectionManager.name} timeout test`, () => { keyManager, nodeGraph, proxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, logger: nodeConnectionManagerLogger, }); await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index 7815c34e0..f40ce814e 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -7,6 +7,7 @@ import fs from 'fs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import UTP from 'utp-native'; +import Queue from '@/nodes/Queue'; import PolykeyAgent from '@/PolykeyAgent'; import KeyManager from '@/keys/KeyManager'; import * as keysUtils from '@/keys/utils'; @@ -20,7 +21,6 @@ import { promise, promisify, sleep } from '@/utils'; import * as nodesUtils from '@/nodes/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as nodesErrors from '@/nodes/errors'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as nodesTestUtils from './utils'; import { generateNodeIdForBucket } from './utils'; @@ -31,7 +31,7 @@ describe(`${NodeManager.name} test`, () => { ]); let dataDir: string; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let proxy: Proxy; let keyManager: KeyManager; @@ -113,11 +113,11 @@ describe(`${NodeManager.name} test`, () => { keyManager, logger, }); - setNodeQueue = new SetNodeQueue({ logger }); + queue = new Queue({ logger }); nodeConnectionManager = new NodeConnectionManager({ keyManager, nodeGraph, - setNodeQueue, + queue, proxy, logger, }); @@ -126,7 +126,7 @@ describe(`${NodeManager.name} test`, () => { mockedPingNode.mockClear(); mockedPingNode.mockImplementation(async (_) => true); await nodeConnectionManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await nodeGraph.stop(); await nodeGraph.destroy(); await sigchain.stop(); @@ -172,7 +172,7 @@ describe(`${NodeManager.name} test`, () => { keyManager, nodeGraph, nodeConnectionManager, - setNodeQueue, + queue, logger, }); await nodeManager.start(); @@ -246,7 +246,7 @@ describe(`${NodeManager.name} test`, () => { keyManager, nodeGraph, nodeConnectionManager, - setNodeQueue, + queue, logger, }); await nodeManager.start(); @@ -434,7 +434,7 @@ describe(`${NodeManager.name} test`, () => { keyManager, nodeGraph, nodeConnectionManager, - setNodeQueue, + queue, logger, }); await nodeManager.start(); @@ -451,18 +451,18 @@ describe(`${NodeManager.name} test`, () => { }); }); test('should add a node when bucket has room', async () => { - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, - setNodeQueue, + queue, logger, }); try { - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const localNodeId = keyManager.getNodeId(); @@ -478,22 +478,22 @@ describe(`${NodeManager.name} test`, () => { expect(bucket).toHaveLength(1); } finally { await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should update a node if node exists', async () => { - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, - setNodeQueue, + queue, logger, }); try { - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const localNodeId = keyManager.getNodeId(); @@ -521,22 +521,22 @@ describe(`${NodeManager.name} test`, () => { expect(newNodeData.lastUpdated).not.toEqual(nodeData.lastUpdated); } finally { await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should not add node if bucket is full and old node is alive', async () => { - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, - setNodeQueue, + queue, logger, }); try { - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const localNodeId = keyManager.getNodeId(); @@ -575,22 +575,22 @@ describe(`${NodeManager.name} test`, () => { nodeManagerPingMock.mockRestore(); } finally { await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should add node if bucket is full, old node is alive and force is set', async () => { - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, - setNodeQueue, + queue, logger, }); try { - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const localNodeId = keyManager.getNodeId(); @@ -631,22 +631,22 @@ describe(`${NodeManager.name} test`, () => { nodeManagerPingMock.mockRestore(); } finally { await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should add node if bucket is full and old node is dead', async () => { - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, - setNodeQueue, + queue, logger, }); try { - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const localNodeId = keyManager.getNodeId(); @@ -679,23 +679,23 @@ describe(`${NodeManager.name} test`, () => { nodeManagerPingMock.mockRestore(); } finally { await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should add node when an incoming connection is established', async () => { let server: PolykeyAgent | undefined; - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: {} as NodeConnectionManager, - setNodeQueue, + queue, logger, }); try { - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); server = await PolykeyAgent.createPolykeyAgent({ @@ -735,23 +735,23 @@ describe(`${NodeManager.name} test`, () => { await server?.stop(); await server?.destroy(); await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should not add nodes to full bucket if pings succeeds', async () => { mockedPingNode.mockImplementation(async (_) => true); - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, - setNodeQueue, + queue, logger, }); try { - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); const nodeId = keyManager.getNodeId(); @@ -777,22 +777,22 @@ describe(`${NodeManager.name} test`, () => { ); } finally { await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should add nodes to full bucket if pings fail', async () => { mockedPingNode.mockImplementation(async (_) => true); - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); try { await nodeConnectionManager.start({ nodeManager }); @@ -818,14 +818,14 @@ describe(`${NodeManager.name} test`, () => { await nodeManager.setNode(newNode1, address); await nodeManager.setNode(newNode2, address); await nodeManager.setNode(newNode3, address); - await setNodeQueue.queueDrained(); + await queue.drained(); const list = await listBucket(100); expect(list).toContain(nodesUtils.encodeNodeId(newNode1)); expect(list).toContain(nodesUtils.encodeNodeId(newNode2)); expect(list).toContain(nodesUtils.encodeNodeId(newNode3)); } finally { await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should not block when bucket is full', async () => { @@ -835,17 +835,17 @@ describe(`${NodeManager.name} test`, () => { logger, }); mockedPingNode.mockImplementation(async (_) => true); - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph: tempNodeGraph, nodeConnectionManager: dummyNodeConnectionManager, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); try { await nodeConnectionManager.start({ nodeManager }); @@ -868,28 +868,28 @@ describe(`${NodeManager.name} test`, () => { await expect( nodeManager.setNode(newNode4, address, false), ).resolves.toBeUndefined(); - delayPing.resolveP(null); - await setNodeQueue.queueDrained(); + delayPing.resolveP(); + await queue.drained(); } finally { await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); await tempNodeGraph.stop(); await tempNodeGraph.destroy(); } }); test('should block when blocking is set to true', async () => { mockedPingNode.mockImplementation(async (_) => true); - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); try { await nodeConnectionManager.start({ nodeManager }); @@ -911,19 +911,19 @@ describe(`${NodeManager.name} test`, () => { expect(mockedPingNode).toBeCalled(); } finally { await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should update deadline when updating a bucket', async () => { const refreshBucketTimeout = 100000; - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, - setNodeQueue, + queue, refreshBucketTimerDefault: refreshBucketTimeout, logger, }); @@ -933,7 +933,7 @@ describe(`${NodeManager.name} test`, () => { ); try { mockRefreshBucket.mockImplementation(async () => {}); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); // @ts-ignore: kidnap map @@ -953,19 +953,19 @@ describe(`${NodeManager.name} test`, () => { } finally { mockRefreshBucket.mockRestore(); await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should add buckets to the queue when exceeding deadline', async () => { const refreshBucketTimeout = 100; - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, - setNodeQueue, + queue, refreshBucketTimerDefault: refreshBucketTimeout, logger, }); @@ -979,7 +979,7 @@ describe(`${NodeManager.name} test`, () => { ); try { mockRefreshBucket.mockImplementation(async () => {}); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); // Getting starting value @@ -990,19 +990,19 @@ describe(`${NodeManager.name} test`, () => { mockRefreshBucketQueueAdd.mockRestore(); mockRefreshBucket.mockRestore(); await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should digest queue to refresh buckets', async () => { const refreshBucketTimeout = 1000000; - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, - setNodeQueue, + queue, refreshBucketTimerDefault: refreshBucketTimeout, logger, }); @@ -1011,7 +1011,7 @@ describe(`${NodeManager.name} test`, () => { 'refreshBucket', ); try { - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); mockRefreshBucket.mockImplementation(async () => {}); @@ -1028,19 +1028,19 @@ describe(`${NodeManager.name} test`, () => { } finally { mockRefreshBucket.mockRestore(); await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); test('should abort refreshBucket queue when stopping', async () => { const refreshBucketTimeout = 1000000; - const setNodeQueue = new SetNodeQueue({ logger }); + const queue = new Queue({ logger }); const nodeManager = new NodeManager({ db, sigchain: {} as Sigchain, keyManager, nodeGraph, nodeConnectionManager: dummyNodeConnectionManager, - setNodeQueue, + queue, refreshBucketTimerDefault: refreshBucketTimeout, logger, }); @@ -1049,7 +1049,7 @@ describe(`${NodeManager.name} test`, () => { 'refreshBucket', ); try { - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); mockRefreshBucket.mockImplementation( @@ -1071,7 +1071,7 @@ describe(`${NodeManager.name} test`, () => { } finally { mockRefreshBucket.mockRestore(); await nodeManager.stop(); - await setNodeQueue.stop(); + await queue.stop(); } }); }); diff --git a/tests/notifications/NotificationsManager.test.ts b/tests/notifications/NotificationsManager.test.ts index 8a498fdb7..946bdcef6 100644 --- a/tests/notifications/NotificationsManager.test.ts +++ b/tests/notifications/NotificationsManager.test.ts @@ -8,6 +8,7 @@ import path from 'path'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { DB } from '@matrixai/db'; import { IdInternal } from '@matrixai/id'; +import Queue from '@/nodes/Queue'; import PolykeyAgent from '@/PolykeyAgent'; import ACL from '@/acl/ACL'; import Sigchain from '@/sigchain/Sigchain'; @@ -22,7 +23,6 @@ import * as notificationsErrors from '@/notifications/errors'; import * as vaultsUtils from '@/vaults/utils'; import * as nodesUtils from '@/nodes/utils'; import * as keysUtils from '@/keys/utils'; -import SetNodeQueue from '@/nodes/SetNodeQueue'; import * as testUtils from '../utils'; describe('NotificationsManager', () => { @@ -51,7 +51,7 @@ describe('NotificationsManager', () => { let acl: ACL; let db: DB; let nodeGraph: NodeGraph; - let setNodeQueue: SetNodeQueue; + let queue: Queue; let nodeConnectionManager: NodeConnectionManager; let nodeManager: NodeManager; let keyManager: KeyManager; @@ -114,12 +114,12 @@ describe('NotificationsManager', () => { keyManager, logger, }); - setNodeQueue = new SetNodeQueue({ logger }); + queue = new Queue({ logger }); nodeConnectionManager = new NodeConnectionManager({ nodeGraph, keyManager, proxy, - setNodeQueue, + queue, logger, }); nodeManager = new NodeManager({ @@ -128,10 +128,10 @@ describe('NotificationsManager', () => { sigchain, nodeConnectionManager, nodeGraph, - setNodeQueue, + queue, logger, }); - await setNodeQueue.start(); + await queue.start(); await nodeManager.start(); await nodeConnectionManager.start({ nodeManager }); // Set up node for receiving notifications @@ -153,7 +153,7 @@ describe('NotificationsManager', () => { }, global.defaultTimeout); afterAll(async () => { await receiver.stop(); - await setNodeQueue.stop(); + await queue.stop(); await nodeConnectionManager.stop(); await nodeGraph.stop(); await proxy.stop(); diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index 46257fa33..446c750c6 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -8,7 +8,7 @@ import type { import type NotificationsManager from '@/notifications/NotificationsManager'; import type { Host, Port, TLSConfig } from '@/network/types'; import type NodeManager from '@/nodes/NodeManager'; -import type SetNodeQueue from '@/nodes/SetNodeQueue'; +import type Queue from '@/nodes/Queue'; import fs from 'fs'; import os from 'os'; import path from 'path'; @@ -581,7 +581,7 @@ describe('VaultManager', () => { keyManager, nodeGraph, proxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, logger, }); await nodeConnectionManager.start({ @@ -1499,7 +1499,7 @@ describe('VaultManager', () => { logger, nodeGraph, proxy, - setNodeQueue: {} as SetNodeQueue, + queue: {} as Queue, connConnectTime: 1000, }); await nodeConnectionManager.start({ From 40809b8a45cf3d535a694e46e0eabc5adefdc85c Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 27 Apr 2022 15:32:17 +1000 Subject: [PATCH 099/137] tests: general fixes for failing tests This contains fixes for failing tests as well as fixes for tests failing to exit when finished. --- src/PolykeyAgent.ts | 2 +- src/nodes/NodeManager.ts | 14 +- src/nodes/Queue.ts | 4 +- tests/agent/service/notificationsSend.test.ts | 2 + tests/client/service/keysKeyPairRenew.test.ts | 2 +- tests/client/service/keysKeyPairReset.test.ts | 2 +- tests/client/service/nodesAdd.test.ts | 3 +- tests/client/service/nodesClaim.test.ts | 1 + .../client/service/notificationsClear.test.ts | 1 + .../client/service/notificationsRead.test.ts | 1 + .../client/service/notificationsSend.test.ts | 1 + tests/nodes/NodeManager.test.ts | 56 +++-- .../NotificationsManager.test.ts | 1 + tests/utils.ts | 197 +++++++++--------- 14 files changed, 148 insertions(+), 139 deletions(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index d5817347b..781530290 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -551,7 +551,7 @@ class PolykeyAgent { await this.status.updateStatusLive({ nodeId: data.nodeId, }); - await this.nodeManager.refreshBuckets(); + await this.nodeManager.resetBuckets(); const tlsConfig = { keyPrivatePem: keysUtils.privateKeyToPem( data.rootKeyPair.privateKey, diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 79f00637b..a9df2bcce 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -533,22 +533,12 @@ class NodeManager { return await this.nodeGraph.unsetNode(nodeId, tran); } - // FIXME - // /** - // * Gets all buckets from the NodeGraph - // */ - // public async getAllBuckets(tran?: DBTransaction): Promise> { - // return await this.nodeGraph.getAllBuckets(tran); - // } - - // FIXME potentially confusing name, should we rename this to renewBuckets? /** * To be called on key renewal. Re-orders all nodes in all buckets with respect * to the new node ID. */ - public async refreshBuckets(tran?: DBTransaction): Promise { - throw Error('fixme'); - // Return await this.nodeGraph.refreshBuckets(tran); + public async resetBuckets(tran?: DBTransaction): Promise { + return await this.nodeGraph.resetBuckets(this.keyManager.getNodeId(tran)); } /** diff --git a/src/nodes/Queue.ts b/src/nodes/Queue.ts index 441165237..0f9c1485e 100644 --- a/src/nodes/Queue.ts +++ b/src/nodes/Queue.ts @@ -11,8 +11,8 @@ class Queue { protected end: boolean = false; protected queue: Array<() => Promise> = []; protected runner: Promise; - protected plug_: PromiseType; - protected drained_: PromiseType; + protected plug_: PromiseType = promise(); + protected drained_: PromiseType = promise(); constructor({ logger }: { logger?: Logger }) { this.logger = logger ?? new Logger(this.constructor.name); diff --git a/tests/agent/service/notificationsSend.test.ts b/tests/agent/service/notificationsSend.test.ts index 4e584f57c..6d08b842a 100644 --- a/tests/agent/service/notificationsSend.test.ts +++ b/tests/agent/service/notificationsSend.test.ts @@ -169,6 +169,8 @@ describe('notificationsSend', () => { await grpcServer.stop(); await notificationsManager.stop(); await nodeConnectionManager.stop(); + await queue.stop(); + await nodeManager.stop(); await sigchain.stop(); await sigchain.stop(); await proxy.stop(); diff --git a/tests/client/service/keysKeyPairRenew.test.ts b/tests/client/service/keysKeyPairRenew.test.ts index a36c621c1..47445ead0 100644 --- a/tests/client/service/keysKeyPairRenew.test.ts +++ b/tests/client/service/keysKeyPairRenew.test.ts @@ -32,7 +32,7 @@ describe('keysKeyPairRenew', () => { beforeAll(async () => { const globalKeyPair = await testUtils.setupGlobalKeypair(); const newKeyPair = await keysUtils.generateKeyPair(1024); - mockedRefreshBuckets = jest.spyOn(NodeManager.prototype, 'refreshBuckets'); + mockedRefreshBuckets = jest.spyOn(NodeManager.prototype, 'resetBuckets'); mockedGenerateKeyPair = jest .spyOn(keysUtils, 'generateKeyPair') .mockResolvedValueOnce(globalKeyPair) diff --git a/tests/client/service/keysKeyPairReset.test.ts b/tests/client/service/keysKeyPairReset.test.ts index 335d5c5fd..55af8f35c 100644 --- a/tests/client/service/keysKeyPairReset.test.ts +++ b/tests/client/service/keysKeyPairReset.test.ts @@ -32,7 +32,7 @@ describe('keysKeyPairReset', () => { beforeAll(async () => { const globalKeyPair = await testUtils.setupGlobalKeypair(); const newKeyPair = await keysUtils.generateKeyPair(1024); - mockedRefreshBuckets = jest.spyOn(NodeManager.prototype, 'refreshBuckets'); + mockedRefreshBuckets = jest.spyOn(NodeManager.prototype, 'resetBuckets'); mockedGenerateKeyPair = jest .spyOn(keysUtils, 'generateKeyPair') .mockResolvedValueOnce(globalKeyPair) diff --git a/tests/client/service/nodesAdd.test.ts b/tests/client/service/nodesAdd.test.ts index d912fb83a..f2c4969a0 100644 --- a/tests/client/service/nodesAdd.test.ts +++ b/tests/client/service/nodesAdd.test.ts @@ -148,6 +148,7 @@ describe('nodesAdd', () => { await grpcServer.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await queue.stop(); await sigchain.stop(); await proxy.stop(); @@ -176,7 +177,7 @@ describe('nodesAdd', () => { )!, ); expect(result).toBeDefined(); - expect(result!.address).toBe('127.0.0.1:11111'); + expect(result!.address).toEqual({ host: '127.0.0.1', port: 11111 }); }); test('cannot add invalid node', async () => { // Invalid host diff --git a/tests/client/service/nodesClaim.test.ts b/tests/client/service/nodesClaim.test.ts index 5e7dedc8d..95eaf8b6e 100644 --- a/tests/client/service/nodesClaim.test.ts +++ b/tests/client/service/nodesClaim.test.ts @@ -187,6 +187,7 @@ describe('nodesClaim', () => { await grpcClient.destroy(); await grpcServer.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await queue.stop(); await nodeGraph.stop(); await notificationsManager.stop(); diff --git a/tests/client/service/notificationsClear.test.ts b/tests/client/service/notificationsClear.test.ts index 73a5e3597..4a9002f21 100644 --- a/tests/client/service/notificationsClear.test.ts +++ b/tests/client/service/notificationsClear.test.ts @@ -167,6 +167,7 @@ describe('notificationsClear', () => { await notificationsManager.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await queue.stop(); await sigchain.stop(); await proxy.stop(); diff --git a/tests/client/service/notificationsRead.test.ts b/tests/client/service/notificationsRead.test.ts index d5688e6c5..b5a3de17a 100644 --- a/tests/client/service/notificationsRead.test.ts +++ b/tests/client/service/notificationsRead.test.ts @@ -243,6 +243,7 @@ describe('notificationsRead', () => { await sigchain.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await queue.stop(); await proxy.stop(); await acl.stop(); diff --git a/tests/client/service/notificationsSend.test.ts b/tests/client/service/notificationsSend.test.ts index 6a2489bdf..35a6a15bb 100644 --- a/tests/client/service/notificationsSend.test.ts +++ b/tests/client/service/notificationsSend.test.ts @@ -175,6 +175,7 @@ describe('notificationsSend', () => { await notificationsManager.stop(); await nodeGraph.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await queue.stop(); await sigchain.stop(); await proxy.stop(); diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index f40ce814e..66bd40999 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -147,6 +147,7 @@ describe(`${NodeManager.name} test`, () => { 'pings node', async () => { let server: PolykeyAgent | undefined; + let nodeManager: NodeManager | undefined; try { server = await PolykeyAgent.createPolykeyAgent({ password: 'password', @@ -166,7 +167,7 @@ describe(`${NodeManager.name} test`, () => { }; await nodeGraph.setNode(serverNodeId, serverNodeAddress); - const nodeManager = new NodeManager({ + nodeManager = new NodeManager({ db, sigchain, keyManager, @@ -213,6 +214,7 @@ describe(`${NodeManager.name} test`, () => { expect(active3).toBe(false); } finally { // Clean up + await nodeManager?.stop(); await server?.stop(); await server?.destroy(); } @@ -221,6 +223,7 @@ describe(`${NodeManager.name} test`, () => { ); // Ping needs to timeout (takes 20 seconds + setup + pulldown) test('getPublicKey', async () => { let server: PolykeyAgent | undefined; + let nodeManager: NodeManager | undefined; try { server = await PolykeyAgent.createPolykeyAgent({ password: 'password', @@ -240,7 +243,7 @@ describe(`${NodeManager.name} test`, () => { }; await nodeGraph.setNode(serverNodeId, serverNodeAddress); - const nodeManager = new NodeManager({ + nodeManager = new NodeManager({ db, sigchain, keyManager, @@ -258,6 +261,7 @@ describe(`${NodeManager.name} test`, () => { expect(key).toEqual(expectedKey); } finally { // Clean up + await nodeManager?.stop(); await server?.stop(); await server?.destroy(); } @@ -425,29 +429,34 @@ describe(`${NodeManager.name} test`, () => { } }); test('can request chain data', async () => { - // Cross signing claims - await y.nodeManager.claimNode(xNodeId); + let nodeManager: NodeManager | undefined; + try { + // Cross signing claims + await y.nodeManager.claimNode(xNodeId); - const nodeManager = new NodeManager({ - db, - sigchain, - keyManager, - nodeGraph, - nodeConnectionManager, - queue, - logger, - }); - await nodeManager.start(); - await nodeConnectionManager.start({ nodeManager }); + nodeManager = new NodeManager({ + db, + sigchain, + keyManager, + nodeGraph, + nodeConnectionManager, + queue, + logger, + }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); - await nodeGraph.setNode(xNodeId, xNodeAddress); + await nodeGraph.setNode(xNodeId, xNodeAddress); - // We want to get the public key of the server - const chainData = JSON.stringify( - await nodeManager.requestChainData(xNodeId), - ); - expect(chainData).toContain(nodesUtils.encodeNodeId(xNodeId)); - expect(chainData).toContain(nodesUtils.encodeNodeId(yNodeId)); + // We want to get the public key of the server + const chainData = JSON.stringify( + await nodeManager.requestChainData(xNodeId), + ); + expect(chainData).toContain(nodesUtils.encodeNodeId(xNodeId)); + expect(chainData).toContain(nodesUtils.encodeNodeId(yNodeId)); + } finally { + await nodeManager?.stop(); + } }); }); test('should add a node when bucket has room', async () => { @@ -704,6 +713,9 @@ describe(`${NodeManager.name} test`, () => { keysConfig: { rootKeyPairBits: 2048, }, + networkConfig: { + proxyHost: localhost, + }, logger: logger, }); const serverNodeId = server.keyManager.getNodeId(); diff --git a/tests/notifications/NotificationsManager.test.ts b/tests/notifications/NotificationsManager.test.ts index 946bdcef6..e2095f191 100644 --- a/tests/notifications/NotificationsManager.test.ts +++ b/tests/notifications/NotificationsManager.test.ts @@ -155,6 +155,7 @@ describe('NotificationsManager', () => { await receiver.stop(); await queue.stop(); await nodeConnectionManager.stop(); + await nodeManager.stop(); await nodeGraph.stop(); await proxy.stop(); await sigchain.stop(); diff --git a/tests/utils.ts b/tests/utils.ts index c7636c4a5..84c67c90e 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,21 +1,21 @@ -// Import type { StatusLive } from '@/status/types'; +import type { Host } from '@/network/types'; import type { NodeId } from '@/nodes/types'; -// import type { Host } from '@/network/types'; +import type { StatusLive } from '@/status/types'; import path from 'path'; import fs from 'fs'; import lock from 'fd-lock'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { IdInternal } from '@matrixai/id'; -// Import PolykeyAgent from '@/PolykeyAgent'; -// import Status from '@/status/Status'; -// import GRPCClientClient from '@/client/GRPCClientClient'; -// import * as clientUtils from '@/client/utils'; +import PolykeyAgent from '@/PolykeyAgent'; +import Status from '@/status/Status'; +import GRPCClientClient from '@/client/GRPCClientClient'; +import * as clientUtils from '@/client/utils'; import * as keysUtils from '@/keys/utils'; -// Import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as grpcErrors from '@/grpc/errors'; import { sleep } from '@/utils'; import * as errors from '@/errors'; -// import config from '@/config'; +import config from '@/config'; /** * Setup the global keypair @@ -87,100 +87,99 @@ async function setupGlobalKeypair() { // * * Ensure server-side side-effects are removed at the end of each test // */ async function setupGlobalAgent( - _logger: Logger = new Logger(setupGlobalAgent.name, LogLevel.WARN, [ + logger: Logger = new Logger(setupGlobalAgent.name, LogLevel.WARN, [ new StreamHandler(), ]), ): Promise { - throw Error('not implemented'); - // Const globalAgentPassword = 'password'; - // const globalAgentDir = path.join(globalThis.dataDir, 'agent'); - // // The references directory will act like our reference count - // await fs.promises.mkdir(path.join(globalAgentDir, 'references'), { - // recursive: true, - // }); - // const pid = process.pid.toString(); - // // Plus 1 to the reference count - // await fs.promises.writeFile(path.join(globalAgentDir, 'references', pid), ''); - // const globalAgentLock = await fs.promises.open( - // path.join(globalThis.dataDir, 'agent.lock'), - // fs.constants.O_WRONLY | fs.constants.O_CREAT, - // ); - // while (!lock(globalAgentLock.fd)) { - // await sleep(1000); - // } - // const status = new Status({ - // statusPath: path.join(globalAgentDir, config.defaults.statusBase), - // statusLockPath: path.join(globalAgentDir, config.defaults.statusLockBase), - // fs, - // }); - // let statusInfo = await status.readStatus(); - // if (statusInfo == null || statusInfo.status === 'DEAD') { - // await PolykeyAgent.createPolykeyAgent({ - // password: globalAgentPassword, - // nodePath: globalAgentDir, - // networkConfig: { - // proxyHost: '127.0.0.1' as Host, - // forwardHost: '127.0.0.1' as Host, - // agentHost: '127.0.0.1' as Host, - // clientHost: '127.0.0.1' as Host, - // }, - // keysConfig: { - // rootKeyPairBits: 2048, - // }, - // seedNodes: {}, // Explicitly no seed nodes on startup - // logger, - // }); - // statusInfo = await status.readStatus(); - // } - // return { - // globalAgentDir, - // globalAgentPassword, - // globalAgentStatus: statusInfo as StatusLive, - // globalAgentClose: async () => { - // // Closing the global agent cannot be done in the globalTeardown - // // This is due to a sequence of reasons: - // // 1. The global agent is not started as a separate process - // // 2. Because we need to be able to mock dependencies - // // 3. This means it is part of a jest worker process - // // 4. Which will block termination of the jest worker process - // // 5. Therefore globalTeardown will never get to execute - // // 6. The global agent is not part of globalSetup - // // 7. Because not all tests need the global agent - // // 8. Therefore setupGlobalAgent is lazy and executed by jest worker processes - // try { - // await fs.promises.rm(path.join(globalAgentDir, 'references', pid)); - // // If the references directory is not empty - // // there are other processes still using the global agent - // try { - // await fs.promises.rmdir(path.join(globalAgentDir, 'references')); - // } catch (e) { - // if (e.code === 'ENOTEMPTY') { - // return; - // } - // throw e; - // } - // // Stopping may occur in a different jest worker process - // // therefore we cannot rely on pkAgent, but instead use GRPC - // const statusInfo = (await status.readStatus()) as StatusLive; - // const grpcClient = await GRPCClientClient.createGRPCClientClient({ - // nodeId: statusInfo.data.nodeId, - // host: statusInfo.data.clientHost, - // port: statusInfo.data.clientPort, - // tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, - // logger, - // }); - // const emptyMessage = new utilsPB.EmptyMessage(); - // const meta = clientUtils.encodeAuthFromPassword(globalAgentPassword); - // // This is asynchronous - // await grpcClient.agentStop(emptyMessage, meta); - // await grpcClient.destroy(); - // await status.waitFor('DEAD'); - // } finally { - // lock.unlock(globalAgentLock.fd); - // await globalAgentLock.close(); - // } - // }, - // }; + const globalAgentPassword = 'password'; + const globalAgentDir = path.join(globalThis.dataDir, 'agent'); + // The references directory will act like our reference count + await fs.promises.mkdir(path.join(globalAgentDir, 'references'), { + recursive: true, + }); + const pid = process.pid.toString(); + // Plus 1 to the reference count + await fs.promises.writeFile(path.join(globalAgentDir, 'references', pid), ''); + const globalAgentLock = await fs.promises.open( + path.join(globalThis.dataDir, 'agent.lock'), + fs.constants.O_WRONLY | fs.constants.O_CREAT, + ); + while (!lock(globalAgentLock.fd)) { + await sleep(1000); + } + const status = new Status({ + statusPath: path.join(globalAgentDir, config.defaults.statusBase), + statusLockPath: path.join(globalAgentDir, config.defaults.statusLockBase), + fs, + }); + let statusInfo = await status.readStatus(); + if (statusInfo == null || statusInfo.status === 'DEAD') { + await PolykeyAgent.createPolykeyAgent({ + password: globalAgentPassword, + nodePath: globalAgentDir, + networkConfig: { + proxyHost: '127.0.0.1' as Host, + forwardHost: '127.0.0.1' as Host, + agentHost: '127.0.0.1' as Host, + clientHost: '127.0.0.1' as Host, + }, + keysConfig: { + rootKeyPairBits: 2048, + }, + seedNodes: {}, // Explicitly no seed nodes on startup + logger, + }); + statusInfo = await status.readStatus(); + } + return { + globalAgentDir, + globalAgentPassword, + globalAgentStatus: statusInfo as StatusLive, + globalAgentClose: async () => { + // Closing the global agent cannot be done in the globalTeardown + // This is due to a sequence of reasons: + // 1. The global agent is not started as a separate process + // 2. Because we need to be able to mock dependencies + // 3. This means it is part of a jest worker process + // 4. Which will block termination of the jest worker process + // 5. Therefore globalTeardown will never get to execute + // 6. The global agent is not part of globalSetup + // 7. Because not all tests need the global agent + // 8. Therefore setupGlobalAgent is lazy and executed by jest worker processes + try { + await fs.promises.rm(path.join(globalAgentDir, 'references', pid)); + // If the references directory is not empty + // there are other processes still using the global agent + try { + await fs.promises.rmdir(path.join(globalAgentDir, 'references')); + } catch (e) { + if (e.code === 'ENOTEMPTY') { + return; + } + throw e; + } + // Stopping may occur in a different jest worker process + // therefore we cannot rely on pkAgent, but instead use GRPC + const statusInfo = (await status.readStatus()) as StatusLive; + const grpcClient = await GRPCClientClient.createGRPCClientClient({ + nodeId: statusInfo.data.nodeId, + host: statusInfo.data.clientHost, + port: statusInfo.data.clientPort, + tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, + logger, + }); + const emptyMessage = new utilsPB.EmptyMessage(); + const meta = clientUtils.encodeAuthFromPassword(globalAgentPassword); + // This is asynchronous + await grpcClient.agentStop(emptyMessage, meta); + await grpcClient.destroy(); + await status.waitFor('DEAD'); + } finally { + lock.unlock(globalAgentLock.fd); + await globalAgentLock.close(); + } + }, + }; } function generateRandomNodeId(): NodeId { From 4a78c17c759ce9676b2f23446d15335e51ef5f16 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 27 Apr 2022 18:50:53 +1000 Subject: [PATCH 100/137] syntax: added `@typescript-eslint/await-thenable` linting rule This checks if we await things that are not promises. This is not a problem per se, but we generally don't want to await random things. --- .eslintrc | 1 + src/acl/ACL.ts | 2 +- src/claims/utils.ts | 6 ++--- .../providers/github/GitHubProvider.ts | 2 +- src/keys/utils.ts | 2 +- src/nodes/NodeConnectionManager.ts | 2 +- src/nodes/NodeGraph.ts | 2 ++ src/sigchain/utils.ts | 2 +- tests/claims/utils.test.ts | 4 +--- tests/keys/KeyManager.test.ts | 4 ++-- .../NodeConnectionManager.lifecycle.test.ts | 2 +- .../NodeConnectionManager.termination.test.ts | 2 +- tests/sigchain/Sigchain.test.ts | 2 +- tests/vaults/VaultInternal.test.ts | 2 +- tests/vaults/VaultManager.test.ts | 22 +++++++++---------- tests/vaults/VaultOps.test.ts | 2 +- 16 files changed, 30 insertions(+), 29 deletions(-) diff --git a/.eslintrc b/.eslintrc index 5b6e8f753..bc8d334e5 100644 --- a/.eslintrc +++ b/.eslintrc @@ -111,6 +111,7 @@ "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }], + "@typescript-eslint/await-thenable": ["error"], "@typescript-eslint/naming-convention": [ "error", { diff --git a/src/acl/ACL.ts b/src/acl/ACL.ts index ac83ade13..7d737e04c 100644 --- a/src/acl/ACL.ts +++ b/src/acl/ACL.ts @@ -321,7 +321,7 @@ class ACL { true, ); if (permId == null) { - const permId = this.generatePermId(); + const permId = await this.generatePermId(); const permRef = { count: 1, object: { diff --git a/src/claims/utils.ts b/src/claims/utils.ts index faee8ea4b..ea5ecf15d 100644 --- a/src/claims/utils.ts +++ b/src/claims/utils.ts @@ -62,7 +62,7 @@ async function createClaim({ const byteEncoder = new TextEncoder(); const claim = new GeneralSign(byteEncoder.encode(canonicalizedPayload)); claim - .addSignature(await createPrivateKey(privateKey)) + .addSignature(createPrivateKey(privateKey)) .setProtectedHeader({ alg: alg, kid: kid }); const signedClaim = await claim.sign(); return signedClaim as ClaimEncoded; @@ -83,14 +83,14 @@ async function signExistingClaim({ kid: NodeIdEncoded; alg?: string; }): Promise { - const decodedClaim = await decodeClaim(claim); + const decodedClaim = decodeClaim(claim); // Reconstruct the claim with our own signature // Make the payload contents deterministic const canonicalizedPayload = canonicalize(decodedClaim.payload); const byteEncoder = new TextEncoder(); const newClaim = new GeneralSign(byteEncoder.encode(canonicalizedPayload)); newClaim - .addSignature(await createPrivateKey(privateKey)) + .addSignature(createPrivateKey(privateKey)) .setProtectedHeader({ alg: alg, kid: kid }); const signedClaim = await newClaim.sign(); // Add our signature to the existing claim diff --git a/src/identities/providers/github/GitHubProvider.ts b/src/identities/providers/github/GitHubProvider.ts index 8fd0a79fe..bfbce7766 100644 --- a/src/identities/providers/github/GitHubProvider.ts +++ b/src/identities/providers/github/GitHubProvider.ts @@ -514,7 +514,7 @@ class GitHubProvider extends Provider { ); } const data = await response.text(); - const claimIds = await this.extractClaimIds(data); + const claimIds = this.extractClaimIds(data); for (const claimId of claimIds) { const claim = await this.getClaim(authIdentityId, claimId); if (claim != null) { diff --git a/src/keys/utils.ts b/src/keys/utils.ts index e36849f47..32c26eea2 100644 --- a/src/keys/utils.ts +++ b/src/keys/utils.ts @@ -508,7 +508,7 @@ function publicKeyBitSize(publicKey: PublicKey): number { } async function getRandomBytes(size: number): Promise { - return Buffer.from(await random.getBytes(size), 'binary'); + return Buffer.from(random.getBytes(size), 'binary'); } function getRandomBytesSync(size: number): Buffer { diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index e2c133a5f..ce37d0a94 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -550,7 +550,7 @@ class NodeConnectionManager { return this.withConnF( nodeId, async (connection) => { - const client = await connection.getClient(); + const client = connection.getClient(); const response = await client.nodesClosestLocalNodesGet(nodeIdMessage); const nodes: Array<[NodeId, NodeData]> = []; // Loop over each map element (from the returned response) and populate nodes diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index 3baf60299..f4f7ae188 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -379,6 +379,7 @@ class NodeGraph { const nodeId = IdInternal.fromBuffer(nodeIdBuffer); bucketDbIterator.seek(nodeIdBuffer); // @ts-ignore + // eslint-disable-next-line const iteratorResult = await bucketDbIterator.next(); if (iteratorResult == null) never(); const [, nodeData] = iteratorResult; @@ -477,6 +478,7 @@ class NodeGraph { nodesUtils.parseLastUpdatedBucketsDbKey(key as unknown as Buffer); bucketsDbIterator.seek(nodesUtils.bucketsDbKey(bucketIndex_, nodeId)); // @ts-ignore + // eslint-disable-next-line const iteratorResult = await bucketsDbIterator.next(); if (iteratorResult == null) never(); const [, nodeData] = iteratorResult; diff --git a/src/sigchain/utils.ts b/src/sigchain/utils.ts index 7f40dd6a3..fe8cc83f8 100644 --- a/src/sigchain/utils.ts +++ b/src/sigchain/utils.ts @@ -19,7 +19,7 @@ async function verifyChainData( continue; } // If verified, add the claim to the decoded chain - decodedChain[claimId] = await claimsUtils.decodeClaim(encodedClaim); + decodedChain[claimId] = claimsUtils.decodeClaim(encodedClaim); } return decodedChain; } diff --git a/tests/claims/utils.test.ts b/tests/claims/utils.test.ts index 069a6dcef..e57403683 100644 --- a/tests/claims/utils.test.ts +++ b/tests/claims/utils.test.ts @@ -328,9 +328,7 @@ describe('claims/utils', () => { // Create some dummy public key, and check that this does not verify const dummyKeyPair = await keysUtils.generateKeyPair(2048); - const dummyPublicKey = await keysUtils.publicKeyToPem( - dummyKeyPair.publicKey, - ); + const dummyPublicKey = keysUtils.publicKeyToPem(dummyKeyPair.publicKey); expect(await claimsUtils.verifyClaimSignature(claim, dummyPublicKey)).toBe( false, ); diff --git a/tests/keys/KeyManager.test.ts b/tests/keys/KeyManager.test.ts index 260346bc6..c1aaa345e 100644 --- a/tests/keys/KeyManager.test.ts +++ b/tests/keys/KeyManager.test.ts @@ -88,9 +88,9 @@ describe('KeyManager', () => { expect(keysPathContents).toContain('root_certs'); expect(keysPathContents).toContain('db.key'); expect(keyManager.dbKey.toString()).toBeTruthy(); - const rootKeyPairPem = await keyManager.getRootKeyPairPem(); + const rootKeyPairPem = keyManager.getRootKeyPairPem(); expect(rootKeyPairPem).not.toBeUndefined(); - const rootCertPem = await keyManager.getRootCertPem(); + const rootCertPem = keyManager.getRootCertPem(); expect(rootCertPem).not.toBeUndefined(); const rootCertPems = await keyManager.getRootCertChainPems(); expect(rootCertPems.length).toBe(1); diff --git a/tests/nodes/NodeConnectionManager.lifecycle.test.ts b/tests/nodes/NodeConnectionManager.lifecycle.test.ts index 69b21c099..a6f9d04e7 100644 --- a/tests/nodes/NodeConnectionManager.lifecycle.test.ts +++ b/tests/nodes/NodeConnectionManager.lifecycle.test.ts @@ -313,7 +313,7 @@ describe(`${NodeConnectionManager.name} lifecycle test`, () => { }; // Creating the generator - const gen = await nodeConnectionManager.withConnG( + const gen = nodeConnectionManager.withConnG( remoteNodeId1, async function* () { yield* testGenerator(); diff --git a/tests/nodes/NodeConnectionManager.termination.test.ts b/tests/nodes/NodeConnectionManager.termination.test.ts index c26a93c03..86598e78c 100644 --- a/tests/nodes/NodeConnectionManager.termination.test.ts +++ b/tests/nodes/NodeConnectionManager.termination.test.ts @@ -609,7 +609,7 @@ describe(`${NodeConnectionManager.name} termination test`, () => { const firstConnection = firstConnAndLock?.connection; // Resolves if the shutdownCallback was called - const gen = await nodeConnectionManager.withConnG( + const gen = nodeConnectionManager.withConnG( agentNodeId, async function* (): AsyncGenerator { // Throw an error here diff --git a/tests/sigchain/Sigchain.test.ts b/tests/sigchain/Sigchain.test.ts index e35a3c20a..a3bbfb193 100644 --- a/tests/sigchain/Sigchain.test.ts +++ b/tests/sigchain/Sigchain.test.ts @@ -237,7 +237,7 @@ describe('Sigchain', () => { expect(verified2).toBe(true); // Check the hash of the previous claim is correct - const verifiedHash = await claimsUtils.verifyHashOfClaim( + const verifiedHash = claimsUtils.verifyHashOfClaim( claim1, decoded2.payload.hPrev as string, ); diff --git a/tests/vaults/VaultInternal.test.ts b/tests/vaults/VaultInternal.test.ts index d91978c5a..ab817a538 100644 --- a/tests/vaults/VaultInternal.test.ts +++ b/tests/vaults/VaultInternal.test.ts @@ -668,7 +668,7 @@ describe('VaultInternal', () => { await efs.writeFile(secret2.name, secret2.content); }); const commit = (await vault.log())[0].commitId; - const gen = await vault.readG(async function* (efs): AsyncGenerator { + const gen = vault.readG(async function* (efs): AsyncGenerator { yield expect((await efs.readFile(secret1.name)).toString()).toEqual( secret1.content, ); diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index 446c750c6..4cf5d50f9 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -1337,7 +1337,7 @@ describe('VaultManager', () => { }); await sleep(200); expect(pullVaultMock).not.toHaveBeenCalled(); - await releaseWrite(); + releaseWrite(); await pullP; expect(pullVaultMock).toHaveBeenCalled(); pullVaultMock.mockClear(); @@ -1363,16 +1363,16 @@ describe('VaultManager', () => { }); await sleep(200); expect(gitPullMock).not.toHaveBeenCalled(); - await releaseVaultWrite(); - await pullP2; - expect(gitPullMock).toHaveBeenCalled(); - } finally { - pullVaultMock.mockRestore(); - gitPullMock.mockRestore(); - await vaultManager?.stop(); - await vaultManager?.destroy(); - } - }, + releaseVaultWrite(); + await pullP2; + expect(gitPullMock).toHaveBeenCalled(); + } finally { + pullVaultMock.mockRestore(); + gitPullMock.mockRestore(); + await vaultManager?.stop(); + await vaultManager?.destroy(); + } + }, global.failedConnectionTimeout, ); }); diff --git a/tests/vaults/VaultOps.test.ts b/tests/vaults/VaultOps.test.ts index c766ddd74..2152a567d 100644 --- a/tests/vaults/VaultOps.test.ts +++ b/tests/vaults/VaultOps.test.ts @@ -355,7 +355,7 @@ describe('VaultOps', () => { expect( (await vaultOps.getSecret(vault, '.hidingSecret')).toString(), ).toStrictEqual('change_contents'); - await expect( + expect( ( await vaultOps.getSecret(vault, '.hidingDir/.hiddenInSecret') ).toString(), From d1c803c03cbca6533cadb0d69b5592f3da8ec2d4 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 28 Apr 2022 16:00:16 +1000 Subject: [PATCH 101/137] fix: updated `@types/node-forge` version and fixed `keysUtils.getRandomBytes` --- package.json | 2 +- src/keys/utils.ts | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0b34498f5..5aea6e1ea 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "@types/jest": "^27.0.2", "@types/nexpect": "^0.4.31", "@types/node": "^16.11.7", - "@types/node-forge": "^0.9.7", + "@types/node-forge": "^0.10.4", "@types/pako": "^1.0.2", "@types/prompts": "^2.0.13", "@types/readable-stream": "^2.3.11", diff --git a/src/keys/utils.ts b/src/keys/utils.ts index 32c26eea2..14b82a92d 100644 --- a/src/keys/utils.ts +++ b/src/keys/utils.ts @@ -508,7 +508,16 @@ function publicKeyBitSize(publicKey: PublicKey): number { } async function getRandomBytes(size: number): Promise { - return Buffer.from(random.getBytes(size), 'binary'); + const p = new Promise((resolve, reject) => { + random.getBytes(size, (e, bytes) => { + if (e != null) { + reject(e); + } else { + resolve(bytes); + } + }); + }); + return Buffer.from(await p, 'binary'); } function getRandomBytesSync(size: number): Buffer { From f7aae95de3a1bb691d918709eddad0c87f03e1c2 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 28 Apr 2022 19:10:10 +1000 Subject: [PATCH 102/137] tests: added test to check if nodes are properly added to the seed nodes when entering the network This tests for if the Seed node contains the new nodes when they are created. It also checks if the new nodes discover each other after being created. Includes a change to `findNode`. It will no longer throw an error when failing to find the node. This will have to be thrown by the caller now. This was required by `refreshBucket` since it's very likely that we can't find the random node it is looking for. --- src/client/service/nodesFind.ts | 1 + src/nodes/NodeConnectionManager.ts | 23 +++-- src/nodes/NodeManager.ts | 9 +- .../NodeConnectionManager.general.test.ts | 7 +- .../NodeConnectionManager.seednodes.test.ts | 89 ++++++++++++++++++- 5 files changed, 109 insertions(+), 20 deletions(-) diff --git a/src/client/service/nodesFind.ts b/src/client/service/nodesFind.ts index 6c2061719..324e1c0e9 100644 --- a/src/client/service/nodesFind.ts +++ b/src/client/service/nodesFind.ts @@ -50,6 +50,7 @@ function nodesFind({ }, ); const address = await nodeConnectionManager.findNode(nodeId); + if (address == null) throw new nodesErrors.ErrorNodeGraphNodeIdNotFound(); response .setNodeId(nodesUtils.encodeNodeId(nodeId)) .setAddress( diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index ce37d0a94..34f5f4d04 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -267,6 +267,9 @@ class NodeConnectionManager { // Creating the connection and set in map // FIXME: this is fine, just use the implicit tran. fix this when adding optional transactions const targetAddress = await this.findNode(targetNodeId); + if (targetAddress == null) { + throw new nodesErrors.ErrorNodeGraphNodeIdNotFound(); + } // If the stored host is not a valid host (IP address), // then we assume it to be a hostname const targetHostname = !networkUtils.isHost(targetAddress.host) @@ -395,23 +398,17 @@ class NodeConnectionManager { public async findNode( targetNodeId: NodeId, options: { signal?: AbortSignal } = {}, - ): Promise { + ): Promise { const { signal } = { ...options }; // First check if we already have an existing ID -> address record let address = (await this.nodeGraph.getNode(targetNodeId))?.address; // Otherwise, attempt to locate it by contacting network - if (address == null) { - address = await this.getClosestGlobalNodes(targetNodeId, undefined, { + address = + address ?? + (await this.getClosestGlobalNodes(targetNodeId, undefined, { signal, - }); - // TODO: This currently just does one iteration - // If not found in this single iteration, we throw an exception - if (address == null) { - throw new nodesErrors.ErrorNodeGraphNodeIdNotFound(); - } - } - // We ensure that we always return a NodeAddress (either by lookup, or - // network search) - if we can't locate it from either, we throw an exception + })); + // TODO: This currently just does one iteration return address; } @@ -585,6 +582,7 @@ class NodeConnectionManager { */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) public async syncNodeGraph(block: boolean = true, timer?: Timer) { + this.logger.info('Syncing nodeGraph'); for (const seedNodeId of this.getSeedNodes()) { // Check if the connection is viable try { @@ -598,6 +596,7 @@ class NodeConnectionManager { this.keyManager.getNodeId(), timer, ); + // FIXME: we need to ping a node before setting it for (const [nodeId, nodeData] of nodes) { if (!block) { this.queue.push(() => diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index a9df2bcce..2838c8ea1 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -47,8 +47,8 @@ class NodeManager { protected refreshBucketQueue: Set = new Set(); protected refreshBucketQueueRunning: boolean = false; protected refreshBucketQueueRunner: Promise; - protected refreshBucketQueuePlug_: PromiseType; - protected refreshBucketQueueDrained_: PromiseType; + protected refreshBucketQueuePlug_: PromiseType = promise(); + protected refreshBucketQueueDrained_: PromiseType = promise(); protected refreshBucketQueueAbortController: AbortController; constructor({ @@ -109,7 +109,10 @@ class NodeManager { // We need to attempt a connection using the proxies // For now we will just do a forward connect + relay message const targetAddress = - address ?? (await this.nodeConnectionManager.findNode(nodeId))!; + address ?? (await this.nodeConnectionManager.findNode(nodeId)); + if (targetAddress == null) { + throw new nodesErrors.ErrorNodeGraphNodeIdNotFound(); + } const targetHost = await networkUtils.resolveHost(targetAddress.host); return await this.nodeConnectionManager.pingNode( nodeId, diff --git a/tests/nodes/NodeConnectionManager.general.test.ts b/tests/nodes/NodeConnectionManager.general.test.ts index 8905f8718..f0fe65d4e 100644 --- a/tests/nodes/NodeConnectionManager.general.test.ts +++ b/tests/nodes/NodeConnectionManager.general.test.ts @@ -16,7 +16,6 @@ import Proxy from '@/network/Proxy'; import GRPCClientAgent from '@/agent/GRPCClientAgent'; import * as nodesUtils from '@/nodes/utils'; -import * as nodesErrors from '@/nodes/errors'; import * as keysUtils from '@/keys/utils'; import * as grpcUtils from '@/grpc/utils'; import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; @@ -336,9 +335,9 @@ describe(`${NodeConnectionManager.name} general test`, () => { port: 22222 as Port, } as NodeAddress); // Un-findable Node cannot be found - await expect(() => - nodeConnectionManager.findNode(nodeId), - ).rejects.toThrowError(nodesErrors.ErrorNodeGraphNodeIdNotFound); + await expect(nodeConnectionManager.findNode(nodeId)).resolves.toEqual( + undefined, + ); await server.stop(); } finally { diff --git a/tests/nodes/NodeConnectionManager.seednodes.test.ts b/tests/nodes/NodeConnectionManager.seednodes.test.ts index d433dcbd1..b63a4ae54 100644 --- a/tests/nodes/NodeConnectionManager.seednodes.test.ts +++ b/tests/nodes/NodeConnectionManager.seednodes.test.ts @@ -1,4 +1,4 @@ -import type { NodeId, SeedNodes } from '@/nodes/types'; +import type { NodeId, NodeIdEncoded, SeedNodes } from '@/nodes/types'; import type { Host, Port } from '@/network/types'; import type { Sigchain } from '@/sigchain'; import fs from 'fs'; @@ -123,6 +123,13 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { }); beforeEach(async () => { + // Clearing nodes from graphs + for await (const [nodeId] of remoteNode1.nodeGraph.getNodes()) { + await remoteNode1.nodeGraph.unsetNode(nodeId); + } + for await (const [nodeId] of remoteNode2.nodeGraph.getNodes()) { + await remoteNode2.nodeGraph.unsetNode(nodeId); + } dataDir = await fs.promises.mkdtemp( path.join(os.tmpdir(), 'polykey-test-'), ); @@ -417,4 +424,84 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { await queue?.stop(); } }); + test('should expand the network when nodes enter', async () => { + // Using a single seed node we need to check that each entering node adds itself to the seed node. + // Also need to check that the new nodes can be seen in the network. + let node1: PolykeyAgent | undefined; + let node2: PolykeyAgent | undefined; + const seedNodes: SeedNodes = {}; + seedNodes[nodesUtils.encodeNodeId(remoteNodeId1)] = { + host: remoteNode1.proxy.getProxyHost(), + port: remoteNode1.proxy.getProxyPort(), + }; + seedNodes[nodesUtils.encodeNodeId(remoteNodeId2)] = { + host: remoteNode2.proxy.getProxyHost(), + port: remoteNode2.proxy.getProxyPort(), + }; + try { + logger.setLevel(LogLevel.WARN); + node1 = await PolykeyAgent.createPolykeyAgent({ + nodePath: path.join(dataDir, 'node1'), + password: 'password', + networkConfig: { + proxyHost: localHost, + agentHost: localHost, + clientHost: localHost, + forwardHost: localHost, + }, + seedNodes, + logger, + }); + node2 = await PolykeyAgent.createPolykeyAgent({ + nodePath: path.join(dataDir, 'node2'), + password: 'password', + networkConfig: { + proxyHost: localHost, + agentHost: localHost, + clientHost: localHost, + forwardHost: localHost, + }, + seedNodes, + logger, + }); + + await node1.queue.drained(); + await node1.nodeManager.refreshBucketQueueDrained(); + await node2.queue.drained(); + await node2.nodeManager.refreshBucketQueueDrained(); + + const getAllNodes = async (node: PolykeyAgent) => { + const nodes: Array = []; + for await (const [nodeId] of node.nodeGraph.getNodes()) { + nodes.push(nodesUtils.encodeNodeId(nodeId)); + } + return nodes; + }; + const rNode1Nodes = await getAllNodes(remoteNode1); + const rNode2Nodes = await getAllNodes(remoteNode2); + const node1Nodes = await getAllNodes(node1); + const node2Nodes = await getAllNodes(node2); + + const nodeIdR1 = nodesUtils.encodeNodeId(remoteNodeId1); + const nodeIdR2 = nodesUtils.encodeNodeId(remoteNodeId2); + const nodeId1 = nodesUtils.encodeNodeId(node1.keyManager.getNodeId()); + const nodeId2 = nodesUtils.encodeNodeId(node2.keyManager.getNodeId()); + expect(rNode1Nodes).toContain(nodeId1); + expect(rNode1Nodes).toContain(nodeId2); + expect(rNode2Nodes).toContain(nodeId1); + expect(rNode2Nodes).toContain(nodeId2); + expect(node1Nodes).toContain(nodeIdR1); + expect(node1Nodes).toContain(nodeIdR2); + expect(node1Nodes).toContain(nodeId2); + expect(node2Nodes).toContain(nodeIdR1); + expect(node2Nodes).toContain(nodeIdR2); + expect(node2Nodes).toContain(nodeId1); + } finally { + logger.setLevel(LogLevel.WARN); + await node1?.stop(); + await node1?.destroy(); + await node2?.stop(); + await node2?.destroy(); + } + }); }); From 22423a6833542434d0c00689c8da7201596c7b50 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 29 Apr 2022 16:58:11 +1000 Subject: [PATCH 103/137] tests: Added agent service tests for `nodesChainDataGet`, `nodesClosestLocalNode` and `nodesHolePunchMessage` --- tests/agent/service/nodesChainDataGet.test.ts | 108 ++++++++++++++++ .../service/nodesClosestLocalNode.test.ts | 118 ++++++++++++++++++ .../service/nodesHolePunchMessage.test.ts | 103 +++++++++++++++ 3 files changed, 329 insertions(+) create mode 100644 tests/agent/service/nodesChainDataGet.test.ts create mode 100644 tests/agent/service/nodesClosestLocalNode.test.ts create mode 100644 tests/agent/service/nodesHolePunchMessage.test.ts diff --git a/tests/agent/service/nodesChainDataGet.test.ts b/tests/agent/service/nodesChainDataGet.test.ts new file mode 100644 index 000000000..8bc388763 --- /dev/null +++ b/tests/agent/service/nodesChainDataGet.test.ts @@ -0,0 +1,108 @@ +import type { Host, Port } from '@/network/types'; +import type { NodeIdEncoded } from '@/nodes/types'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import PolykeyAgent from '@/PolykeyAgent'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientAgent from '@/agent/GRPCClientAgent'; +import { AgentServiceService } from '@/proto/js/polykey/v1/agent_service_grpc_pb'; +import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; +import * as keysUtils from '@/keys/utils'; +import * as nodesUtils from '@/nodes/utils'; +import nodesClosestLocalNodesGet from '@/agent/service/nodesClosestLocalNodesGet'; +import * as testNodesUtils from '../../nodes/utils'; +import * as testUtils from '../../utils'; + +describe('nodesClosestLocalNode', () => { + const logger = new Logger('nodesClosestLocalNode test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + let dataDir: string; + let nodePath: string; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientAgent; + let pkAgent: PolykeyAgent; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValueOnce(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValueOnce(globalKeyPair); + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + nodePath = path.join(dataDir, 'keynode'); + pkAgent = await PolykeyAgent.createPolykeyAgent({ + password, + nodePath, + keysConfig: { + rootKeyPairBits: 2048, + }, + seedNodes: {}, // Explicitly no seed nodes on startup + networkConfig: { + proxyHost: '127.0.0.1' as Host, + }, + logger, + }); + // Setting up a remote keynode + const agentService = { + nodesClosestLocalNodesGet: nodesClosestLocalNodesGet({ + nodeGraph: pkAgent.nodeGraph, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[AgentServiceService, agentService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientAgent.createGRPCClientAgent({ + nodeId: pkAgent.keyManager.getNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }, global.defaultTimeout); + afterAll(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await pkAgent.stop(); + await pkAgent.destroy(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + test('should get closest local nodes', async () => { + // Adding 10 nodes + const nodes: Array = []; + for (let i = 0; i < 10; i++) { + const nodeId = testNodesUtils.generateRandomNodeId(); + await pkAgent.nodeGraph.setNode(nodeId, { + host: 'localhost' as Host, + port: 55555 as Port, + }); + nodes.push(nodesUtils.encodeNodeId(nodeId)); + } + const nodeIdEncoded = nodesUtils.encodeNodeId( + testNodesUtils.generateRandomNodeId(), + ); + const nodeMessage = new nodesPB.Node(); + nodeMessage.setNodeId(nodeIdEncoded); + const result = await grpcClient.nodesClosestLocalNodesGet(nodeMessage); + const resultNodes: Array = []; + for (const [resultNode] of result.toObject().nodeTableMap) { + resultNodes.push(resultNode as NodeIdEncoded); + } + expect(nodes.sort()).toEqual(resultNodes.sort()); + }); +}); diff --git a/tests/agent/service/nodesClosestLocalNode.test.ts b/tests/agent/service/nodesClosestLocalNode.test.ts new file mode 100644 index 000000000..5453d8e5a --- /dev/null +++ b/tests/agent/service/nodesClosestLocalNode.test.ts @@ -0,0 +1,118 @@ +import type { Host, Port } from '@/network/types'; +import type { ClaimData } from '@/claims/types'; +import type { IdentityId, ProviderId } from '@/identities/types'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import PolykeyAgent from '@/PolykeyAgent'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientAgent from '@/agent/GRPCClientAgent'; +import { AgentServiceService } from '@/proto/js/polykey/v1/agent_service_grpc_pb'; +import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; +import * as keysUtils from '@/keys/utils'; +import * as nodesUtils from '@/nodes/utils'; +import nodesChainDataGet from '@/agent/service/nodesChainDataGet'; +import * as testUtils from '../../utils'; +import * as testNodesUtils from '../../nodes/utils'; + +describe('nodesChainDataGet', () => { + const logger = new Logger('nodesChainDataGet test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + let dataDir: string; + let nodePath: string; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientAgent; + let pkAgent: PolykeyAgent; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValueOnce(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValueOnce(globalKeyPair); + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + nodePath = path.join(dataDir, 'keynode'); + pkAgent = await PolykeyAgent.createPolykeyAgent({ + password, + nodePath, + keysConfig: { + rootKeyPairBits: 2048, + }, + seedNodes: {}, // Explicitly no seed nodes on startup + networkConfig: { + proxyHost: '127.0.0.1' as Host, + }, + logger, + }); + const agentService = { + nodesChainDataGet: nodesChainDataGet({ + sigchain: pkAgent.sigchain, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[AgentServiceService, agentService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientAgent.createGRPCClientAgent({ + nodeId: pkAgent.keyManager.getNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }, global.defaultTimeout); + afterAll(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await pkAgent.stop(); + await pkAgent.destroy(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + test('should get closest nodes', async () => { + const srcNodeIdEncoded = nodesUtils.encodeNodeId( + pkAgent.keyManager.getNodeId(), + ); + // Add 10 claims + for (let i = 1; i <= 5; i++) { + const node2 = nodesUtils.encodeNodeId( + testNodesUtils.generateRandomNodeId(), + ); + const nodeLink: ClaimData = { + type: 'node', + node1: srcNodeIdEncoded, + node2: node2, + }; + await pkAgent.sigchain.addClaim(nodeLink); + } + for (let i = 6; i <= 10; i++) { + const identityLink: ClaimData = { + type: 'identity', + node: srcNodeIdEncoded, + provider: ('ProviderId' + i.toString()) as ProviderId, + identity: ('IdentityId' + i.toString()) as IdentityId, + }; + await pkAgent.sigchain.addClaim(identityLink); + } + + const response = await grpcClient.nodesChainDataGet( + new utilsPB.EmptyMessage(), + ); + const chainIds: Array = []; + for (const [id] of response.toObject().chainDataMap) chainIds.push(id); + expect(chainIds).toHaveLength(10); + }); +}); diff --git a/tests/agent/service/nodesHolePunchMessage.test.ts b/tests/agent/service/nodesHolePunchMessage.test.ts new file mode 100644 index 000000000..4bef6d759 --- /dev/null +++ b/tests/agent/service/nodesHolePunchMessage.test.ts @@ -0,0 +1,103 @@ +import type { Host, Port } from '@/network/types'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import PolykeyAgent from '@/PolykeyAgent'; +import GRPCServer from '@/grpc/GRPCServer'; +import GRPCClientAgent from '@/agent/GRPCClientAgent'; +import { AgentServiceService } from '@/proto/js/polykey/v1/agent_service_grpc_pb'; +import * as nodesPB from '@/proto/js/polykey/v1/nodes/nodes_pb'; +import * as keysUtils from '@/keys/utils'; +import * as nodesUtils from '@/nodes/utils'; +import nodesHolePunchMessageSend from '@/agent/service/nodesHolePunchMessageSend'; +import * as networkUtils from '@/network/utils'; +import * as testUtils from '../../utils'; + +describe('nodesHolePunchMessage', () => { + const logger = new Logger('nodesHolePunchMessage test', LogLevel.WARN, [ + new StreamHandler(), + ]); + const password = 'helloworld'; + let dataDir: string; + let nodePath: string; + let grpcServer: GRPCServer; + let grpcClient: GRPCClientAgent; + let pkAgent: PolykeyAgent; + let mockedGenerateKeyPair: jest.SpyInstance; + let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + beforeAll(async () => { + const globalKeyPair = await testUtils.setupGlobalKeypair(); + mockedGenerateKeyPair = jest + .spyOn(keysUtils, 'generateKeyPair') + .mockResolvedValueOnce(globalKeyPair); + mockedGenerateDeterministicKeyPair = jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockResolvedValueOnce(globalKeyPair); + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + nodePath = path.join(dataDir, 'keynode'); + pkAgent = await PolykeyAgent.createPolykeyAgent({ + password, + nodePath, + keysConfig: { + rootKeyPairBits: 2048, + }, + seedNodes: {}, // Explicitly no seed nodes on startup + networkConfig: { + proxyHost: '127.0.0.1' as Host, + }, + logger, + }); + const agentService = { + nodesHolePunchMessageSend: nodesHolePunchMessageSend({ + keyManager: pkAgent.keyManager, + nodeConnectionManager: pkAgent.nodeConnectionManager, + nodeManager: pkAgent.nodeManager, + }), + }; + grpcServer = new GRPCServer({ logger }); + await grpcServer.start({ + services: [[AgentServiceService, agentService]], + host: '127.0.0.1' as Host, + port: 0 as Port, + }); + grpcClient = await GRPCClientAgent.createGRPCClientAgent({ + nodeId: pkAgent.keyManager.getNodeId(), + host: '127.0.0.1' as Host, + port: grpcServer.getPort(), + logger, + }); + }, global.defaultTimeout); + afterAll(async () => { + await grpcClient.destroy(); + await grpcServer.stop(); + await pkAgent.stop(); + await pkAgent.destroy(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + mockedGenerateKeyPair.mockRestore(); + mockedGenerateDeterministicKeyPair.mockRestore(); + }); + test('should get the chain data', async () => { + const nodeId = nodesUtils.encodeNodeId(pkAgent.keyManager.getNodeId()); + const proxyAddress = networkUtils.buildAddress( + pkAgent.proxy.getProxyHost(), + pkAgent.proxy.getProxyPort(), + ); + const signature = await pkAgent.keyManager.signWithRootKeyPair( + Buffer.from(proxyAddress), + ); + const relayMessage = new nodesPB.Relay(); + relayMessage + .setTargetId(nodeId) + .setSrcId(nodeId) + .setSignature(signature.toString()) + .setProxyAddress(proxyAddress); + await grpcClient.nodesHolePunchMessageSend(relayMessage); + // TODO: check if the ping was sent + }); +}); From 0d277e84bedc15188cdb3a948d1927be83af4e74 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 2 Jun 2022 17:04:54 +1000 Subject: [PATCH 104/137] fix: post re-base fixes DB and type changes using new transactions Linting Fixing timeouts --- src/PolykeyAgent.ts | 4 +- src/acl/ACL.ts | 2 +- src/client/service/nodesAdd.ts | 4 +- src/nodes/NodeConnectionManager.ts | 17 +- src/nodes/NodeGraph.ts | 126 +++--- src/nodes/NodeManager.ts | 24 +- src/nodes/errors.ts | 8 +- src/nodes/utils.ts | 41 +- tests/agent/service/nodesChainDataGet.test.ts | 2 + .../service/nodesClosestLocalNode.test.ts | 2 + .../service/nodesHolePunchMessage.test.ts | 2 + tests/client/service/agentLockAll.test.ts | 3 +- tests/gestalts/GestaltGraph.test.ts | 4 +- tests/network/Proxy.test.ts | 10 +- tests/nodes/NodeConnection.test.ts | 2 +- .../NodeConnectionManager.seednodes.test.ts | 158 +++---- tests/nodes/utils.test.ts | 30 +- tests/utils.ts | 1 - tests/vaults/VaultInternal.test.ts | 102 ++--- tests/vaults/VaultManager.test.ts | 412 +++++++++--------- 20 files changed, 481 insertions(+), 473 deletions(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index 781530290..e3f033c71 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -690,6 +690,7 @@ class PolykeyAgent { this.logger.info(`Started ${this.constructor.name}`); } catch (e) { this.logger.warn(`Failed Starting ${this.constructor.name}`); + this.events.removeAllListeners(); await this.status?.beginStop({ pid: process.pid }); await this.sessionManager?.stop(); await this.notificationsManager?.stop(); @@ -706,7 +707,6 @@ class PolykeyAgent { await this.keyManager?.stop(); await this.schema?.stop(); await this.status?.stop({}); - this.events.removeAllListeners(); throw e; } } @@ -716,6 +716,7 @@ class PolykeyAgent { */ public async stop() { this.logger.info(`Stopping ${this.constructor.name}`); + this.events.removeAllListeners(); await this.status.beginStop({ pid: process.pid }); await this.sessionManager.stop(); await this.notificationsManager.stop(); @@ -736,7 +737,6 @@ class PolykeyAgent { await this.keyManager.stop(); await this.schema.stop(); await this.status.stop({}); - this.events.removeAllListeners(); this.logger.info(`Stopped ${this.constructor.name}`); } diff --git a/src/acl/ACL.ts b/src/acl/ACL.ts index 7d737e04c..ac83ade13 100644 --- a/src/acl/ACL.ts +++ b/src/acl/ACL.ts @@ -321,7 +321,7 @@ class ACL { true, ); if (permId == null) { - const permId = await this.generatePermId(); + const permId = this.generatePermId(); const permRef = { count: 1, object: { diff --git a/src/client/service/nodesAdd.ts b/src/client/service/nodesAdd.ts index 0884a0f0b..0d993c746 100644 --- a/src/client/service/nodesAdd.ts +++ b/src/client/service/nodesAdd.ts @@ -14,7 +14,7 @@ import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import * as clientUtils from '../utils'; /** - * Adds a node ID -> node address mapping into the buckets database. + * Adds a node ID -> node address mapping into the buckets' database. * This is an unrestricted add: no validity checks are made for the correctness * of the passed ID or host/port. */ @@ -67,6 +67,8 @@ function nodesAdd({ host, port, } as NodeAddress, + true, + true, undefined, tran, ), diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 34f5f4d04..484757f81 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -11,13 +11,10 @@ import type { NodeId, NodeIdString, SeedNodes, - NodeEntry, - NodeBucket, - NodeIdString, } from './types'; -import { withF } from '@matrixai/resources'; import type NodeManager from './NodeManager'; import type { AbortSignal } from 'node-abort-controller'; +import { withF } from '@matrixai/resources'; import Logger from '@matrixai/logger'; import { ready, StartStop } from '@matrixai/async-init/dist/StartStop'; import { IdInternal } from '@matrixai/id'; @@ -139,7 +136,6 @@ class NodeConnectionManager { * an acquire function with no parameters). * @param targetNodeId Id of target node to communicate with * @param timer Connection timeout timer - * @param address Optional address to connect to * @returns ResourceAcquire Resource API for use in with contexts */ @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) @@ -148,7 +144,10 @@ class NodeConnectionManager { timer?: Timer, ): Promise>> { return async () => { - const { connection, timer } = await this.getConnection(targetNodeId, timer); + const { connection, timer: timeToLiveTimer } = await this.getConnection( + targetNodeId, + timer, + ); // Acquire the read lock and the release function const [release] = await this.connectionLocks.lock([ targetNodeId.toString(), @@ -156,7 +155,7 @@ class NodeConnectionManager { 'write', ])(); // Resetting TTL timer - timer?.refresh(); + timeToLiveTimer?.refresh(); // Return tuple of [ResourceRelease, Resource] return [ async (e) => { @@ -224,7 +223,7 @@ class NodeConnectionManager { const [release, conn] = await acquire(); let caughtError; try { - return yield* await g(conn!); + return yield* g(conn!); } catch (e) { caughtError = e; throw e; @@ -604,7 +603,7 @@ class NodeConnectionManager { ); } else { try { - // FIXME: no tran neededawait this.nodeManager?.setNode(nodeId, nodeData.address); + await this.nodeManager?.setNode(nodeId, nodeData.address); } catch (e) { if (!(e instanceof nodesErrors.ErrorNodeGraphSameNodeId)) throw e; } diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index f4f7ae188..a5b8da332 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -198,7 +198,7 @@ class NodeGraph { }, this.nodeGraphBucketsDbPath, )) { - const { nodeId } = nodesUtils.parseBucketsDbKey(key as unknown as Buffer); + const { nodeId } = nodesUtils.parseBucketsDbKey(key as Array); yield [nodeId, nodeData]; } } @@ -224,11 +224,9 @@ class NodeGraph { const [bucketIndex, bucketKey] = this.bucketIndex(nodeId); const lastUpdatedPath = [...this.nodeGraphLastUpdatedDbPath, bucketKey]; - const bucketPath = [...this.nodeGraphBucketsDbPath, bucketKey]; - const nodeData = await tran.get([ - ...bucketPath, - nodesUtils.bucketDbKey(nodeId), - ]); + const nodeIdKey = nodesUtils.bucketDbKey(nodeId); + const bucketPath = [...this.nodeGraphBucketsDbPath, bucketKey, nodeIdKey]; + const nodeData = await tran.get(bucketPath); if (nodeData != null) { this.logger.debug( `Updating node ${nodesUtils.encodeNodeId( @@ -236,33 +234,27 @@ class NodeGraph { )} in bucket ${bucketIndex}`, ); // If the node already exists we want to remove the old `lastUpdated` - const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( - nodeData.lastUpdated, - nodeId, - ); - await tran.del([...lastUpdatedPath, lastUpdatedKey]); + const lastUpdatedKey = nodesUtils.lastUpdatedKey(nodeData.lastUpdated); + await tran.del([...lastUpdatedPath, lastUpdatedKey, nodeIdKey]); } else { this.logger.debug( `Adding node ${nodesUtils.encodeNodeId( nodeId, )} to bucket ${bucketIndex}`, ); - // It didn't exist so we want to increment the bucket count + // It didn't exist, so we want to increment the bucket count const count = await this.getBucketMetaProp(bucketIndex, 'count', tran); await this.setBucketMetaProp(bucketIndex, 'count', count + 1, tran); } const lastUpdated = getUnixtime(); - await tran.put([...bucketPath, nodesUtils.bucketDbKey(nodeId)], { + await tran.put(bucketPath, { address: nodeAddress, lastUpdated, }); - const newLastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( - lastUpdated, - nodeId, - ); + const newLastUpdatedKey = nodesUtils.lastUpdatedKey(lastUpdated); await tran.put( - [...lastUpdatedPath, newLastUpdatedKey], - nodesUtils.bucketDbKey(nodeId), + [...lastUpdatedPath, newLastUpdatedKey, nodeIdKey], + nodeIdKey, true, ); } @@ -281,8 +273,13 @@ class NodeGraph { const bucketKey = nodesUtils.bucketKey(bucketIndex); // Remove the oldest entry in the bucket const oldestNodeIds: Array = []; - for await (const [key] of tran.iterator({ limit }, [...this.nodeGraphLastUpdatedDbPath, bucketKey])) { - const { nodeId } = nodesUtils.parseLastUpdatedBucketDbKey(key as unknown as Buffer); + for await (const [key] of tran.iterator({ limit }, [ + ...this.nodeGraphLastUpdatedDbPath, + bucketKey, + ])) { + const { nodeId } = nodesUtils.parseLastUpdatedBucketDbKey( + key as Array, + ); oldestNodeIds.push(nodeId); } return oldestNodeIds; @@ -299,10 +296,8 @@ class NodeGraph { const [bucketIndex, bucketKey] = this.bucketIndex(nodeId); const bucketPath = [...this.nodeGraphBucketsDbPath, bucketKey]; const lastUpdatedPath = [...this.nodeGraphLastUpdatedDbPath, bucketKey]; - const nodeData = await tran.get([ - ...bucketPath, - nodesUtils.bucketDbKey(nodeId), - ]); + const nodeIdKey = nodesUtils.bucketDbKey(nodeId); + const nodeData = await tran.get([...bucketPath, nodeIdKey]); if (nodeData != null) { this.logger.debug( `Removing node ${nodesUtils.encodeNodeId( @@ -311,12 +306,9 @@ class NodeGraph { ); const count = await this.getBucketMetaProp(bucketIndex, 'count', tran); await this.setBucketMetaProp(bucketIndex, 'count', count - 1, tran); - await tran.del([...bucketPath, nodesUtils.bucketDbKey(nodeId)]); - const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( - nodeData.lastUpdated, - nodeId, - ); - await tran.del([...lastUpdatedPath, lastUpdatedKey]); + await tran.del([...bucketPath, nodeIdKey]); + const lastUpdatedKey = nodesUtils.lastUpdatedKey(nodeData.lastUpdated); + await tran.del([...lastUpdatedPath, lastUpdatedKey, nodeIdKey]); } } @@ -354,7 +346,7 @@ class NodeGraph { }, [...this.nodeGraphBucketsDbPath, bucketKey], )) { - const nodeId = nodesUtils.parseBucketDbKey(key as unknown as Buffer); + const nodeId = nodesUtils.parseBucketDbKey(key[0] as Buffer); bucket.push([nodeId, nodeData]); } if (sort === 'distance') { @@ -429,7 +421,7 @@ class NodeGraph { this.nodeGraphBucketsDbPath, )) { const { bucketIndex: bucketIndex_, nodeId } = - nodesUtils.parseBucketsDbKey(key as unknown as Buffer); + nodesUtils.parseBucketsDbKey(key as Array); if (bucketIndex == null) { // First entry of the first bucket bucketIndex = bucketIndex_; @@ -475,8 +467,8 @@ class NodeGraph { this.nodeGraphLastUpdatedDbPath, )) { const { bucketIndex: bucketIndex_, nodeId } = - nodesUtils.parseLastUpdatedBucketsDbKey(key as unknown as Buffer); - bucketsDbIterator.seek(nodesUtils.bucketsDbKey(bucketIndex_, nodeId)); + nodesUtils.parseLastUpdatedBucketsDbKey(key as Array); + bucketsDbIterator.seek([key[0], key[2]]); // @ts-ignore // eslint-disable-next-line const iteratorResult = await bucketsDbIterator.next(); @@ -518,8 +510,10 @@ class NodeGraph { ); } + const logger = this.logger.getChild('resetBuckets'); // Setup new space const spaceNew = this.space === '0' ? '1' : '0'; + logger.debug('new space: ' + spaceNew); const nodeGraphMetaDbPathNew = [...this.nodeGraphDbPath, 'meta' + spaceNew]; const nodeGraphBucketsDbPathNew = [ ...this.nodeGraphDbPath, @@ -540,10 +534,16 @@ class NodeGraph { this.nodeGraphBucketsDbPath, )) { // The key is a combined bucket key and node ID - const { nodeId } = nodesUtils.parseBucketsDbKey(key as unknown as Buffer); + const { bucketIndex: bucketIndexOld, nodeId } = + nodesUtils.parseBucketsDbKey(key as Array); + const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); + const nodeIdKey = nodesUtils.bucketDbKey(nodeId); // If the new own node ID is one of the existing node IDs, it is just dropped // We only map to the new bucket if it isn't one of the existing node IDs if (nodeId.equals(nodeIdOwn)) { + logger.debug( + `nodeId ${nodeIdEncoded} from bucket ${bucketIndexOld} was identical to new NodeId and was dropped.`, + ); continue; } const bucketIndexNew = nodesUtils.bucketIndex(nodeIdOwn, nodeId); @@ -555,7 +555,7 @@ class NodeGraph { if (countNew < this.nodeBucketLimit) { await tran.put([...metaPathNew, 'count'], countNew + 1); } else { - let oldestIndexKey: Buffer | undefined = undefined; + let oldestIndexKey: Array | undefined = undefined; let oldestNodeId: NodeId | undefined = undefined; for await (const [key] of tran.iterator( { @@ -563,28 +563,29 @@ class NodeGraph { }, indexPathNew, )) { - oldestIndexKey = key as unknown as Buffer; + oldestIndexKey = key as Array; ({ nodeId: oldestNodeId } = nodesUtils.parseLastUpdatedBucketDbKey( - key as unknown as Buffer, + key as Array, )); } await tran.del([ ...bucketPathNew, nodesUtils.bucketDbKey(oldestNodeId!), ]); - await tran.del([...indexPathNew, oldestIndexKey!]); + await tran.del([...indexPathNew, ...oldestIndexKey!]); } + if (bucketIndexOld !== bucketIndexNew) { + logger.debug( + `nodeId ${nodeIdEncoded} moved ${bucketIndexOld}=>${bucketIndexNew}`, + ); + } else { + logger.debug(`nodeId ${nodeIdEncoded} unchanged ${bucketIndexOld}`); + } + await tran.put([...bucketPathNew, nodeIdKey], nodeData); + const lastUpdatedKey = nodesUtils.lastUpdatedKey(nodeData.lastUpdated); await tran.put( - [...bucketPathNew, nodesUtils.bucketDbKey(nodeId)], - nodeData, - ); - const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( - nodeData.lastUpdated, - nodeId, - ); - await tran.put( - [...indexPathNew, lastUpdatedKey], - nodesUtils.bucketDbKey(nodeId), + [...indexPathNew, lastUpdatedKey, nodeIdKey], + nodeIdKey, true, ); } @@ -678,6 +679,8 @@ class NodeGraph { * current node has less than k nodes in all of its buckets, in which case it * returns all nodes it has knowledge of) */ + // FIXME: this is still operating on assumptions from old code. + // I can't get the gt/lt to work on the iterator. @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async getClosestNodes( nodeId: NodeId, @@ -716,55 +719,44 @@ class NodeGraph { // We can just use `!(lexpack bucketId)` to start from // Less than `!(bucketId 101)!` gets us buckets 100 and lower // greater than `!(bucketId 99)!` gets up buckets 100 and greater - const prefix = Buffer.from([33]); // Code for `!` prefix if (nodeIds.length < limit) { // Just before target bucket - const bucketId = Buffer.from(nodesUtils.bucketKey(startingBucket)); - const endKeyLower = Buffer.concat([prefix, bucketId, prefix]); + const bucketIdKey = Buffer.from(nodesUtils.bucketKey(startingBucket)); const remainingLimit = limit - nodeIds.length; // Iterate over lower buckets - tran.iterator( - { - lt: endKeyLower, - limit: remainingLimit, - valueAsBuffer: false, - }, - this.nodeGraphBucketsDbPath, - ); for await (const [key, nodeData] of tran.iterator( { - lt: endKeyLower, + lt: [bucketIdKey, ''], limit: remainingLimit, valueAsBuffer: false, }, this.nodeGraphBucketsDbPath, )) { - const info = nodesUtils.parseBucketsDbKey(key as unknown as Buffer); + const info = nodesUtils.parseBucketsDbKey(key as Array); nodeIds.push([info.nodeId, nodeData]); } } if (nodeIds.length < limit) { // Just after target bucket const bucketId = Buffer.from(nodesUtils.bucketKey(startingBucket + 1)); - const startKeyUpper = Buffer.concat([prefix, bucketId, prefix]); const remainingLimit = limit - nodeIds.length; // Iterate over ids further away tran.iterator( { - gt: startKeyUpper, + gt: [bucketId, ''], limit: remainingLimit, }, this.nodeGraphBucketsDbPath, ); for await (const [key, nodeData] of tran.iterator( { - gt: startKeyUpper, + gt: [bucketId, ''], limit: remainingLimit, valueAsBuffer: false, }, this.nodeGraphBucketsDbPath, )) { - const info = nodesUtils.parseBucketsDbKey(key as unknown as Buffer); + const info = nodesUtils.parseBucketsDbKey(key as Array); nodeIds.push([info.nodeId, nodeData]); } } diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 2838c8ea1..23832dbb7 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -116,10 +116,8 @@ class NodeManager { const targetHost = await networkUtils.resolveHost(targetAddress.host); return await this.nodeConnectionManager.pingNode( nodeId, - { - host: targetHost, - port: targetAddress.port, - }, + targetHost, + targetAddress.port, timer, ); } @@ -383,7 +381,7 @@ class NodeManager { */ public async getBucket( bucketIndex: number, - tran: DBTransaction, + tran?: DBTransaction, ): Promise { return await this.nodeGraph.getBucket( bucketIndex, @@ -402,7 +400,7 @@ class NodeManager { * @param block - Flag for if the operation should block or utilize the async queue * @param force - Flag for if we want to add the node without authenticating or if the bucket is full. * This will drop the oldest node in favor of the new. - * @param timeout Connection timeout timeout + * @param timeout Connection timeout * @param tran */ @ready(new nodesErrors.ErrorNodeManagerNotRunning()) @@ -412,8 +410,14 @@ class NodeManager { block: boolean = true, force: boolean = false, timeout?: number, - tran: DBTransaction, + tran?: DBTransaction, ): Promise { + if (tran == null) { + return this.db.withTransactionF(async (tran) => + this.setNode(nodeId, nodeAddress, block, force, timeout, tran), + ); + } + // When adding a node we need to handle 3 cases // 1. The node already exists. We need to update it's last updated field // 2. The node doesn't exist and bucket has room. @@ -486,7 +490,7 @@ class NodeManager { nodeAddress: NodeAddress, timeout?: number, ) { - const oldestNodeIds = await this.nodeGraph.getOldestNode(bucketIndex, 3, tran); + const oldestNodeIds = await this.nodeGraph.getOldestNode(bucketIndex, 3); // We want to concurrently ping the nodes const pingPromises = oldestNodeIds.map((nodeId) => { const doPing = async (): Promise<{ @@ -540,8 +544,8 @@ class NodeManager { * To be called on key renewal. Re-orders all nodes in all buckets with respect * to the new node ID. */ - public async resetBuckets(tran?: DBTransaction): Promise { - return await this.nodeGraph.resetBuckets(this.keyManager.getNodeId(tran)); + public async resetBuckets(): Promise { + return await this.nodeGraph.resetBuckets(this.keyManager.getNodeId()); } /** diff --git a/src/nodes/errors.ts b/src/nodes/errors.ts index ad5b31c90..b35a58f70 100644 --- a/src/nodes/errors.ts +++ b/src/nodes/errors.ts @@ -2,17 +2,17 @@ import { ErrorPolykey, sysexits } from '../errors'; class ErrorNodes extends ErrorPolykey {} -class ErrorNodeAborted extends ErrorNodes { - description = 'Operation was aborted'; +class ErrorNodeAborted extends ErrorNodes { + static description = 'Operation was aborted'; exitCode = sysexits.USAGE; } -class ErrorNodeManagerNotRunning extends ErrorNodes { +class ErrorNodeManagerNotRunning extends ErrorNodes { static description = 'NodeManager is not running'; exitCode = sysexits.USAGE; } -class ErrorQueueNotRunning extends ErrorNodes { +class ErrorQueueNotRunning extends ErrorNodes { static description = 'queue is not running'; exitCode = sysexits.USAGE; } diff --git a/src/nodes/utils.ts b/src/nodes/utils.ts index c61a6cd58..449fc407b 100644 --- a/src/nodes/utils.ts +++ b/src/nodes/utils.ts @@ -6,7 +6,7 @@ import type { } from './types'; import { IdInternal } from '@matrixai/id'; import lexi from 'lexicographic-integer'; -import { bytes2BigInt, bufferSplit } from '../utils'; +import { bytes2BigInt } from '../utils'; import * as keysUtils from '../keys/utils'; // FIXME: @@ -135,22 +135,21 @@ function lastUpdatedBucketDbKey(lastUpdated: number, nodeId: NodeId): Buffer { ]); } +function lastUpdatedKey(lastUpdated: number): Buffer { + return Buffer.from(lexi.pack(lastUpdated, 'hex')); +} + /** * Parse the NodeGraph buckets sublevel key * The keys look like `!!` * It is assumed that the `!` is the sublevel prefix. */ -function parseBucketsDbKey(keyBuffer: Buffer): { +function parseBucketsDbKey(keyBufferArray: Array): { bucketIndex: NodeBucketIndex; bucketKey: string; nodeId: NodeId; } { - const [, bucketKeyBuffer, nodeIdBuffer] = bufferSplit( - keyBuffer, - prefixBuffer, - 3, - true, - ); + const [bucketKeyBuffer, nodeIdBuffer] = keyBufferArray; if (bucketKeyBuffer == null || nodeIdBuffer == null) { throw new TypeError('Buffer is not an NodeGraph buckets key'); } @@ -178,19 +177,14 @@ function parseBucketDbKey(keyBuffer: Buffer): NodeId { * The keys look like `!!-` * It is assumed that the `!` is the sublevel prefix. */ -function parseLastUpdatedBucketsDbKey(keyBuffer: Buffer): { +function parseLastUpdatedBucketsDbKey(keyBufferArray: Array): { bucketIndex: NodeBucketIndex; bucketKey: string; lastUpdated: number; nodeId: NodeId; } { - const [, bucketKeyBuffer, lastUpdatedBuffer] = bufferSplit( - keyBuffer, - prefixBuffer, - 3, - true, - ); - if (bucketKeyBuffer == null || lastUpdatedBuffer == null) { + const [bucketKeyBuffer, ...lastUpdatedBufferArray] = keyBufferArray; + if (bucketKeyBuffer == null || lastUpdatedBufferArray == null) { throw new TypeError('Buffer is not an NodeGraph index key'); } const bucketKey = bucketKeyBuffer.toString(); @@ -198,8 +192,9 @@ function parseLastUpdatedBucketsDbKey(keyBuffer: Buffer): { if (bucketIndex == null) { throw new TypeError('Buffer is not an NodeGraph index key'); } - const { lastUpdated, nodeId } = - parseLastUpdatedBucketDbKey(lastUpdatedBuffer); + const { lastUpdated, nodeId } = parseLastUpdatedBucketDbKey( + lastUpdatedBufferArray, + ); return { bucketIndex, bucketKey, @@ -213,16 +208,11 @@ function parseLastUpdatedBucketsDbKey(keyBuffer: Buffer): { * The keys look like `-` * It is assumed that the `!` is the sublevel prefix. */ -function parseLastUpdatedBucketDbKey(keyBuffer: Buffer): { +function parseLastUpdatedBucketDbKey(keyBufferArray: Array): { lastUpdated: number; nodeId: NodeId; } { - const [lastUpdatedBuffer, nodeIdBuffer] = bufferSplit( - keyBuffer, - Buffer.from('-'), - 2, - true, - ); + const [lastUpdatedBuffer, nodeIdBuffer] = keyBufferArray; if (lastUpdatedBuffer == null || nodeIdBuffer == null) { throw new TypeError('Buffer is not an NodeGraph index bucket key'); } @@ -332,6 +322,7 @@ export { bucketDbKey, lastUpdatedBucketsDbKey, lastUpdatedBucketDbKey, + lastUpdatedKey, parseBucketsDbKey, parseBucketDbKey, parseLastUpdatedBucketsDbKey, diff --git a/tests/agent/service/nodesChainDataGet.test.ts b/tests/agent/service/nodesChainDataGet.test.ts index 8bc388763..306d9cd06 100644 --- a/tests/agent/service/nodesChainDataGet.test.ts +++ b/tests/agent/service/nodesChainDataGet.test.ts @@ -55,6 +55,8 @@ describe('nodesClosestLocalNode', () => { const agentService = { nodesClosestLocalNodesGet: nodesClosestLocalNodesGet({ nodeGraph: pkAgent.nodeGraph, + db: pkAgent.db, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/agent/service/nodesClosestLocalNode.test.ts b/tests/agent/service/nodesClosestLocalNode.test.ts index 5453d8e5a..4e080443a 100644 --- a/tests/agent/service/nodesClosestLocalNode.test.ts +++ b/tests/agent/service/nodesClosestLocalNode.test.ts @@ -55,6 +55,8 @@ describe('nodesChainDataGet', () => { const agentService = { nodesChainDataGet: nodesChainDataGet({ sigchain: pkAgent.sigchain, + db: pkAgent.db, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/agent/service/nodesHolePunchMessage.test.ts b/tests/agent/service/nodesHolePunchMessage.test.ts index 4bef6d759..70615948c 100644 --- a/tests/agent/service/nodesHolePunchMessage.test.ts +++ b/tests/agent/service/nodesHolePunchMessage.test.ts @@ -55,6 +55,8 @@ describe('nodesHolePunchMessage', () => { keyManager: pkAgent.keyManager, nodeConnectionManager: pkAgent.nodeConnectionManager, nodeManager: pkAgent.nodeManager, + db: pkAgent.db, + logger, }), }; grpcServer = new GRPCServer({ logger }); diff --git a/tests/client/service/agentLockAll.test.ts b/tests/client/service/agentLockAll.test.ts index a024cc05c..fe56a0d7d 100644 --- a/tests/client/service/agentLockAll.test.ts +++ b/tests/client/service/agentLockAll.test.ts @@ -14,6 +14,7 @@ import { ClientServiceService } from '@/proto/js/polykey/v1/client_service_grpc_ import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as keysUtils from '@/keys/utils'; import * as clientUtils from '@/client/utils/utils'; +import { timerStart } from '@/utils/index'; import * as testUtils from '../../utils'; describe('agentLockall', () => { @@ -89,7 +90,7 @@ describe('agentLockall', () => { nodeId: keyManager.getNodeId(), host: '127.0.0.1' as Host, port: grpcServer.getPort(), - timeout: 5000, + timer: timerStart(5000), logger, }); }); diff --git a/tests/gestalts/GestaltGraph.test.ts b/tests/gestalts/GestaltGraph.test.ts index 0953a2b4a..e24a08e00 100644 --- a/tests/gestalts/GestaltGraph.test.ts +++ b/tests/gestalts/GestaltGraph.test.ts @@ -1248,8 +1248,8 @@ describe('GestaltGraph', () => { // its just that node 1 is eliminated nodePerms = await acl.getNodePerms(); expect(Object.keys(nodePerms)).toHaveLength(1); - expect(nodePerms[0]).not.toHaveProperty(nodeIdABC.toString()); - expect(nodePerms[0]).toHaveProperty(nodeIdDEE.toString()); + expect(nodePerms[0][nodeIdABC.toString()]).toBeUndefined(); + expect(nodePerms[0][nodeIdDEE.toString()]).toBeDefined(); await gestaltGraph.unsetNode(nodeIdDEE); nodePerms = await acl.getNodePerms(); expect(Object.keys(nodePerms)).toHaveLength(0); diff --git a/tests/network/Proxy.test.ts b/tests/network/Proxy.test.ts index 7e8b12d46..5bab753c4 100644 --- a/tests/network/Proxy.test.ts +++ b/tests/network/Proxy.test.ts @@ -3034,10 +3034,7 @@ describe(Proxy.name, () => { }; await utpSocketBind(0, localHost); const utpSocketPort = utpSocket.address().port; - await proxy.openConnectionReverse( - localHost, - utpSocketPort as Port, - ); + await proxy.openConnectionReverse(localHost, utpSocketPort as Port); const utpConn = utpSocket.connect(proxyPort, proxyHost); const tlsSocket = tls.connect( { @@ -3068,10 +3065,7 @@ describe(Proxy.name, () => { await clientReadyP; await clientSecureConnectP; await serverConnP; - await proxy.closeConnectionReverse( - localHost, - utpSocketPort as Port, - ); + await proxy.closeConnectionReverse(localHost, utpSocketPort as Port); expect(proxy.getConnectionReverseCount()).toBe(0); await clientCloseP; await serverConnEndP; diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index 725e6a684..dbd95397e 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -63,7 +63,7 @@ const mockedGenerateDeterministicKeyPair = jest.spyOn( 'generateDeterministicKeyPair', ); -describe('${NodeConnection.name} test', () => { +describe(`${NodeConnection.name} test`, () => { const logger = new Logger(`${NodeConnection.name} test`, LogLevel.WARN, [ new StreamHandler(), ]); diff --git a/tests/nodes/NodeConnectionManager.seednodes.test.ts b/tests/nodes/NodeConnectionManager.seednodes.test.ts index b63a4ae54..e6d91f399 100644 --- a/tests/nodes/NodeConnectionManager.seednodes.test.ts +++ b/tests/nodes/NodeConnectionManager.seednodes.test.ts @@ -424,84 +424,88 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { await queue?.stop(); } }); - test('should expand the network when nodes enter', async () => { - // Using a single seed node we need to check that each entering node adds itself to the seed node. - // Also need to check that the new nodes can be seen in the network. - let node1: PolykeyAgent | undefined; - let node2: PolykeyAgent | undefined; - const seedNodes: SeedNodes = {}; - seedNodes[nodesUtils.encodeNodeId(remoteNodeId1)] = { - host: remoteNode1.proxy.getProxyHost(), - port: remoteNode1.proxy.getProxyPort(), - }; - seedNodes[nodesUtils.encodeNodeId(remoteNodeId2)] = { - host: remoteNode2.proxy.getProxyHost(), - port: remoteNode2.proxy.getProxyPort(), - }; - try { - logger.setLevel(LogLevel.WARN); - node1 = await PolykeyAgent.createPolykeyAgent({ - nodePath: path.join(dataDir, 'node1'), - password: 'password', - networkConfig: { - proxyHost: localHost, - agentHost: localHost, - clientHost: localHost, - forwardHost: localHost, - }, - seedNodes, - logger, - }); - node2 = await PolykeyAgent.createPolykeyAgent({ - nodePath: path.join(dataDir, 'node2'), - password: 'password', - networkConfig: { - proxyHost: localHost, - agentHost: localHost, - clientHost: localHost, - forwardHost: localHost, - }, - seedNodes, - logger, - }); + test( + 'should expand the network when nodes enter', + async () => { + // Using a single seed node we need to check that each entering node adds itself to the seed node. + // Also need to check that the new nodes can be seen in the network. + let node1: PolykeyAgent | undefined; + let node2: PolykeyAgent | undefined; + const seedNodes: SeedNodes = {}; + seedNodes[nodesUtils.encodeNodeId(remoteNodeId1)] = { + host: remoteNode1.proxy.getProxyHost(), + port: remoteNode1.proxy.getProxyPort(), + }; + seedNodes[nodesUtils.encodeNodeId(remoteNodeId2)] = { + host: remoteNode2.proxy.getProxyHost(), + port: remoteNode2.proxy.getProxyPort(), + }; + try { + logger.setLevel(LogLevel.WARN); + node1 = await PolykeyAgent.createPolykeyAgent({ + nodePath: path.join(dataDir, 'node1'), + password: 'password', + networkConfig: { + proxyHost: localHost, + agentHost: localHost, + clientHost: localHost, + forwardHost: localHost, + }, + seedNodes, + logger, + }); + node2 = await PolykeyAgent.createPolykeyAgent({ + nodePath: path.join(dataDir, 'node2'), + password: 'password', + networkConfig: { + proxyHost: localHost, + agentHost: localHost, + clientHost: localHost, + forwardHost: localHost, + }, + seedNodes, + logger, + }); - await node1.queue.drained(); - await node1.nodeManager.refreshBucketQueueDrained(); - await node2.queue.drained(); - await node2.nodeManager.refreshBucketQueueDrained(); + await node1.queue.drained(); + await node1.nodeManager.refreshBucketQueueDrained(); + await node2.queue.drained(); + await node2.nodeManager.refreshBucketQueueDrained(); - const getAllNodes = async (node: PolykeyAgent) => { - const nodes: Array = []; - for await (const [nodeId] of node.nodeGraph.getNodes()) { - nodes.push(nodesUtils.encodeNodeId(nodeId)); - } - return nodes; - }; - const rNode1Nodes = await getAllNodes(remoteNode1); - const rNode2Nodes = await getAllNodes(remoteNode2); - const node1Nodes = await getAllNodes(node1); - const node2Nodes = await getAllNodes(node2); + const getAllNodes = async (node: PolykeyAgent) => { + const nodes: Array = []; + for await (const [nodeId] of node.nodeGraph.getNodes()) { + nodes.push(nodesUtils.encodeNodeId(nodeId)); + } + return nodes; + }; + const rNode1Nodes = await getAllNodes(remoteNode1); + const rNode2Nodes = await getAllNodes(remoteNode2); + const node1Nodes = await getAllNodes(node1); + const node2Nodes = await getAllNodes(node2); - const nodeIdR1 = nodesUtils.encodeNodeId(remoteNodeId1); - const nodeIdR2 = nodesUtils.encodeNodeId(remoteNodeId2); - const nodeId1 = nodesUtils.encodeNodeId(node1.keyManager.getNodeId()); - const nodeId2 = nodesUtils.encodeNodeId(node2.keyManager.getNodeId()); - expect(rNode1Nodes).toContain(nodeId1); - expect(rNode1Nodes).toContain(nodeId2); - expect(rNode2Nodes).toContain(nodeId1); - expect(rNode2Nodes).toContain(nodeId2); - expect(node1Nodes).toContain(nodeIdR1); - expect(node1Nodes).toContain(nodeIdR2); - expect(node1Nodes).toContain(nodeId2); - expect(node2Nodes).toContain(nodeIdR1); - expect(node2Nodes).toContain(nodeIdR2); - expect(node2Nodes).toContain(nodeId1); - } finally { - logger.setLevel(LogLevel.WARN); - await node1?.stop(); - await node1?.destroy(); - await node2?.stop(); - await node2?.destroy(); - } - }); + const nodeIdR1 = nodesUtils.encodeNodeId(remoteNodeId1); + const nodeIdR2 = nodesUtils.encodeNodeId(remoteNodeId2); + const nodeId1 = nodesUtils.encodeNodeId(node1.keyManager.getNodeId()); + const nodeId2 = nodesUtils.encodeNodeId(node2.keyManager.getNodeId()); + expect(rNode1Nodes).toContain(nodeId1); + expect(rNode1Nodes).toContain(nodeId2); + expect(rNode2Nodes).toContain(nodeId1); + expect(rNode2Nodes).toContain(nodeId2); + expect(node1Nodes).toContain(nodeIdR1); + expect(node1Nodes).toContain(nodeIdR2); + expect(node1Nodes).toContain(nodeId2); + expect(node2Nodes).toContain(nodeIdR1); + expect(node2Nodes).toContain(nodeIdR2); + expect(node2Nodes).toContain(nodeId1); + } finally { + logger.setLevel(LogLevel.WARN); + await node1?.stop(); + await node1?.destroy(); + await node2?.stop(); + await node2?.destroy(); + } + }, + global.defaultTimeout * 2, + ); }); diff --git a/tests/nodes/utils.test.ts b/tests/nodes/utils.test.ts index c87a82f26..0d962f963 100644 --- a/tests/nodes/utils.test.ts +++ b/tests/nodes/utils.test.ts @@ -94,7 +94,7 @@ describe('nodes/utils', () => { } }); test('parse NodeGraph buckets db key', async () => { - const bucketsDb = await db.level('buckets'); + const bucketsDbPath = ['buckets']; const data: Array<{ bucketIndex: number; bucketKey: string; @@ -111,16 +111,19 @@ describe('nodes/utils', () => { nodeId, key: Buffer.concat([Buffer.from(bucketKey), nodeId]), }); - const bucketDomain = ['buckets', bucketKey]; - await db.put(bucketDomain, nodesUtils.bucketDbKey(nodeId), null); + await db.put( + ['buckets', bucketKey, nodesUtils.bucketDbKey(nodeId)], + null, + ); } // LevelDB will store keys in lexicographic order // Use the key property as a concatenated buffer of the bucket key and node ID data.sort((a, b) => Buffer.compare(a.key, b.key)); let i = 0; - for await (const key of bucketsDb.createKeyStream()) { + + for await (const [key] of db.iterator({}, bucketsDbPath)) { const { bucketIndex, bucketKey, nodeId } = nodesUtils.parseBucketsDbKey( - key as Buffer, + key as Array, ); expect(bucketIndex).toBe(data[i].bucketIndex); expect(bucketKey).toBe(data[i].bucketKey); @@ -129,7 +132,7 @@ describe('nodes/utils', () => { } }); test('parse NodeGraph lastUpdated buckets db key', async () => { - const lastUpdatedDb = await db.level('lastUpdated'); + const lastUpdatedDbPath = ['lastUpdated']; const data: Array<{ bucketIndex: number; bucketKey: string; @@ -142,28 +145,25 @@ describe('nodes/utils', () => { const bucketKey = lexi.pack(bucketIndex, 'hex'); const lastUpdated = utils.getUnixtime(); const nodeId = testNodesUtils.generateRandomNodeId(); - const lastUpdatedKey = nodesUtils.lastUpdatedBucketDbKey( - lastUpdated, - nodeId, - ); + const nodeIdKey = nodesUtils.bucketDbKey(nodeId); + const lastUpdatedKey = nodesUtils.lastUpdatedKey(lastUpdated); data.push({ bucketIndex, bucketKey, lastUpdated, nodeId, - key: Buffer.concat([Buffer.from(bucketKey), lastUpdatedKey]), + key: Buffer.concat([Buffer.from(bucketKey), lastUpdatedKey, nodeIdKey]), }); - const lastUpdatedDomain = ['lastUpdated', bucketKey]; - await db.put(lastUpdatedDomain, lastUpdatedKey, null); + await db.put(['lastUpdated', bucketKey, lastUpdatedKey, nodeIdKey], null); } // LevelDB will store keys in lexicographic order // Use the key property as a concatenated buffer of // the bucket key and last updated and node ID data.sort((a, b) => Buffer.compare(a.key, b.key)); let i = 0; - for await (const key of lastUpdatedDb.createKeyStream()) { + for await (const [key] of db.iterator({}, lastUpdatedDbPath)) { const { bucketIndex, bucketKey, lastUpdated, nodeId } = - nodesUtils.parseLastUpdatedBucketsDbKey(key as Buffer); + nodesUtils.parseLastUpdatedBucketsDbKey(key as Array); expect(bucketIndex).toBe(data[i].bucketIndex); expect(bucketKey).toBe(data[i].bucketKey); expect(lastUpdated).toBe(data[i].lastUpdated); diff --git a/tests/utils.ts b/tests/utils.ts index 84c67c90e..3ac9a7499 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -14,7 +14,6 @@ import * as keysUtils from '@/keys/utils'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as grpcErrors from '@/grpc/errors'; import { sleep } from '@/utils'; -import * as errors from '@/errors'; import config from '@/config'; /** diff --git a/tests/vaults/VaultInternal.test.ts b/tests/vaults/VaultInternal.test.ts index ab817a538..d95ae1c2c 100644 --- a/tests/vaults/VaultInternal.test.ts +++ b/tests/vaults/VaultInternal.test.ts @@ -678,60 +678,64 @@ describe('VaultInternal', () => { expect(log).toHaveLength(2); expect(log[0].commitId).toStrictEqual(commit); }); - test('garbage collection', async () => { - await vault.writeF(async (efs) => { - await efs.writeFile(secret1.name, secret1.content); - }); - await vault.writeF(async (efs) => { - await efs.writeFile(secret2.name, secret2.content); - }); - await vault.writeF(async (efs) => { - await efs.writeFile(secret3.name, secret3.content); - }); - // @ts-ignore: kidnap efs - const vaultEfs = vault.efs; - // @ts-ignore: kidnap efs - const vaultEfsData = vault.efsVault; - const quickCommit = async (ref: string, secret: string) => { - await vaultEfsData.writeFile(secret, secret); - await git.add({ - fs: vaultEfs, - dir: vault.vaultDataDir, - gitdir: vault.vaultGitDir, - filepath: secret, + test( + 'garbage collection', + async () => { + await vault.writeF(async (efs) => { + await efs.writeFile(secret1.name, secret1.content); }); - return await git.commit({ - fs: vaultEfs, - dir: vault.vaultDataDir, - gitdir: vault.vaultGitDir, - author: { - name: 'test', - email: 'test', - }, - message: 'test', - ref: ref, + await vault.writeF(async (efs) => { + await efs.writeFile(secret2.name, secret2.content); }); - }; - const log = await vault.log(); - let num = 5; - const refs: string[] = []; - for (const logElement of log) { - refs.push(await quickCommit(logElement.commitId, `secret-${num++}`)); - } - // @ts-ignore - await vault.garbageCollectGitObjects(); - - for (const ref of refs) { - await expect( - git.checkout({ + await vault.writeF(async (efs) => { + await efs.writeFile(secret3.name, secret3.content); + }); + // @ts-ignore: kidnap efs + const vaultEfs = vault.efs; + // @ts-ignore: kidnap efs + const vaultEfsData = vault.efsVault; + const quickCommit = async (ref: string, secret: string) => { + await vaultEfsData.writeFile(secret, secret); + await git.add({ fs: vaultEfs, dir: vault.vaultDataDir, gitdir: vault.vaultGitDir, - ref, - }), - ).rejects.toThrow(git.Errors.CommitNotFetchedError); - } - }); + filepath: secret, + }); + return await git.commit({ + fs: vaultEfs, + dir: vault.vaultDataDir, + gitdir: vault.vaultGitDir, + author: { + name: 'test', + email: 'test', + }, + message: 'test', + ref: ref, + }); + }; + const log = await vault.log(); + let num = 5; + const refs: string[] = []; + for (const logElement of log) { + refs.push(await quickCommit(logElement.commitId, `secret-${num++}`)); + } + // @ts-ignore + await vault.garbageCollectGitObjects(); + + for (const ref of refs) { + await expect( + git.checkout({ + fs: vaultEfs, + dir: vault.vaultDataDir, + gitdir: vault.vaultGitDir, + ref, + }), + ).rejects.toThrow(git.Errors.CommitNotFetchedError); + } + }, + global.defaultTimeout * 2, + ); // Locking tests const waitDelay = 200; test('writeF respects read and write locking', async () => { diff --git a/tests/vaults/VaultManager.test.ts b/tests/vaults/VaultManager.test.ts index 4cf5d50f9..e57495cb9 100644 --- a/tests/vaults/VaultManager.test.ts +++ b/tests/vaults/VaultManager.test.ts @@ -185,7 +185,7 @@ describe('VaultManager', () => { await vaultManager?.destroy(); } }, - global.defaultTimeout * 2, + global.defaultTimeout * 4, ); test('can rename a vault', async () => { const vaultManager = await VaultManager.createVaultManager({ @@ -278,49 +278,53 @@ describe('VaultManager', () => { await vaultManager?.destroy(); } }); - test('able to read and load existing metadata', async () => { - const vaultManager = await VaultManager.createVaultManager({ - vaultsPath, - keyManager: dummyKeyManager, - gestaltGraph: {} as GestaltGraph, - nodeConnectionManager: {} as NodeConnectionManager, - acl: {} as ACL, - notificationsManager: {} as NotificationsManager, - db, - logger: logger.getChild(VaultManager.name), - }); - try { - const vaultNames = [ - 'Vault1', - 'Vault2', - 'Vault3', - 'Vault4', - 'Vault5', - 'Vault6', - 'Vault7', - 'Vault8', - 'Vault9', - 'Vault10', - ]; - for (const vaultName of vaultNames) { - await vaultManager.createVault(vaultName as VaultName); - } - const vaults = await vaultManager.listVaults(); - const vaultId = vaults.get('Vault1' as VaultName) as VaultId; - expect(vaultId).not.toBeUndefined(); - await vaultManager.stop(); - await vaultManager.start(); - const restartedVaultNames: Array = []; - const vaultList = await vaultManager.listVaults(); - vaultList.forEach((_, vaultName) => { - restartedVaultNames.push(vaultName); + test( + 'able to read and load existing metadata', + async () => { + const vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + keyManager: dummyKeyManager, + gestaltGraph: {} as GestaltGraph, + nodeConnectionManager: {} as NodeConnectionManager, + acl: {} as ACL, + notificationsManager: {} as NotificationsManager, + db, + logger: logger.getChild(VaultManager.name), }); - expect(restartedVaultNames.sort()).toEqual(vaultNames.sort()); - } finally { - await vaultManager?.stop(); - await vaultManager?.destroy(); - } - }); + try { + const vaultNames = [ + 'Vault1', + 'Vault2', + 'Vault3', + 'Vault4', + 'Vault5', + 'Vault6', + 'Vault7', + 'Vault8', + 'Vault9', + 'Vault10', + ]; + for (const vaultName of vaultNames) { + await vaultManager.createVault(vaultName as VaultName); + } + const vaults = await vaultManager.listVaults(); + const vaultId = vaults.get('Vault1' as VaultName) as VaultId; + expect(vaultId).not.toBeUndefined(); + await vaultManager.stop(); + await vaultManager.start(); + const restartedVaultNames: Array = []; + const vaultList = await vaultManager.listVaults(); + vaultList.forEach((_, vaultName) => { + restartedVaultNames.push(vaultName); + }); + expect(restartedVaultNames.sort()).toEqual(vaultNames.sort()); + } finally { + await vaultManager?.stop(); + await vaultManager?.destroy(); + } + }, + global.defaultTimeout * 2, + ); test('cannot concurrently create vaults with the same name', async () => { const vaultManager = await VaultManager.createVaultManager({ vaultsPath, @@ -884,91 +888,95 @@ describe('VaultManager', () => { await vaultManager?.destroy(); } }); - test('can pull a cloned vault', async () => { - const vaultManager = await VaultManager.createVaultManager({ - vaultsPath, - keyManager: dummyKeyManager, - gestaltGraph: {} as GestaltGraph, - nodeConnectionManager, - acl: {} as ACL, - notificationsManager: {} as NotificationsManager, - db, - logger: logger.getChild(VaultManager.name), - }); - try { - // Creating some state at the remote - await remoteKeynode1.vaultManager.withVaults( - [remoteVaultId], - async (vault) => { - await vault.writeF(async (efs) => { - await efs.writeFile('secret-1', 'secret1'); - }); - }, - ); - - // Setting permissions - await remoteKeynode1.gestaltGraph.setNode({ - id: localNodeIdEncoded, - chain: {}, + test( + 'can pull a cloned vault', + async () => { + const vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + keyManager: dummyKeyManager, + gestaltGraph: {} as GestaltGraph, + nodeConnectionManager, + acl: {} as ACL, + notificationsManager: {} as NotificationsManager, + db, + logger: logger.getChild(VaultManager.name), }); - await remoteKeynode1.gestaltGraph.setGestaltActionByNode( - localNodeId, - 'scan', - ); - await remoteKeynode1.acl.setVaultAction( - remoteVaultId, - localNodeId, - 'clone', - ); - await remoteKeynode1.acl.setVaultAction( - remoteVaultId, - localNodeId, - 'pull', - ); + try { + // Creating some state at the remote + await remoteKeynode1.vaultManager.withVaults( + [remoteVaultId], + async (vault) => { + await vault.writeF(async (efs) => { + await efs.writeFile('secret-1', 'secret1'); + }); + }, + ); - await vaultManager.cloneVault(remoteKeynode1Id, vaultName); - const vaultId = await vaultManager.getVaultId(vaultName); - if (vaultId === undefined) fail('VaultId is not found.'); - await vaultManager.withVaults([vaultId], async (vaultClone) => { - return await vaultClone.readF(async (efs) => { - const file = await efs.readFile('secret-1', { encoding: 'utf8' }); - const secretsList = await efs.readdir('.'); - expect(file).toBe('secret1'); - expect(secretsList).toContain('secret-1'); - expect(secretsList).not.toContain('secret-2'); + // Setting permissions + await remoteKeynode1.gestaltGraph.setNode({ + id: localNodeIdEncoded, + chain: {}, }); - }); + await remoteKeynode1.gestaltGraph.setGestaltActionByNode( + localNodeId, + 'scan', + ); + await remoteKeynode1.acl.setVaultAction( + remoteVaultId, + localNodeId, + 'clone', + ); + await remoteKeynode1.acl.setVaultAction( + remoteVaultId, + localNodeId, + 'pull', + ); - // Creating new history - await remoteKeynode1.vaultManager.withVaults( - [remoteVaultId], - async (vault) => { - await vault.writeF(async (efs) => { - await efs.writeFile('secret-2', 'secret2'); + await vaultManager.cloneVault(remoteKeynode1Id, vaultName); + const vaultId = await vaultManager.getVaultId(vaultName); + if (vaultId === undefined) fail('VaultId is not found.'); + await vaultManager.withVaults([vaultId], async (vaultClone) => { + return await vaultClone.readF(async (efs) => { + const file = await efs.readFile('secret-1', { encoding: 'utf8' }); + const secretsList = await efs.readdir('.'); + expect(file).toBe('secret1'); + expect(secretsList).toContain('secret-1'); + expect(secretsList).not.toContain('secret-2'); }); - }, - ); + }); - // Pulling vault - await vaultManager.pullVault({ - vaultId: vaultId, - }); + // Creating new history + await remoteKeynode1.vaultManager.withVaults( + [remoteVaultId], + async (vault) => { + await vault.writeF(async (efs) => { + await efs.writeFile('secret-2', 'secret2'); + }); + }, + ); - // Should have new data - await vaultManager.withVaults([vaultId], async (vaultClone) => { - return await vaultClone.readF(async (efs) => { - const file = await efs.readFile('secret-1', { encoding: 'utf8' }); - const secretsList = await efs.readdir('.'); - expect(file).toBe('secret1'); - expect(secretsList).toContain('secret-1'); - expect(secretsList).toContain('secret-2'); + // Pulling vault + await vaultManager.pullVault({ + vaultId: vaultId, }); - }); - } finally { - await vaultManager?.stop(); - await vaultManager?.destroy(); - } - }); + + // Should have new data + await vaultManager.withVaults([vaultId], async (vaultClone) => { + return await vaultClone.readF(async (efs) => { + const file = await efs.readFile('secret-1', { encoding: 'utf8' }); + const secretsList = await efs.readdir('.'); + expect(file).toBe('secret1'); + expect(secretsList).toContain('secret-1'); + expect(secretsList).toContain('secret-2'); + }); + }); + } finally { + await vaultManager?.stop(); + await vaultManager?.destroy(); + } + }, + global.defaultTimeout * 2, + ); test( 'manage pulling from different remotes', async () => { @@ -1105,78 +1113,82 @@ describe('VaultManager', () => { }, global.failedConnectionTimeout, ); - test('able to recover metadata after complex operations', async () => { - const vaultManager = await VaultManager.createVaultManager({ - vaultsPath, - keyManager: dummyKeyManager, - gestaltGraph: {} as GestaltGraph, - nodeConnectionManager, - acl: {} as ACL, - notificationsManager: {} as NotificationsManager, - db, - logger: logger.getChild(VaultManager.name), - }); - try { - const vaultNames = ['Vault1', 'Vault2', 'Vault3', 'Vault4', 'Vault5']; - const alteredVaultNames = [ - 'Vault1', - 'Vault2', - 'Vault3', - 'Vault6', - 'Vault10', - ]; - for (const vaultName of vaultNames) { - await vaultManager.createVault(vaultName as VaultName); - } - const v5 = await vaultManager.getVaultId('Vault5' as VaultName); - expect(v5).not.toBeUndefined(); - await vaultManager.destroyVault(v5!); - const v4 = await vaultManager.getVaultId('Vault4' as VaultName); - expect(v4).toBeTruthy(); - await vaultManager.renameVault(v4!, 'Vault10' as VaultName); - const v6 = await vaultManager.createVault('Vault6' as VaultName); - - await vaultManager.withVaults([v6], async (vault6) => { - await vault6.writeF(async (efs) => { - await efs.writeFile('reloaded', 'reload'); - }); + test( + 'able to recover metadata after complex operations', + async () => { + const vaultManager = await VaultManager.createVaultManager({ + vaultsPath, + keyManager: dummyKeyManager, + gestaltGraph: {} as GestaltGraph, + nodeConnectionManager, + acl: {} as ACL, + notificationsManager: {} as NotificationsManager, + db, + logger: logger.getChild(VaultManager.name), }); - - const vn: Array = []; - (await vaultManager.listVaults()).forEach((_, vaultName) => - vn.push(vaultName), - ); - expect(vn.sort()).toEqual(alteredVaultNames.sort()); - await vaultManager.stop(); - await vaultManager.start(); - await vaultManager.createVault('Vault7' as VaultName); - - const v10 = await vaultManager.getVaultId('Vault10' as VaultName); - expect(v10).not.toBeUndefined(); - alteredVaultNames.push('Vault7'); - expect((await vaultManager.listVaults()).size).toEqual( - alteredVaultNames.length, - ); - const vnAltered: Array = []; - (await vaultManager.listVaults()).forEach((_, vaultName) => - vnAltered.push(vaultName), - ); - expect(vnAltered.sort()).toEqual(alteredVaultNames.sort()); - const file = await vaultManager.withVaults( - [v6], - async (reloadedVault) => { - return await reloadedVault.readF(async (efs) => { - return await efs.readFile('reloaded', { encoding: 'utf8' }); + try { + const vaultNames = ['Vault1', 'Vault2', 'Vault3', 'Vault4', 'Vault5']; + const alteredVaultNames = [ + 'Vault1', + 'Vault2', + 'Vault3', + 'Vault6', + 'Vault10', + ]; + for (const vaultName of vaultNames) { + await vaultManager.createVault(vaultName as VaultName); + } + const v5 = await vaultManager.getVaultId('Vault5' as VaultName); + expect(v5).not.toBeUndefined(); + await vaultManager.destroyVault(v5!); + const v4 = await vaultManager.getVaultId('Vault4' as VaultName); + expect(v4).toBeTruthy(); + await vaultManager.renameVault(v4!, 'Vault10' as VaultName); + const v6 = await vaultManager.createVault('Vault6' as VaultName); + + await vaultManager.withVaults([v6], async (vault6) => { + await vault6.writeF(async (efs) => { + await efs.writeFile('reloaded', 'reload'); }); - }, - ); + }); - expect(file).toBe('reload'); - } finally { - await vaultManager?.stop(); - await vaultManager?.destroy(); - } - }); + const vn: Array = []; + (await vaultManager.listVaults()).forEach((_, vaultName) => + vn.push(vaultName), + ); + expect(vn.sort()).toEqual(alteredVaultNames.sort()); + await vaultManager.stop(); + await vaultManager.start(); + await vaultManager.createVault('Vault7' as VaultName); + + const v10 = await vaultManager.getVaultId('Vault10' as VaultName); + expect(v10).not.toBeUndefined(); + alteredVaultNames.push('Vault7'); + expect((await vaultManager.listVaults()).size).toEqual( + alteredVaultNames.length, + ); + const vnAltered: Array = []; + (await vaultManager.listVaults()).forEach((_, vaultName) => + vnAltered.push(vaultName), + ); + expect(vnAltered.sort()).toEqual(alteredVaultNames.sort()); + const file = await vaultManager.withVaults( + [v6], + async (reloadedVault) => { + return await reloadedVault.readF(async (efs) => { + return await efs.readFile('reloaded', { encoding: 'utf8' }); + }); + }, + ); + + expect(file).toBe('reload'); + } finally { + await vaultManager?.stop(); + await vaultManager?.destroy(); + } + }, + global.defaultTimeout * 2, + ); test('throw when trying to commit to a cloned vault', async () => { const vaultManager = await VaultManager.createVaultManager({ vaultsPath, @@ -1337,7 +1349,7 @@ describe('VaultManager', () => { }); await sleep(200); expect(pullVaultMock).not.toHaveBeenCalled(); - releaseWrite(); + await releaseWrite(); await pullP; expect(pullVaultMock).toHaveBeenCalled(); pullVaultMock.mockClear(); @@ -1363,16 +1375,16 @@ describe('VaultManager', () => { }); await sleep(200); expect(gitPullMock).not.toHaveBeenCalled(); - releaseVaultWrite(); - await pullP2; - expect(gitPullMock).toHaveBeenCalled(); - } finally { - pullVaultMock.mockRestore(); - gitPullMock.mockRestore(); - await vaultManager?.stop(); - await vaultManager?.destroy(); - } - }, + await releaseVaultWrite(); + await pullP2; + expect(gitPullMock).toHaveBeenCalled(); + } finally { + pullVaultMock.mockRestore(); + gitPullMock.mockRestore(); + await vaultManager?.stop(); + await vaultManager?.destroy(); + } + }, global.failedConnectionTimeout, ); }); From 2a0498d05a1a28d07ba470522db0cdf38d674f23 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 7 Jun 2022 11:23:00 +1000 Subject: [PATCH 105/137] syntax: style fixes Exports moved to end of the file as part of the `export {}` block Cleaned up TODOs and FIXMEs Fixed index and other incorrect imports Type fixes in utils --- src/client/service/nodesGetAll.ts | 15 +++++++-------- src/nodes/NodeConnectionManager.ts | 7 +------ src/nodes/NodeGraph.ts | 2 -- src/nodes/NodeManager.ts | 6 +++--- src/nodes/Queue.ts | 6 +++--- src/nodes/types.ts | 17 ----------------- src/nodes/utils.ts | 15 +++++++-------- src/utils/utils.ts | 5 +++-- src/vaults/VaultInternal.ts | 3 ++- 9 files changed, 26 insertions(+), 50 deletions(-) diff --git a/src/client/service/nodesGetAll.ts b/src/client/service/nodesGetAll.ts index bc01e84e0..8c021a248 100644 --- a/src/client/service/nodesGetAll.ts +++ b/src/client/service/nodesGetAll.ts @@ -1,8 +1,9 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { KeyManager } from '../../keys'; +import type KeyManager from '../../keys/KeyManager'; import type { NodeId } from '../../nodes/types'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import type NodeGraph from '../../nodes/NodeGraph'; import { IdInternal } from '@matrixai/id'; import { utils as nodesUtils } from '../../nodes'; import { utils as grpcUtils } from '../../grpc'; @@ -12,11 +13,11 @@ import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; * Retrieves all nodes from all buckets in the NodeGraph. */ function nodesGetAll({ - // NodeGraph, + nodeGraph, keyManager, authenticate, }: { - // NodeGraph: NodeGraph; + nodeGraph: NodeGraph; keyManager: KeyManager; authenticate: Authenticate; }) { @@ -28,10 +29,8 @@ function nodesGetAll({ const response = new nodesPB.NodeBuckets(); const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - // FIXME: - // const buckets = await nodeGraph.getAllBuckets(); - const buckets: any = []; - for (const b of buckets) { + const buckets = nodeGraph.getBuckets(); + for await (const b of buckets) { let index; for (const id of Object.keys(b)) { const encodedId = nodesUtils.encodeNodeId( @@ -48,7 +47,7 @@ function nodesGetAll({ ); } // Need to either add node to an existing bucket, or create a new - // bucket (if doesn't exist) + // bucket (if it doesn't exist) const bucket = response.getBucketsMap().get(index); if (bucket) { bucket.getNodeTableMap().set(encodedId, address); diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 484757f81..8efe369e9 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -112,7 +112,7 @@ class NodeConnectionManager { this.nodeManager = nodeManager; for (const nodeIdEncoded in this.seedNodes) { const nodeId = nodesUtils.decodeNodeId(nodeIdEncoded)!; - await this.nodeGraph.setNode(nodeId, this.seedNodes[nodeIdEncoded]); // FIXME: also fine implicit transactions + await this.nodeGraph.setNode(nodeId, this.seedNodes[nodeIdEncoded]); } this.logger.info(`Started ${this.constructor.name}`); } @@ -264,7 +264,6 @@ class NodeConnectionManager { )}`, ); // Creating the connection and set in map - // FIXME: this is fine, just use the implicit tran. fix this when adding optional transactions const targetAddress = await this.findNode(targetNodeId); if (targetAddress == null) { throw new nodesErrors.ErrorNodeGraphNodeIdNotFound(); @@ -411,7 +410,6 @@ class NodeConnectionManager { return address; } - // FIXME: getClosestNodes was moved to NodeGraph? that needs to be updated. /** * Attempts to locate a target node in the network (using Kademlia). * Adds all discovered, active nodes to the current node's database (up to k @@ -438,7 +436,6 @@ class NodeConnectionManager { // Let foundTarget: boolean = false; let foundAddress: NodeAddress | undefined = undefined; // Get the closest alpha nodes to the target node (set as shortlist) - // FIXME: no tran const shortlist = await this.nodeGraph.getClosestNodes( targetNodeId, this.initialClosestNodes, @@ -473,7 +470,6 @@ class NodeConnectionManager { try { // Add the node to the database so that we can find its address in // call to getConnectionToNode - // FIXME: no tran await this.nodeGraph.setNode(nextNodeId, nextNodeAddress.address); await this.getConnection(nextNodeId, timer); } catch (e) { @@ -496,7 +492,6 @@ class NodeConnectionManager { continue; } if (nodeId.equals(targetNodeId)) { - // FIXME: no tran await this.nodeGraph.setNode(nodeId, nodeData.address); foundAddress = nodeData.address; // We have found the target node, so we can stop trying to look for it diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index a5b8da332..c9ebaf0f3 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -679,8 +679,6 @@ class NodeGraph { * current node has less than k nodes in all of its buckets, in which case it * returns all nodes it has knowledge of) */ - // FIXME: this is still operating on assumptions from old code. - // I can't get the gt/lt to work on the iterator. @ready(new nodesErrors.ErrorNodeGraphNotRunning()) public async getClosestNodes( nodeId: NodeId, diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 23832dbb7..95251648c 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -14,7 +14,7 @@ import type { } from '../nodes/types'; import type { ClaimEncoded } from '../claims/types'; import type { Timer } from '../types'; -import type { PromiseType } from '../utils/utils'; +import type { PromiseDeconstructed } from '../utils/utils'; import type { AbortSignal } from 'node-abort-controller'; import Logger from '@matrixai/logger'; import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; @@ -47,8 +47,8 @@ class NodeManager { protected refreshBucketQueue: Set = new Set(); protected refreshBucketQueueRunning: boolean = false; protected refreshBucketQueueRunner: Promise; - protected refreshBucketQueuePlug_: PromiseType = promise(); - protected refreshBucketQueueDrained_: PromiseType = promise(); + protected refreshBucketQueuePlug_: PromiseDeconstructed = promise(); + protected refreshBucketQueueDrained_: PromiseDeconstructed = promise(); protected refreshBucketQueueAbortController: AbortController; constructor({ diff --git a/src/nodes/Queue.ts b/src/nodes/Queue.ts index 0f9c1485e..602efd5ae 100644 --- a/src/nodes/Queue.ts +++ b/src/nodes/Queue.ts @@ -1,4 +1,4 @@ -import type { PromiseType } from '../utils'; +import type { PromiseDeconstructed } from '../utils'; import Logger from '@matrixai/logger'; import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; import * as nodesErrors from './errors'; @@ -11,8 +11,8 @@ class Queue { protected end: boolean = false; protected queue: Array<() => Promise> = []; protected runner: Promise; - protected plug_: PromiseType = promise(); - protected drained_: PromiseType = promise(); + protected plug_: PromiseDeconstructed = promise(); + protected drained_: PromiseDeconstructed = promise(); constructor({ logger }: { logger?: Logger }) { this.logger = logger ?? new Logger(this.constructor.name); diff --git a/src/nodes/types.ts b/src/nodes/types.ts index 8e173b4f2..37775be9d 100644 --- a/src/nodes/types.ts +++ b/src/nodes/types.ts @@ -33,8 +33,6 @@ type NodeBucketMeta = { count: number; }; -// Type NodeBucketMetaProps = NonFunctionProperties; - // Just make the bucket entries also // bucketIndex anot as a key // but as the domain @@ -45,20 +43,8 @@ type NodeData = { lastUpdated: number; }; -// Type NodeBucketEntry = { -// address: NodeAddress; -// lastUpdated: Date; -// }; - type SeedNodes = Record; -// FIXME: should have a proper name -type NodeEntry = { - id: NodeId; - address: NodeAddress; - distance: BigInt; -}; - /** * A claim made on a node. That is, can be either: * - a claim from a node -> node @@ -106,9 +92,6 @@ export type { NodeBucketMeta, NodeBucket, NodeData, - NodeEntry, - // NodeBucketEntry, - NodeGraphOp, NodeGraphSpace, }; diff --git a/src/nodes/utils.ts b/src/nodes/utils.ts index 449fc407b..0078ef784 100644 --- a/src/nodes/utils.ts +++ b/src/nodes/utils.ts @@ -6,12 +6,11 @@ import type { } from './types'; import { IdInternal } from '@matrixai/id'; import lexi from 'lexicographic-integer'; +import { utils as dbUtils } from '@matrixai/db'; import { bytes2BigInt } from '../utils'; import * as keysUtils from '../keys/utils'; -// FIXME: -const prefixBuffer = Buffer.from([33]); -// Const prefixBuffer = Buffer.from(dbUtils.prefix); +const sepBuffer = dbUtils.sep; /** * Encodes the NodeId as a `base32hex` string @@ -94,9 +93,9 @@ function bucketKey(bucketIndex: NodeBucketIndex): string { */ function bucketsDbKey(bucketIndex: NodeBucketIndex, nodeId: NodeId): Buffer { return Buffer.concat([ - prefixBuffer, + sepBuffer, Buffer.from(bucketKey(bucketIndex)), - prefixBuffer, + sepBuffer, bucketDbKey(nodeId), ]); } @@ -117,9 +116,9 @@ function lastUpdatedBucketsDbKey( nodeId: NodeId, ): Buffer { return Buffer.concat([ - prefixBuffer, + sepBuffer, Buffer.from(bucketKey(bucketIndex)), - prefixBuffer, + sepBuffer, lastUpdatedBucketDbKey(lastUpdated, nodeId), ]); } @@ -313,7 +312,7 @@ function generateRandomNodeIdForBucket( } export { - prefixBuffer, + sepBuffer, encodeNodeId, decodeNodeId, bucketIndex, diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 168825b32..0a1519d19 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -170,7 +170,7 @@ function promisify< }; } -export type PromiseType = { +type PromiseDeconstructed = { p: Promise; resolveP: (value: T | PromiseLike) => void; rejectP: (reason?: any) => void; @@ -179,7 +179,7 @@ export type PromiseType = { /** * Deconstructed promise */ -function promise(): PromiseType { +function promise(): PromiseDeconstructed { let resolveP, rejectP; const p = new Promise((resolve, reject) => { resolveP = resolve; @@ -310,6 +310,7 @@ function debounce

( }; } +export type { PromiseDeconstructed }; export { getDefaultNodePath, never, diff --git a/src/vaults/VaultInternal.ts b/src/vaults/VaultInternal.ts index ae2adf6cf..b5e32da06 100644 --- a/src/vaults/VaultInternal.ts +++ b/src/vaults/VaultInternal.ts @@ -35,7 +35,7 @@ import * as validationUtils from '../validation/utils'; import * as vaultsPB from '../proto/js/polykey/v1/vaults/vaults_pb'; import { never } from '../utils/utils'; -export type RemoteInfo = { +type RemoteInfo = { remoteNode: NodeIdEncoded; remoteVault: VaultIdEncoded; }; @@ -1098,3 +1098,4 @@ class VaultInternal { } export default VaultInternal; +export type { RemoteInfo }; From 17b5f6ed04a4483438406779fe10c82b3816d5cc Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 7 Jun 2022 13:24:00 +1000 Subject: [PATCH 106/137] build: removing `node-abort-controller` polyfill Abort controller functionality is included in node now. --- package-lock.json | 5 ----- package.json | 1 - src/nodes/NodeConnectionManager.ts | 1 - src/nodes/NodeManager.ts | 4 +--- 4 files changed, 1 insertion(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5658b4d4c..8674bf340 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15953,11 +15953,6 @@ } } }, - "node-abort-controller": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", - "integrity": "sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==" - }, "node-fetch": { "version": "2.6.7", "requires": { diff --git a/package.json b/package.json index 5aea6e1ea..96e74b3f6 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,6 @@ "jose": "^4.3.6", "lexicographic-integer": "^1.1.0", "multiformats": "^9.4.8", - "node-abort-controller": "^3.0.1", "node-forge": "^0.10.0", "pako": "^1.0.11", "prompts": "^2.4.1", diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 8efe369e9..093fe22d6 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -13,7 +13,6 @@ import type { SeedNodes, } from './types'; import type NodeManager from './NodeManager'; -import type { AbortSignal } from 'node-abort-controller'; import { withF } from '@matrixai/resources'; import Logger from '@matrixai/logger'; import { ready, StartStop } from '@matrixai/async-init/dist/StartStop'; diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 95251648c..ffd9aa18f 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -15,10 +15,8 @@ import type { import type { ClaimEncoded } from '../claims/types'; import type { Timer } from '../types'; import type { PromiseDeconstructed } from '../utils/utils'; -import type { AbortSignal } from 'node-abort-controller'; import Logger from '@matrixai/logger'; import { StartStop, ready } from '@matrixai/async-init/dist/StartStop'; -import { AbortController } from 'node-abort-controller'; import * as nodesErrors from './errors'; import * as nodesUtils from './utils'; import * as networkUtils from '../network/utils'; @@ -394,7 +392,7 @@ class NodeManager { /** * Adds a node to the node graph. This assumes that you have already authenticated the node * Updates the node if the node already exists - * This operation is blocking by default - set `block` to false to make it non-blocking + * This operation is blocking by default - set `block` 2qto false to make it non-blocking * @param nodeId - Id of the node we wish to add * @param nodeAddress - Expected address of the node we want to add * @param block - Flag for if the operation should block or utilize the async queue From dac96be3eca9cf9da1c2636eed37b9b0f03d1fa1 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 7 Jun 2022 15:09:46 +1000 Subject: [PATCH 107/137] build: removing unneeded files --- test-iterator.ts | 31 -- test-lexi.ts | 4 - test-nodegraph.ts | 107 ----- test-nodeidgen.ts | 44 --- test-order.ts | 98 ----- test-sorting.ts | 28 -- test-split.ts | 37 -- test-trie.ts | 29 -- tests/nodes/NodeGraph.test.ts.old | 624 ------------------------------ 9 files changed, 1002 deletions(-) delete mode 100644 test-iterator.ts delete mode 100644 test-lexi.ts delete mode 100644 test-nodegraph.ts delete mode 100644 test-nodeidgen.ts delete mode 100644 test-order.ts delete mode 100644 test-sorting.ts delete mode 100644 test-split.ts delete mode 100644 test-trie.ts delete mode 100644 tests/nodes/NodeGraph.test.ts.old diff --git a/test-iterator.ts b/test-iterator.ts deleted file mode 100644 index 82a21762c..000000000 --- a/test-iterator.ts +++ /dev/null @@ -1,31 +0,0 @@ - - -function getYouG () { - console.log('ALREADY EXECUTED'); - return abc(); -} - -async function *abc() { - console.log('START'); - yield 1; - yield 2; - yield 3; -} - -async function main () { - - // we would want that you don't iterate it - - const g = getYouG(); - - await g.next(); - - // console.log('SUP'); - - // for await (const r of abc()) { - // console.log(r); - // } - -} - -main(); diff --git a/test-lexi.ts b/test-lexi.ts deleted file mode 100644 index b48f9cea1..000000000 --- a/test-lexi.ts +++ /dev/null @@ -1,4 +0,0 @@ -import lexi from 'lexicographic-integer'; - - -console.log(lexi.pack(1646203779)); diff --git a/test-nodegraph.ts b/test-nodegraph.ts deleted file mode 100644 index 33bd58bb7..000000000 --- a/test-nodegraph.ts +++ /dev/null @@ -1,107 +0,0 @@ -import type { NodeId, NodeAddress } from './src/nodes/types'; -import { DB } from '@matrixai/db'; -import { IdInternal } from '@matrixai/id'; -import * as keysUtils from './src/keys/utils'; -import * as nodesUtils from './src/nodes/utils'; -import NodeGraph from './src/nodes/NodeGraph'; -import KeyManager from './src/keys/KeyManager'; - -function generateRandomNodeId(readable: boolean = false): NodeId { - if (readable) { - const random = keysUtils.getRandomBytesSync(16).toString('hex'); - return IdInternal.fromString(random); - } else { - const random = keysUtils.getRandomBytesSync(32); - return IdInternal.fromBuffer(random); - } -} - -async function main () { - - const db = await DB.createDB({ - dbPath: './tmp/db' - }); - - const keyManager = await KeyManager.createKeyManager({ - keysPath: './tmp/keys', - password: 'abc123', - // fresh: true - }); - - const nodeGraph = await NodeGraph.createNodeGraph({ - db, - keyManager, - fresh: true - }); - - for (let i = 0; i < 10; i++) { - await nodeGraph.setNode( - generateRandomNodeId(), - { - host: '127.0.0.1', - port: 55555 - } as NodeAddress - ); - } - - for await (const [bucketIndex, bucket] of nodeGraph.getBuckets()) { - - // the bucket lengths are wrong - console.log( - 'BucketIndex', - bucketIndex, - 'Bucket Count', - bucket.length, - ); - - // console.log(bucket); - for (const [nodeId, nodeData] of bucket) { - // console.log('NODEID', nodeId); - // console.log('NODEDATA', nodeData); - // console.log(nodeData.address); - } - } - - for await (const [nodeId, nodeData] of nodeGraph.getNodes()) { - // console.log(nodeId, nodeData); - } - - const bucket = await nodeGraph.getBucket(255, 'lastUpdated'); - console.log(bucket.length); - - // console.log('OLD NODE ID', keyManager.getNodeId()); - // const newNodeId = generateRandomNodeId(); - // console.log('NEW NODE ID', newNodeId); - - // console.log('---------FIRST RESET--------'); - - // await nodeGraph.resetBuckets(newNodeId); - // for await (const [bucketIndex, bucket] of nodeGraph.getBuckets()) { - // console.log( - // 'BucketIndex', - // bucketIndex, - // 'Bucket Count', - // Object.keys(bucket).length - // ); - // } - - - // console.log('---------SECOND RESET--------'); - // const newNodeId2 = generateRandomNodeId(); - // await nodeGraph.resetBuckets(newNodeId2); - - // for await (const [bucketIndex, bucket] of nodeGraph.getBuckets()) { - // console.log( - // 'BucketIndex', - // bucketIndex, - // 'Bucket Count', - // Object.keys(bucket).length - // ); - // } - - await nodeGraph.stop(); - await keyManager.stop(); - await db.stop(); -} - -main(); diff --git a/test-nodeidgen.ts b/test-nodeidgen.ts deleted file mode 100644 index 2f79bddda..000000000 --- a/test-nodeidgen.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { NodeId } from './src/nodes/types'; -import { IdInternal } from '@matrixai/id'; -import * as keysUtils from './src/keys/utils'; -import * as nodesUtils from './src/nodes/utils'; - -function generateRandomNodeId(readable: boolean = false): NodeId { - if (readable) { - const random = keysUtils.getRandomBytesSync(16).toString('hex'); - return IdInternal.fromString(random); - } else { - const random = keysUtils.getRandomBytesSync(32); - return IdInternal.fromBuffer(random); - } -} - -async function main () { - - const firstNodeId = generateRandomNodeId(); - - - let lastBucket = 0; - let penultimateBucket = 0; - let lowerBuckets = 0; - - for (let i = 0; i < 1000; i++) { - const nodeId = generateRandomNodeId(); - const bucketIndex = nodesUtils.bucketIndex(firstNodeId, nodeId); - if (bucketIndex === 255) { - lastBucket++; - } else if (bucketIndex === 254) { - penultimateBucket++; - } else { - lowerBuckets++; - } - } - - console.log(lastBucket); - console.log(penultimateBucket); - console.log(lowerBuckets); - - -} - -main(); diff --git a/test-order.ts b/test-order.ts deleted file mode 100644 index f6046d6da..000000000 --- a/test-order.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { DB } from '@matrixai/db'; -import lexi from 'lexicographic-integer'; -import { getUnixtime, hex2Bytes } from './src/utils'; - -async function main () { - - const db = await DB.createDB({ - dbPath: './tmp/orderdb', - fresh: true - }); - - await db.put([], 'node1', 'value'); - await db.put([], 'node2', 'value'); - await db.put([], 'node3', 'value'); - await db.put([], 'node4', 'value'); - await db.put([], 'node5', 'value'); - await db.put([], 'node6', 'value'); - await db.put([], 'node7', 'value'); - - const now = new Date; - const t1 = new Date(now.getTime() + 1000 * 1); - const t2 = new Date(now.getTime() + 1000 * 2); - const t3 = new Date(now.getTime() + 1000 * 3); - const t4 = new Date(now.getTime() + 1000 * 4); - const t5 = new Date(now.getTime() + 1000 * 5); - const t6 = new Date(now.getTime() + 1000 * 6); - const t7 = new Date(now.getTime() + 1000 * 7); - - // so unix time is only what we really need to know - // further precision is unlikely - // and hex-packed time is shorter keys - // so it is likely faster - // the only issue is that unpacking requires - // converting hex into bytes, then into strings - - // console.log(t1.getTime()); - // console.log(getUnixtime(t1)); - // console.log(lexi.pack(getUnixtime(t1), 'hex')); - // console.log(lexi.pack(t1.getTime(), 'hex')); - // console.log(t1.toISOString()); - - - // buckets0!BUCKETINDEX!NODEID - // buckets0!BUCKETINDEX!date - - // Duplicate times that are put here - // But differentiate by the node1, node2 - await db.put([], lexi.pack(getUnixtime(t6), 'hex') + '-node1', 'value'); - await db.put([], lexi.pack(getUnixtime(t6), 'hex') + '-node2', 'value'); - - await db.put([], lexi.pack(getUnixtime(t1), 'hex') + '-node3', 'value'); - await db.put([], lexi.pack(getUnixtime(t4), 'hex') + '-node4', 'value'); - await db.put([], lexi.pack(getUnixtime(t3), 'hex') + '-node5', 'value'); - await db.put([], lexi.pack(getUnixtime(t2), 'hex') + '-node6', 'value'); - await db.put([], lexi.pack(getUnixtime(t5), 'hex') + '-node7', 'value'); - - // await db.put([], t6.toISOString() + '-node1', 'value'); - // await db.put([], t6.toISOString() + '-node2', 'value'); - - // await db.put([], t1.toISOString() + '-node3', 'value'); - // await db.put([], t4.toISOString() + '-node4', 'value'); - // await db.put([], t3.toISOString() + '-node5', 'value'); - // await db.put([], t2.toISOString() + '-node6', 'value'); - // await db.put([], t5.toISOString() + '-node7', 'value'); - - // Why did this require `-node3` - - // this will awlays get one or the other - - // ok so we if we want to say get a time - // or order it by time - // we are goingto have to create read stream over the bucket right? - // yea so we would have another sublevel, or at least a sublevel formed by the bucket - // one that is the bucket index - // so that would be the correct way to do it - - for await (const o of db.db.createReadStream({ - gte: lexi.pack(getUnixtime(t1), 'hex'), - limit: 1, - // keys: true, - // values: true, - // lte: lexi.pack(getUnixtime(t6)) - })) { - - console.log(o.key.toString()); - - } - - await db.stop(); - - - // so it works - // now if you give it something liek - - -} - -main(); diff --git a/test-sorting.ts b/test-sorting.ts deleted file mode 100644 index 1692fa83f..000000000 --- a/test-sorting.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as testNodesUtils from './tests/nodes/utils'; - -const arr = [ - { a: 'abc', b: 3}, - { a: 'abc', b: 1}, - { a: 'abc', b: 0}, -]; - -arr.sort((a, b): number => { - if (a.b > b.b) { - return 1; - } else if (a.b < b.b) { - return -1; - } else { - return 0; - } -}); - -console.log(arr); - -const arr2 = [3, 1, 0]; - -arr2.sort(); - -console.log(arr2); - - -console.log(testNodesUtils.generateRandomNodeId()); diff --git a/test-split.ts b/test-split.ts deleted file mode 100644 index ee06d75d6..000000000 --- a/test-split.ts +++ /dev/null @@ -1,37 +0,0 @@ - -function bufferSplit(input: Buffer, delimiter?: Buffer): Array { - const output: Array = []; - let delimiterIndex = 0; - let chunkIndex = 0; - if (delimiter != null) { - while (true) { - const i = input.indexOf( - delimiter, - delimiterIndex - ); - if (i > -1) { - output.push(input.subarray(chunkIndex, i)); - delimiterIndex = i + delimiter.byteLength; - chunkIndex = i + delimiter.byteLength; - } else { - output.push(input.subarray(chunkIndex)); - break; - } - } - } else { - for (let i = 0; i < input.byteLength; i++) { - output.push(input.subarray(i, i + 1)); - } - } - return output; -} - - -const b = Buffer.from('!a!!b!'); - -console.log(bufferSplit(b, Buffer.from('!!'))); -console.log(bufferSplit(b)); - -const s = '!a!!b!'; - -console.log(s.split('!!')); diff --git a/test-trie.ts b/test-trie.ts deleted file mode 100644 index a17c4165d..000000000 --- a/test-trie.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as utils from './src/utils'; -import * as nodesUtils from './src/nodes/utils'; - -// 110 -const ownNodeId = Buffer.from([6]); - -const i = 2; - -const maxDistance = utils.bigInt2Bytes(BigInt(2 ** i)); -const minDistance = utils.bigInt2Bytes(BigInt(2 ** (i - 1))); - -console.log('max distance', maxDistance, utils.bytes2Bits(maxDistance)); -console.log('min distance', minDistance, utils.bytes2Bits(minDistance)); - -// ownNodeId XOR maxdistance = GTE node id -const gte = ownNodeId.map((byte, i) => byte ^ maxDistance[i]); - -// ownNodeId XOR mindistance = LT node id -const lt = ownNodeId.map((byte, i) => byte ^ minDistance[i]); - -console.log('Lowest Distance Node (inc)', gte, utils.bytes2Bits(gte)); -console.log('Greatest Distance Node (exc)', lt, utils.bytes2Bits(lt)); - -// function nodeDistance(nodeId1: Buffer, nodeId2: Buffer): bigint { -// const distance = nodeId1.map((byte, i) => byte ^ nodeId2[i]); -// return utils.bytes2BigInt(distance); -// } - -// console.log(nodeDistance(ownNodeId, Buffer.from([0]))); diff --git a/tests/nodes/NodeGraph.test.ts.old b/tests/nodes/NodeGraph.test.ts.old deleted file mode 100644 index 1960c02d3..000000000 --- a/tests/nodes/NodeGraph.test.ts.old +++ /dev/null @@ -1,624 +0,0 @@ -import type { Host, Port } from '@/network/types'; -import type { NodeAddress, NodeData, NodeId } from '@/nodes/types'; -import os from 'os'; -import path from 'path'; -import fs from 'fs'; -import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import { DB } from '@matrixai/db'; -import { IdInternal } from '@matrixai/id'; -import NodeConnectionManager from '@/nodes/NodeConnectionManager'; -import NodeGraph from '@/nodes/NodeGraph'; -import * as nodesErrors from '@/nodes/errors'; -import KeyManager from '@/keys/KeyManager'; -import * as keysUtils from '@/keys/utils'; -import ForwardProxy from '@/network/ForwardProxy'; -import ReverseProxy from '@/network/ReverseProxy'; -import * as nodesUtils from '@/nodes/utils'; -import Sigchain from '@/sigchain/Sigchain'; -import * as nodesTestUtils from './utils'; - -describe(`${NodeGraph.name} test`, () => { - const password = 'password'; - let nodeGraph: NodeGraph; - let nodeId: NodeId; - - const nodeId1 = IdInternal.create([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, - ]); - const dummyNode = nodesUtils.decodeNodeId( - 'vi3et1hrpv2m2lrplcm7cu913kr45v51cak54vm68anlbvuf83ra0', - )!; - - const logger = new Logger(`${NodeGraph.name} test`, LogLevel.ERROR, [ - new StreamHandler(), - ]); - let fwdProxy: ForwardProxy; - let revProxy: ReverseProxy; - let dataDir: string; - let keyManager: KeyManager; - let db: DB; - let nodeConnectionManager: NodeConnectionManager; - let sigchain: Sigchain; - - const hostGen = (i: number) => `${i}.${i}.${i}.${i}` as Host; - - const mockedGenerateDeterministicKeyPair = jest.spyOn( - keysUtils, - 'generateDeterministicKeyPair', - ); - - beforeEach(async () => { - mockedGenerateDeterministicKeyPair.mockImplementation((bits, _) => { - return keysUtils.generateKeyPair(bits); - }); - - dataDir = await fs.promises.mkdtemp( - path.join(os.tmpdir(), 'polykey-test-'), - ); - const keysPath = `${dataDir}/keys`; - keyManager = await KeyManager.createKeyManager({ - password, - keysPath, - logger, - }); - fwdProxy = new ForwardProxy({ - authToken: 'auth', - logger: logger, - }); - - revProxy = new ReverseProxy({ - logger: logger, - }); - - await fwdProxy.start({ - tlsConfig: { - keyPrivatePem: keyManager.getRootKeyPairPem().privateKey, - certChainPem: await keyManager.getRootCertChainPem(), - }, - }); - const dbPath = `${dataDir}/db`; - db = await DB.createDB({ - dbPath, - logger, - crypto: { - key: keyManager.dbKey, - ops: { - encrypt: keysUtils.encryptWithKey, - decrypt: keysUtils.decryptWithKey, - }, - }, - }); - sigchain = await Sigchain.createSigchain({ - keyManager: keyManager, - db: db, - logger: logger, - }); - nodeGraph = await NodeGraph.createNodeGraph({ - db, - keyManager, - logger, - }); - nodeConnectionManager = new NodeConnectionManager({ - keyManager: keyManager, - nodeGraph: nodeGraph, - fwdProxy: fwdProxy, - revProxy: revProxy, - logger: logger, - }); - await nodeConnectionManager.start(); - // Retrieve the NodeGraph reference from NodeManager - nodeId = keyManager.getNodeId(); - }); - - afterEach(async () => { - await db.stop(); - await sigchain.stop(); - await nodeConnectionManager.stop(); - await nodeGraph.stop(); - await keyManager.stop(); - await fwdProxy.stop(); - await fs.promises.rm(dataDir, { - force: true, - recursive: true, - }); - }); - - test('NodeGraph readiness', async () => { - const nodeGraph2 = await NodeGraph.createNodeGraph({ - db, - keyManager, - logger, - }); - // @ts-ignore - await expect(nodeGraph2.destroy()).rejects.toThrow( - nodesErrors.ErrorNodeGraphRunning, - ); - // Should be a noop - await nodeGraph2.start(); - await nodeGraph2.stop(); - await nodeGraph2.destroy(); - await expect(async () => { - await nodeGraph2.start(); - }).rejects.toThrow(nodesErrors.ErrorNodeGraphDestroyed); - await expect(async () => { - await nodeGraph2.getBucket(0); - }).rejects.toThrow(nodesErrors.ErrorNodeGraphNotRunning); - await expect(async () => { - await nodeGraph2.getBucket(0); - }).rejects.toThrow(nodesErrors.ErrorNodeGraphNotRunning); - }); - test('knows node (true and false case)', async () => { - // Known node - const nodeAddress1: NodeAddress = { - host: '127.0.0.1' as Host, - port: 11111 as Port, - }; - await nodeGraph.setNode(nodeId1, nodeAddress1); - expect(await nodeGraph.knowsNode(nodeId1)).toBeTruthy(); - - // Unknown node - expect(await nodeGraph.knowsNode(dummyNode)).toBeFalsy(); - }); - test('finds correct node address', async () => { - // New node added - const newNode2Id = nodeId1; - const newNode2Address = { host: '227.1.1.1', port: 4567 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - // Get node address - const foundAddress = await nodeGraph.getNode(newNode2Id); - expect(foundAddress).toEqual({ host: '227.1.1.1', port: 4567 }); - }); - test('unable to find node address', async () => { - // New node added - const newNode2Id = nodeId1; - const newNode2Address = { host: '227.1.1.1', port: 4567 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - // Get node address (of non-existent node) - const foundAddress = await nodeGraph.getNode(dummyNode); - expect(foundAddress).toBeUndefined(); - }); - test('adds a single node into a bucket', async () => { - // New node added - const newNode2Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 1); - const newNode2Address = { host: '227.1.1.1', port: 4567 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - // Check new node is in retrieved bucket from database - // bucketIndex = 1 as "NODEID1" XOR "NODEID2" = 3 - const bucket = await nodeGraph.getBucket(1); - expect(bucket).toBeDefined(); - expect(bucket![newNode2Id]).toEqual({ - address: { host: '227.1.1.1', port: 4567 }, - lastUpdated: expect.any(Date), - }); - }); - test('adds multiple nodes into the same bucket', async () => { - // Add 3 new nodes into bucket 4 - const bucketIndex = 4; - const newNode1Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 0, - ); - const newNode1Address = { host: '4.4.4.4', port: 4444 } as NodeAddress; - await nodeGraph.setNode(newNode1Id, newNode1Address); - - const newNode2Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 1, - ); - const newNode2Address = { host: '5.5.5.5', port: 5555 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - const newNode3Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 2, - ); - const newNode3Address = { host: '6.6.6.6', port: 6666 } as NodeAddress; - await nodeGraph.setNode(newNode3Id, newNode3Address); - // Based on XOR values, all 3 nodes should appear in bucket 4 - const bucket = await nodeGraph.getBucket(4); - expect(bucket).toBeDefined(); - if (!bucket) fail('bucket should be defined, letting TS know'); - expect(bucket[newNode1Id]).toEqual({ - address: { host: '4.4.4.4', port: 4444 }, - lastUpdated: expect.any(Date), - }); - expect(bucket[newNode2Id]).toEqual({ - address: { host: '5.5.5.5', port: 5555 }, - lastUpdated: expect.any(Date), - }); - expect(bucket[newNode3Id]).toEqual({ - address: { host: '6.6.6.6', port: 6666 }, - lastUpdated: expect.any(Date), - }); - }); - test('adds a single node into different buckets', async () => { - // New node for bucket 3 - const newNode1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 3); - const newNode1Address = { host: '1.1.1.1', port: 1111 } as NodeAddress; - await nodeGraph.setNode(newNode1Id, newNode1Address); - // New node for bucket 255 (the highest possible bucket) - const newNode2Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 255); - const newNode2Address = { host: '2.2.2.2', port: 2222 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - const bucket3 = await nodeGraph.getBucket(3); - const bucket351 = await nodeGraph.getBucket(255); - if (bucket3 && bucket351) { - expect(bucket3[newNode1Id]).toEqual({ - address: { host: '1.1.1.1', port: 1111 }, - lastUpdated: expect.any(Date), - }); - expect(bucket351[newNode2Id]).toEqual({ - address: { host: '2.2.2.2', port: 2222 }, - lastUpdated: expect.any(Date), - }); - } else { - // Should be unreachable - fail('Bucket undefined'); - } - }); - test('deletes a single node (and removes bucket)', async () => { - // New node for bucket 2 - const newNode1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 2); - const newNode1Address = { host: '4.4.4.4', port: 4444 } as NodeAddress; - await nodeGraph.setNode(newNode1Id, newNode1Address); - - // Check the bucket is there first - const bucket = await nodeGraph.getBucket(2); - if (bucket) { - expect(bucket[newNode1Id]).toEqual({ - address: { host: '4.4.4.4', port: 4444 }, - lastUpdated: expect.any(Date), - }); - } else { - // Should be unreachable - fail('Bucket undefined'); - } - - // Delete the node - await nodeGraph.unsetNode(newNode1Id); - // Check bucket no longer exists - const newBucket = await nodeGraph.getBucket(2); - expect(newBucket).toBeUndefined(); - }); - test('deletes a single node (and retains remainder of bucket)', async () => { - // Add 3 new nodes into bucket 4 - const bucketIndex = 4; - const newNode1Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 0, - ); - const newNode1Address = { host: '4.4.4.4', port: 4444 } as NodeAddress; - await nodeGraph.setNode(newNode1Id, newNode1Address); - - const newNode2Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 1, - ); - const newNode2Address = { host: '5.5.5.5', port: 5555 } as NodeAddress; - await nodeGraph.setNode(newNode2Id, newNode2Address); - - const newNode3Id = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - 2, - ); - const newNode3Address = { host: '6.6.6.6', port: 6666 } as NodeAddress; - await nodeGraph.setNode(newNode3Id, newNode3Address); - // Based on XOR values, all 3 nodes should appear in bucket 4 - const bucket = await nodeGraph.getBucket(bucketIndex); - if (bucket) { - expect(bucket[newNode1Id]).toEqual({ - address: { host: '4.4.4.4', port: 4444 }, - lastUpdated: expect.any(Date), - }); - expect(bucket[newNode2Id]).toEqual({ - address: { host: '5.5.5.5', port: 5555 }, - lastUpdated: expect.any(Date), - }); - expect(bucket[newNode3Id]).toEqual({ - address: { host: '6.6.6.6', port: 6666 }, - lastUpdated: expect.any(Date), - }); - } else { - // Should be unreachable - fail('Bucket undefined'); - } - - // Delete the node - await nodeGraph.unsetNode(newNode1Id); - // Check node no longer exists in the bucket - const newBucket = await nodeGraph.getBucket(bucketIndex); - if (newBucket) { - expect(newBucket[newNode1Id]).toBeUndefined(); - expect(bucket[newNode2Id]).toEqual({ - address: { host: '5.5.5.5', port: 5555 }, - lastUpdated: expect.any(Date), - }); - expect(bucket[newNode3Id]).toEqual({ - address: { host: '6.6.6.6', port: 6666 }, - lastUpdated: expect.any(Date), - }); - } else { - // Should be unreachable - fail('New bucket undefined'); - } - }); - test('enforces k-bucket size, removing least active node when a new node is discovered', async () => { - // Add k nodes to the database (importantly, they all go into the same bucket) - const bucketIndex = 59; - // Keep a record of the first node ID that we added - const firstNodeId = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - ); - for (let i = 1; i <= nodeGraph.maxNodesPerBucket; i++) { - // Add the current node ID - const nodeAddress = { - host: hostGen(i), - port: i as Port, - }; - await nodeGraph.setNode( - nodesTestUtils.generateNodeIdForBucket(nodeId, bucketIndex, i), - nodeAddress, - ); - // Increment the current node ID - } - // All of these nodes are in bucket 59 - const originalBucket = await nodeGraph.getBucket(bucketIndex); - if (originalBucket) { - expect(Object.keys(originalBucket).length).toBe( - nodeGraph.maxNodesPerBucket, - ); - } else { - // Should be unreachable - fail('Bucket undefined'); - } - - // Attempt to add a new node into this full bucket (increment the last node - // ID that was added) - const newNodeId = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - nodeGraph.maxNodesPerBucket + 1, - ); - const newNodeAddress = { host: '0.0.0.1' as Host, port: 1234 as Port }; - await nodeGraph.setNode(newNodeId, newNodeAddress); - - const finalBucket = await nodeGraph.getBucket(bucketIndex); - if (finalBucket) { - // We should still have a full bucket (but no more) - expect(Object.keys(finalBucket).length).toEqual( - nodeGraph.maxNodesPerBucket, - ); - // Ensure that this new node is in the bucket - expect(finalBucket[newNodeId]).toEqual({ - address: newNodeAddress, - lastUpdated: expect.any(Date), - }); - // NODEID1 should have been removed from this bucket (as this was the least active) - // The first node added should have been removed from this bucket (as this - // was the least active, purely because it was inserted first) - expect(finalBucket[firstNodeId]).toBeUndefined(); - } else { - // Should be unreachable - fail('Bucket undefined'); - } - }); - test('enforces k-bucket size, retaining all nodes if adding a pre-existing node', async () => { - // Add k nodes to the database (importantly, they all go into the same bucket) - const bucketIndex = 59; - const currNodeId = nodesTestUtils.generateNodeIdForBucket( - nodeId, - bucketIndex, - ); - // Keep a record of the first node ID that we added - // const firstNodeId = currNodeId; - let increment = 1; - for (let i = 1; i <= nodeGraph.maxNodesPerBucket; i++) { - // Add the current node ID - const nodeAddress = { - host: hostGen(i), - port: i as Port, - }; - await nodeGraph.setNode( - nodesTestUtils.generateNodeIdForBucket(nodeId, bucketIndex, increment), - nodeAddress, - ); - // Increment the current node ID - skip for the last one to keep currNodeId - // as the last added node ID - if (i !== nodeGraph.maxNodesPerBucket) { - increment++; - } - } - // All of these nodes are in bucket 59 - const originalBucket = await nodeGraph.getBucket(bucketIndex); - if (originalBucket) { - expect(Object.keys(originalBucket).length).toBe( - nodeGraph.maxNodesPerBucket, - ); - } else { - // Should be unreachable - fail('Bucket undefined'); - } - - // If we tried to re-add the first node, it would simply remove the original - // first node, as this is the "least active" - // We instead want to check that we don't mistakenly delete a node if we're - // updating an existing one - // So, re-add the last node - const newLastAddress: NodeAddress = { - host: '30.30.30.30' as Host, - port: 30 as Port, - }; - await nodeGraph.setNode(currNodeId, newLastAddress); - - const finalBucket = await nodeGraph.getBucket(bucketIndex); - if (finalBucket) { - // We should still have a full bucket - expect(Object.keys(finalBucket).length).toEqual( - nodeGraph.maxNodesPerBucket, - ); - // Ensure that this new node is in the bucket - expect(finalBucket[currNodeId]).toEqual({ - address: newLastAddress, - lastUpdated: expect.any(Date), - }); - } else { - // Should be unreachable - fail('Bucket undefined'); - } - }); - test('retrieves all buckets (in expected lexicographic order)', async () => { - // Bucket 0 is expected to never have any nodes (as nodeId XOR 0 = nodeId) - // Bucket 1 (minimum): - - const node1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 1); - const node1Address = { host: '1.1.1.1', port: 1111 } as NodeAddress; - await nodeGraph.setNode(node1Id, node1Address); - - // Bucket 4 (multiple nodes in 1 bucket): - const node41Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 4); - const node41Address = { host: '41.41.41.41', port: 4141 } as NodeAddress; - await nodeGraph.setNode(node41Id, node41Address); - const node42Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 4, 1); - const node42Address = { host: '42.42.42.42', port: 4242 } as NodeAddress; - await nodeGraph.setNode(node42Id, node42Address); - - // Bucket 10 (lexicographic ordering - should appear after 2): - const node10Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 10); - const node10Address = { host: '10.10.10.10', port: 1010 } as NodeAddress; - await nodeGraph.setNode(node10Id, node10Address); - - // Bucket 255 (maximum): - const node255Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 255); - const node255Address = { - host: '255.255.255.255', - port: 255, - } as NodeAddress; - await nodeGraph.setNode(node255Id, node255Address); - - const buckets = await nodeGraph.getAllBuckets(); - expect(buckets.length).toBe(4); - // Buckets should be returned in lexicographic ordering (using hex keys to - // ensure the bucket indexes are in numberical order) - expect(buckets).toEqual([ - { - [node1Id]: { - address: { host: '1.1.1.1', port: 1111 }, - lastUpdated: expect.any(String), - }, - }, - { - [node41Id]: { - address: { host: '41.41.41.41', port: 4141 }, - lastUpdated: expect.any(String), - }, - [node42Id]: { - address: { host: '42.42.42.42', port: 4242 }, - lastUpdated: expect.any(String), - }, - }, - { - [node10Id]: { - address: { host: '10.10.10.10', port: 1010 }, - lastUpdated: expect.any(String), - }, - }, - { - [node255Id]: { - address: { host: '255.255.255.255', port: 255 }, - lastUpdated: expect.any(String), - }, - }, - ]); - }); - test( - 'refreshes buckets', - async () => { - const initialNodes: Record = {}; - // Generate and add some nodes - for (let i = 1; i < 255; i += 20) { - const newNodeId = nodesTestUtils.generateNodeIdForBucket( - keyManager.getNodeId(), - i, - ); - const nodeAddress = { - host: hostGen(i), - port: i as Port, - }; - await nodeGraph.setNode(newNodeId, nodeAddress); - initialNodes[newNodeId] = { - id: newNodeId, - address: nodeAddress, - distance: nodesUtils.calculateDistance( - keyManager.getNodeId(), - newNodeId, - ), - }; - } - - // Renew the keypair - await keyManager.renewRootKeyPair('newPassword'); - // Reset the test's node ID state - nodeId = keyManager.getNodeId(); - // Refresh the buckets - await nodeGraph.refreshBuckets(); - - // Get all the new buckets, and expect that each node is in the correct bucket - const newBuckets = await nodeGraph.getAllBuckets(); - let nodeCount = 0; - for (const b of newBuckets) { - for (const n of Object.keys(b)) { - const nodeId = IdInternal.fromString(n); - // Check that it was a node in the original DB - expect(initialNodes[nodeId]).toBeDefined(); - // Check it's in the correct bucket - const expectedIndex = nodesUtils.calculateBucketIndex( - keyManager.getNodeId(), - nodeId, - ); - const expectedBucket = await nodeGraph.getBucket(expectedIndex); - expect(expectedBucket).toBeDefined(); - expect(expectedBucket![nodeId]).toBeDefined(); - // Check it has the correct address - expect(b[nodeId].address).toEqual(initialNodes[nodeId].address); - nodeCount++; - } - } - // We had less than k (20) nodes, so we expect that all nodes will be re-added - // If we had more than k nodes, we may lose some of them (because the nodes - // may be re-added to newly full buckets) - expect(Object.keys(initialNodes).length).toEqual(nodeCount); - }, - global.defaultTimeout * 4, - ); - test('updates node', async () => { - // New node added - const node1Id = nodesTestUtils.generateNodeIdForBucket(nodeId, 2); - const node1Address = { host: '1.1.1.1', port: 1 } as NodeAddress; - await nodeGraph.setNode(node1Id, node1Address); - - // Check new node is in retrieved bucket from database - const bucket = await nodeGraph.getBucket(2); - const time1 = bucket![node1Id].lastUpdated; - - // Update node and check that time is later - const newNode1Address = { host: '2.2.2.2', port: 2 } as NodeAddress; - await nodeGraph.updateNode(node1Id, newNode1Address); - - const bucket2 = await nodeGraph.getBucket(2); - const time2 = bucket2![node1Id].lastUpdated; - expect(bucket2![node1Id].address).toEqual(newNode1Address); - expect(time1 < time2).toBeTruthy(); - }); -}); From a522de3be06ae5b4b871c0f83ef1ee49f6865879 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 7 Jun 2022 16:59:35 +1000 Subject: [PATCH 108/137] fix: `NodeConnectionManager.syncNodeGraph` now pings nodes Need to ensure validity of nodes by pinging them before adding them to the node graph. #322 --- src/bin/nodes/CommandAdd.ts | 12 +- src/bin/utils/options.ts | 11 + src/client/service/nodesAdd.ts | 22 +- src/nodes/NodeConnectionManager.ts | 64 +++-- src/nodes/NodeManager.ts | 6 + src/nodes/errors.ts | 6 + src/proto/js/google/protobuf/any_pb.js | 1 + src/proto/js/google/protobuf/descriptor_pb.js | 1 + src/proto/js/google/protobuf/duration_pb.js | 1 + src/proto/js/google/protobuf/empty_pb.js | 1 + src/proto/js/google/protobuf/field_mask_pb.js | 1 + src/proto/js/google/protobuf/struct_pb.js | 1 + src/proto/js/google/protobuf/timestamp_pb.js | 1 + src/proto/js/google/protobuf/wrappers_pb.js | 1 + src/proto/js/polykey/v1/agent/agent_pb.js | 1 + src/proto/js/polykey/v1/agent_service_pb.js | 1 + .../js/polykey/v1/client_service_grpc_pb.d.ts | 20 +- .../js/polykey/v1/client_service_grpc_pb.js | 17 +- src/proto/js/polykey/v1/client_service_pb.js | 1 + .../js/polykey/v1/gestalts/gestalts_pb.js | 1 + .../js/polykey/v1/identities/identities_pb.js | 1 + src/proto/js/polykey/v1/keys/keys_pb.js | 1 + src/proto/js/polykey/v1/nodes/nodes_pb.d.ts | 32 +++ src/proto/js/polykey/v1/nodes/nodes_pb.js | 264 ++++++++++++++++++ .../v1/notifications/notifications_pb.js | 1 + .../polykey/v1/permissions/permissions_pb.js | 1 + src/proto/js/polykey/v1/secrets/secrets_pb.js | 1 + .../js/polykey/v1/sessions/sessions_pb.js | 1 + src/proto/js/polykey/v1/test_service_pb.js | 1 + src/proto/js/polykey/v1/utils/utils_pb.js | 1 + src/proto/js/polykey/v1/vaults/vaults_pb.js | 1 + .../schemas/polykey/v1/client_service.proto | 2 +- .../schemas/polykey/v1/nodes/nodes.proto | 7 + tests/bin/nodes/add.test.ts | 98 ++++++- tests/bin/nodes/find.test.ts | 60 ++-- tests/client/service/nodesAdd.test.ts | 8 +- .../NodeConnectionManager.general.test.ts | 35 ++- .../NodeConnectionManager.seednodes.test.ts | 38 ++- 38 files changed, 639 insertions(+), 84 deletions(-) diff --git a/src/bin/nodes/CommandAdd.ts b/src/bin/nodes/CommandAdd.ts index fdf49f48e..49ea3105a 100644 --- a/src/bin/nodes/CommandAdd.ts +++ b/src/bin/nodes/CommandAdd.ts @@ -18,6 +18,8 @@ class CommandAdd extends CommandPolykey { this.addOption(binOptions.nodeId); this.addOption(binOptions.clientHost); this.addOption(binOptions.clientPort); + this.addOption(binOptions.forceNodeAdd); + this.addOption(binOptions.noPing); this.action(async (nodeId: NodeId, host: Host, port: Port, options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const nodesUtils = await import('../../nodes/utils'); @@ -46,13 +48,15 @@ class CommandAdd extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - const nodeAddressMessage = new nodesPB.NodeAddress(); - nodeAddressMessage.setNodeId(nodesUtils.encodeNodeId(nodeId)); - nodeAddressMessage.setAddress( + const nodeAddMessage = new nodesPB.NodeAdd(); + nodeAddMessage.setNodeId(nodesUtils.encodeNodeId(nodeId)); + nodeAddMessage.setAddress( new nodesPB.Address().setHost(host).setPort(port), ); + nodeAddMessage.setForce(options.force); + nodeAddMessage.setPing(options.ping); await binUtils.retryAuthentication( - (auth) => pkClient.grpcClient.nodesAdd(nodeAddressMessage, auth), + (auth) => pkClient.grpcClient.nodesAdd(nodeAddMessage, auth), meta, ); } finally { diff --git a/src/bin/utils/options.ts b/src/bin/utils/options.ts index bed18d65a..f2da17b8c 100644 --- a/src/bin/utils/options.ts +++ b/src/bin/utils/options.ts @@ -154,6 +154,15 @@ const pullVault = new commander.Option( 'Name or Id of the vault to pull from', ); +const forceNodeAdd = new commander.Option( + '--force', + 'Force adding node to nodeGraph', +).default(false); + +const noPing = new commander.Option('--no-ping', 'Skip ping step').default( + true, +); + export { nodePath, format, @@ -176,4 +185,6 @@ export { network, workers, pullVault, + forceNodeAdd, + noPing, }; diff --git a/src/client/service/nodesAdd.ts b/src/client/service/nodesAdd.ts index 0d993c746..3b6043219 100644 --- a/src/client/service/nodesAdd.ts +++ b/src/client/service/nodesAdd.ts @@ -6,6 +6,7 @@ import type { NodeId, NodeAddress } from '../../nodes/types'; import type { Host, Hostname, Port } from '../../network/types'; import type * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; import type Logger from '@matrixai/logger'; +import * as nodeErrors from '../../nodes/errors'; import * as grpcUtils from '../../grpc/utils'; import { validateSync } from '../../validation'; import * as validationUtils from '../../validation/utils'; @@ -30,12 +31,13 @@ function nodesAdd({ logger: Logger; }) { return async ( - call: grpc.ServerUnaryCall, + call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData, ): Promise => { try { const response = new utilsPB.EmptyMessage(); const metadata = await authenticate(call.metadata); + const request = call.request; call.sendMetadata(metadata); const { nodeId, @@ -55,11 +57,21 @@ function nodesAdd({ ); }, { - nodeId: call.request.getNodeId(), - host: call.request.getAddress()?.getHost(), - port: call.request.getAddress()?.getPort(), + nodeId: request.getNodeId(), + host: request.getAddress()?.getHost(), + port: request.getAddress()?.getPort(), }, ); + // Pinging to authenticate the node + if ( + request.getPing() && + !(await nodeManager.pingNode(nodeId, { host, port })) + ) { + throw new nodeErrors.ErrorNodePingFailed( + 'Failed to authenticate target node', + ); + } + await db.withTransactionF(async (tran) => nodeManager.setNode( nodeId, @@ -68,7 +80,7 @@ function nodesAdd({ port, } as NodeAddress, true, - true, + request.getForce(), undefined, tran, ), diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 093fe22d6..f39f333d8 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -111,7 +111,12 @@ class NodeConnectionManager { this.nodeManager = nodeManager; for (const nodeIdEncoded in this.seedNodes) { const nodeId = nodesUtils.decodeNodeId(nodeIdEncoded)!; - await this.nodeGraph.setNode(nodeId, this.seedNodes[nodeIdEncoded]); + await this.nodeManager.setNode( + nodeId, + this.seedNodes[nodeIdEncoded], + true, + true, + ); } this.logger.info(`Started ${this.constructor.name}`); } @@ -431,10 +436,14 @@ class NodeConnectionManager { timer?: Timer, options: { signal?: AbortSignal } = {}, ): Promise { + const localNodeId = this.keyManager.getNodeId(); const { signal } = { ...options }; // Let foundTarget: boolean = false; let foundAddress: NodeAddress | undefined = undefined; // Get the closest alpha nodes to the target node (set as shortlist) + // FIXME? this is an array. Shouldn't it be a set? + // It's possible for this to grow faster than we can consume it, + // doubly so if we allow duplicates const shortlist = await this.nodeGraph.getClosestNodes( targetNodeId, this.initialClosestNodes, @@ -466,13 +475,15 @@ class NodeConnectionManager { } // Connect to the node (check if pre-existing connection exists, otherwise // create a new one) - try { - // Add the node to the database so that we can find its address in - // call to getConnectionToNode - await this.nodeGraph.setNode(nextNodeId, nextNodeAddress.address); - await this.getConnection(nextNodeId, timer); - } catch (e) { - // If we can't connect to the node, then skip it + if ( + await this.pingNode( + nextNodeId, + nextNodeAddress.address.host, + nextNodeAddress.address.port, + ) + ) { + await this.nodeManager!.setNode(nextNodeId, nextNodeAddress.address); + } else { continue; } contacted[nextNodeId] = true; @@ -486,12 +497,19 @@ class NodeConnectionManager { // them to the shortlist for (const [nodeId, nodeData] of foundClosest) { if (signal?.aborted) throw new nodesErrors.ErrorNodeAborted(); - // Ignore a`ny nodes that have been contacted - if (contacted[nodeId]) { + // Ignore any nodes that have been contacted or our own node + if (contacted[nodeId] || localNodeId.equals(nodeId)) { continue; } - if (nodeId.equals(targetNodeId)) { - await this.nodeGraph.setNode(nodeId, nodeData.address); + if ( + nodeId.equals(targetNodeId) && + (await this.pingNode( + nodeId, + nodeData.address.host, + nodeData.address.port, + )) + ) { + await this.nodeManager!.setNode(nodeId, nodeData.address); foundAddress = nodeData.address; // We have found the target node, so we can stop trying to look for it // in the shortlist @@ -555,7 +573,9 @@ class NodeConnectionManager { host: address.getHost() as Host | Hostname, port: address.getPort() as Port, }, - lastUpdated: 0, // FIXME? + // Not really needed + // But if it's needed then we need to add the information to the proto definition + lastUpdated: 0, }, ]); } @@ -589,15 +609,20 @@ class NodeConnectionManager { this.keyManager.getNodeId(), timer, ); - // FIXME: we need to ping a node before setting it for (const [nodeId, nodeData] of nodes) { + const pingAndAddNode = async () => { + const port = nodeData.address.port; + const host = await networkUtils.resolveHost(nodeData.address.host); + if (await this.pingNode(nodeId, host, port)) { + await this.nodeManager!.setNode(nodeId, nodeData.address, true); + } + }; + if (!block) { - this.queue.push(() => - this.nodeManager!.setNode(nodeId, nodeData.address), - ); + this.queue.push(pingAndAddNode); } else { try { - await this.nodeManager?.setNode(nodeId, nodeData.address); + await pingAndAddNode(); } catch (e) { if (!(e instanceof nodesErrors.ErrorNodeGraphSameNodeId)) throw e; } @@ -703,10 +728,11 @@ class NodeConnectionManager { @ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning()) public async pingNode( nodeId: NodeId, - host: Host, + host: Host | Hostname, port: Port, timer?: Timer, ): Promise { + host = await networkUtils.resolveHost(host); // If we can create a connection then we have punched though the NAT, // authenticated and confirmed the nodeId matches const proxyAddress = networkUtils.buildAddress( diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index ffd9aa18f..bb264de4f 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -410,6 +410,12 @@ class NodeManager { timeout?: number, tran?: DBTransaction, ): Promise { + // We don't want to add our own node + if (nodeId.equals(this.keyManager.getNodeId())) { + this.logger.debug('Is own NodeId, skipping'); + return; + } + if (tran == null) { return this.db.withTransactionF(async (tran) => this.setNode(nodeId, nodeAddress, block, force, timeout, tran), diff --git a/src/nodes/errors.ts b/src/nodes/errors.ts index b35a58f70..bc0185025 100644 --- a/src/nodes/errors.ts +++ b/src/nodes/errors.ts @@ -86,6 +86,11 @@ class ErrorNodeConnectionHostWildcard extends ErrorNodes { static description = 'An IP wildcard was provided for the target host'; exitCode = sysexits.USAGE; } +class ErrorNodePingFailed extends ErrorNodes { + static description = + 'Failed to ping the node when attempting to authenticate'; + exitCode = sysexits.NOHOST; +} export { ErrorNodes, @@ -106,4 +111,5 @@ export { ErrorNodeConnectionPublicKeyNotFound, ErrorNodeConnectionManagerNotRunning, ErrorNodeConnectionHostWildcard, + ErrorNodePingFailed, }; diff --git a/src/proto/js/google/protobuf/any_pb.js b/src/proto/js/google/protobuf/any_pb.js index 2154f2078..cec1761c8 100644 --- a/src/proto/js/google/protobuf/any_pb.js +++ b/src/proto/js/google/protobuf/any_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/google/protobuf/descriptor_pb.js b/src/proto/js/google/protobuf/descriptor_pb.js index 64e84878b..9c345b93d 100644 --- a/src/proto/js/google/protobuf/descriptor_pb.js +++ b/src/proto/js/google/protobuf/descriptor_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/google/protobuf/duration_pb.js b/src/proto/js/google/protobuf/duration_pb.js index 74166f0fd..1b5f0fd84 100644 --- a/src/proto/js/google/protobuf/duration_pb.js +++ b/src/proto/js/google/protobuf/duration_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/google/protobuf/empty_pb.js b/src/proto/js/google/protobuf/empty_pb.js index d85fa310a..bd5d8a4e1 100644 --- a/src/proto/js/google/protobuf/empty_pb.js +++ b/src/proto/js/google/protobuf/empty_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/google/protobuf/field_mask_pb.js b/src/proto/js/google/protobuf/field_mask_pb.js index 67860a3a2..34e581b04 100644 --- a/src/proto/js/google/protobuf/field_mask_pb.js +++ b/src/proto/js/google/protobuf/field_mask_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/google/protobuf/struct_pb.js b/src/proto/js/google/protobuf/struct_pb.js index bff1ed412..b16b8b2fa 100644 --- a/src/proto/js/google/protobuf/struct_pb.js +++ b/src/proto/js/google/protobuf/struct_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/google/protobuf/timestamp_pb.js b/src/proto/js/google/protobuf/timestamp_pb.js index 6881a1d93..a270c1c47 100644 --- a/src/proto/js/google/protobuf/timestamp_pb.js +++ b/src/proto/js/google/protobuf/timestamp_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/google/protobuf/wrappers_pb.js b/src/proto/js/google/protobuf/wrappers_pb.js index 9c89af542..458e1b436 100644 --- a/src/proto/js/google/protobuf/wrappers_pb.js +++ b/src/proto/js/google/protobuf/wrappers_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/agent/agent_pb.js b/src/proto/js/polykey/v1/agent/agent_pb.js index 13a458c48..29361addf 100644 --- a/src/proto/js/polykey/v1/agent/agent_pb.js +++ b/src/proto/js/polykey/v1/agent/agent_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/agent_service_pb.js b/src/proto/js/polykey/v1/agent_service_pb.js index ade0b70fa..9fa48c738 100644 --- a/src/proto/js/polykey/v1/agent_service_pb.js +++ b/src/proto/js/polykey/v1/agent_service_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts b/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts index 067688187..b230f8df4 100644 --- a/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts +++ b/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts @@ -122,12 +122,12 @@ interface IClientServiceService_IAgentUnlock extends grpc.MethodDefinition; responseDeserialize: grpc.deserialize; } -interface IClientServiceService_INodesAdd extends grpc.MethodDefinition { +interface IClientServiceService_INodesAdd extends grpc.MethodDefinition { path: "/polykey.v1.ClientService/NodesAdd"; requestStream: false; responseStream: false; - requestSerialize: grpc.serialize; - requestDeserialize: grpc.deserialize; + requestSerialize: grpc.serialize; + requestDeserialize: grpc.deserialize; responseSerialize: grpc.serialize; responseDeserialize: grpc.deserialize; } @@ -679,7 +679,7 @@ export interface IClientServiceServer extends grpc.UntypedServiceImplementation agentStatus: grpc.handleUnaryCall; agentStop: grpc.handleUnaryCall; agentUnlock: grpc.handleUnaryCall; - nodesAdd: grpc.handleUnaryCall; + nodesAdd: grpc.handleUnaryCall; nodesPing: grpc.handleUnaryCall; nodesClaim: grpc.handleUnaryCall; nodesFind: grpc.handleUnaryCall; @@ -755,9 +755,9 @@ export interface IClientServiceClient { agentUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; agentUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; agentUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; - nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; - nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; - nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAdd, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAdd, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAdd, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; nodesPing(request: polykey_v1_nodes_nodes_pb.Node, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; nodesPing(request: polykey_v1_nodes_nodes_pb.Node, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; nodesPing(request: polykey_v1_nodes_nodes_pb.Node, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; @@ -943,9 +943,9 @@ export class ClientServiceClient extends grpc.Client implements IClientServiceCl public agentUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; public agentUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; public agentUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; - public nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; - public nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; - public nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + public nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAdd, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + public nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAdd, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + public nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAdd, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; public nodesPing(request: polykey_v1_nodes_nodes_pb.Node, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; public nodesPing(request: polykey_v1_nodes_nodes_pb.Node, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; public nodesPing(request: polykey_v1_nodes_nodes_pb.Node, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; diff --git a/src/proto/js/polykey/v1/client_service_grpc_pb.js b/src/proto/js/polykey/v1/client_service_grpc_pb.js index 642127423..e08b6512c 100644 --- a/src/proto/js/polykey/v1/client_service_grpc_pb.js +++ b/src/proto/js/polykey/v1/client_service_grpc_pb.js @@ -201,6 +201,17 @@ function deserialize_polykey_v1_nodes_Node(buffer_arg) { return polykey_v1_nodes_nodes_pb.Node.deserializeBinary(new Uint8Array(buffer_arg)); } +function serialize_polykey_v1_nodes_NodeAdd(arg) { + if (!(arg instanceof polykey_v1_nodes_nodes_pb.NodeAdd)) { + throw new Error('Expected argument of type polykey.v1.nodes.NodeAdd'); + } + return Buffer.from(arg.serializeBinary()); +} + +function deserialize_polykey_v1_nodes_NodeAdd(buffer_arg) { + return polykey_v1_nodes_nodes_pb.NodeAdd.deserializeBinary(new Uint8Array(buffer_arg)); +} + function serialize_polykey_v1_nodes_NodeAddress(arg) { if (!(arg instanceof polykey_v1_nodes_nodes_pb.NodeAddress)) { throw new Error('Expected argument of type polykey.v1.nodes.NodeAddress'); @@ -528,10 +539,10 @@ nodesAdd: { path: '/polykey.v1.ClientService/NodesAdd', requestStream: false, responseStream: false, - requestType: polykey_v1_nodes_nodes_pb.NodeAddress, + requestType: polykey_v1_nodes_nodes_pb.NodeAdd, responseType: polykey_v1_utils_utils_pb.EmptyMessage, - requestSerialize: serialize_polykey_v1_nodes_NodeAddress, - requestDeserialize: deserialize_polykey_v1_nodes_NodeAddress, + requestSerialize: serialize_polykey_v1_nodes_NodeAdd, + requestDeserialize: deserialize_polykey_v1_nodes_NodeAdd, responseSerialize: serialize_polykey_v1_utils_EmptyMessage, responseDeserialize: deserialize_polykey_v1_utils_EmptyMessage, }, diff --git a/src/proto/js/polykey/v1/client_service_pb.js b/src/proto/js/polykey/v1/client_service_pb.js index 4adc8bd6d..68a9ebcb8 100644 --- a/src/proto/js/polykey/v1/client_service_pb.js +++ b/src/proto/js/polykey/v1/client_service_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/gestalts/gestalts_pb.js b/src/proto/js/polykey/v1/gestalts/gestalts_pb.js index 90435b3be..36b225293 100644 --- a/src/proto/js/polykey/v1/gestalts/gestalts_pb.js +++ b/src/proto/js/polykey/v1/gestalts/gestalts_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/identities/identities_pb.js b/src/proto/js/polykey/v1/identities/identities_pb.js index cbfb21ed9..a52a535f4 100644 --- a/src/proto/js/polykey/v1/identities/identities_pb.js +++ b/src/proto/js/polykey/v1/identities/identities_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/keys/keys_pb.js b/src/proto/js/polykey/v1/keys/keys_pb.js index dfbc1df0b..323ef8f16 100644 --- a/src/proto/js/polykey/v1/keys/keys_pb.js +++ b/src/proto/js/polykey/v1/keys/keys_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/nodes/nodes_pb.d.ts b/src/proto/js/polykey/v1/nodes/nodes_pb.d.ts index 79d0fbd58..09fb028eb 100644 --- a/src/proto/js/polykey/v1/nodes/nodes_pb.d.ts +++ b/src/proto/js/polykey/v1/nodes/nodes_pb.d.ts @@ -98,6 +98,38 @@ export namespace Claim { } } +export class NodeAdd extends jspb.Message { + getNodeId(): string; + setNodeId(value: string): NodeAdd; + + hasAddress(): boolean; + clearAddress(): void; + getAddress(): Address | undefined; + setAddress(value?: Address): NodeAdd; + getForce(): boolean; + setForce(value: boolean): NodeAdd; + getPing(): boolean; + setPing(value: boolean): NodeAdd; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): NodeAdd.AsObject; + static toObject(includeInstance: boolean, msg: NodeAdd): NodeAdd.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: NodeAdd, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): NodeAdd; + static deserializeBinaryFromReader(message: NodeAdd, reader: jspb.BinaryReader): NodeAdd; +} + +export namespace NodeAdd { + export type AsObject = { + nodeId: string, + address?: Address.AsObject, + force: boolean, + ping: boolean, + } +} + export class NodeBuckets extends jspb.Message { getBucketsMap(): jspb.Map; diff --git a/src/proto/js/polykey/v1/nodes/nodes_pb.js b/src/proto/js/polykey/v1/nodes/nodes_pb.js index 8fe0c189f..6dd70cdc3 100644 --- a/src/proto/js/polykey/v1/nodes/nodes_pb.js +++ b/src/proto/js/polykey/v1/nodes/nodes_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public @@ -24,6 +25,7 @@ goog.exportSymbol('proto.polykey.v1.nodes.Claims', null, global); goog.exportSymbol('proto.polykey.v1.nodes.Connection', null, global); goog.exportSymbol('proto.polykey.v1.nodes.CrossSign', null, global); goog.exportSymbol('proto.polykey.v1.nodes.Node', null, global); +goog.exportSymbol('proto.polykey.v1.nodes.NodeAdd', null, global); goog.exportSymbol('proto.polykey.v1.nodes.NodeAddress', null, global); goog.exportSymbol('proto.polykey.v1.nodes.NodeBuckets', null, global); goog.exportSymbol('proto.polykey.v1.nodes.NodeTable', null, global); @@ -113,6 +115,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.polykey.v1.nodes.Claim.displayName = 'proto.polykey.v1.nodes.Claim'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.polykey.v1.nodes.NodeAdd = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.polykey.v1.nodes.NodeAdd, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.polykey.v1.nodes.NodeAdd.displayName = 'proto.polykey.v1.nodes.NodeAdd'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -978,6 +1001,247 @@ proto.polykey.v1.nodes.Claim.prototype.setForceInvite = function(value) { +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.polykey.v1.nodes.NodeAdd.prototype.toObject = function(opt_includeInstance) { + return proto.polykey.v1.nodes.NodeAdd.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.polykey.v1.nodes.NodeAdd} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.polykey.v1.nodes.NodeAdd.toObject = function(includeInstance, msg) { + var f, obj = { + nodeId: jspb.Message.getFieldWithDefault(msg, 1, ""), + address: (f = msg.getAddress()) && proto.polykey.v1.nodes.Address.toObject(includeInstance, f), + force: jspb.Message.getBooleanFieldWithDefault(msg, 3, false), + ping: jspb.Message.getBooleanFieldWithDefault(msg, 4, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.polykey.v1.nodes.NodeAdd} + */ +proto.polykey.v1.nodes.NodeAdd.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.polykey.v1.nodes.NodeAdd; + return proto.polykey.v1.nodes.NodeAdd.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.polykey.v1.nodes.NodeAdd} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.polykey.v1.nodes.NodeAdd} + */ +proto.polykey.v1.nodes.NodeAdd.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setNodeId(value); + break; + case 2: + var value = new proto.polykey.v1.nodes.Address; + reader.readMessage(value,proto.polykey.v1.nodes.Address.deserializeBinaryFromReader); + msg.setAddress(value); + break; + case 3: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setForce(value); + break; + case 4: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setPing(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.polykey.v1.nodes.NodeAdd.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.polykey.v1.nodes.NodeAdd.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.polykey.v1.nodes.NodeAdd} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.polykey.v1.nodes.NodeAdd.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNodeId(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getAddress(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.polykey.v1.nodes.Address.serializeBinaryToWriter + ); + } + f = message.getForce(); + if (f) { + writer.writeBool( + 3, + f + ); + } + f = message.getPing(); + if (f) { + writer.writeBool( + 4, + f + ); + } +}; + + +/** + * optional string node_id = 1; + * @return {string} + */ +proto.polykey.v1.nodes.NodeAdd.prototype.getNodeId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.polykey.v1.nodes.NodeAdd} returns this + */ +proto.polykey.v1.nodes.NodeAdd.prototype.setNodeId = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional Address address = 2; + * @return {?proto.polykey.v1.nodes.Address} + */ +proto.polykey.v1.nodes.NodeAdd.prototype.getAddress = function() { + return /** @type{?proto.polykey.v1.nodes.Address} */ ( + jspb.Message.getWrapperField(this, proto.polykey.v1.nodes.Address, 2)); +}; + + +/** + * @param {?proto.polykey.v1.nodes.Address|undefined} value + * @return {!proto.polykey.v1.nodes.NodeAdd} returns this +*/ +proto.polykey.v1.nodes.NodeAdd.prototype.setAddress = function(value) { + return jspb.Message.setWrapperField(this, 2, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.polykey.v1.nodes.NodeAdd} returns this + */ +proto.polykey.v1.nodes.NodeAdd.prototype.clearAddress = function() { + return this.setAddress(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.polykey.v1.nodes.NodeAdd.prototype.hasAddress = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional bool force = 3; + * @return {boolean} + */ +proto.polykey.v1.nodes.NodeAdd.prototype.getForce = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.polykey.v1.nodes.NodeAdd} returns this + */ +proto.polykey.v1.nodes.NodeAdd.prototype.setForce = function(value) { + return jspb.Message.setProto3BooleanField(this, 3, value); +}; + + +/** + * optional bool ping = 4; + * @return {boolean} + */ +proto.polykey.v1.nodes.NodeAdd.prototype.getPing = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 4, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.polykey.v1.nodes.NodeAdd} returns this + */ +proto.polykey.v1.nodes.NodeAdd.prototype.setPing = function(value) { + return jspb.Message.setProto3BooleanField(this, 4, value); +}; + + + + + if (jspb.Message.GENERATE_TO_OBJECT) { /** * Creates an object representation of this proto. diff --git a/src/proto/js/polykey/v1/notifications/notifications_pb.js b/src/proto/js/polykey/v1/notifications/notifications_pb.js index f50f614f5..80794ae7f 100644 --- a/src/proto/js/polykey/v1/notifications/notifications_pb.js +++ b/src/proto/js/polykey/v1/notifications/notifications_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/permissions/permissions_pb.js b/src/proto/js/polykey/v1/permissions/permissions_pb.js index 53e129985..1b55e4f47 100644 --- a/src/proto/js/polykey/v1/permissions/permissions_pb.js +++ b/src/proto/js/polykey/v1/permissions/permissions_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/secrets/secrets_pb.js b/src/proto/js/polykey/v1/secrets/secrets_pb.js index 5008028d8..28d2e02ae 100644 --- a/src/proto/js/polykey/v1/secrets/secrets_pb.js +++ b/src/proto/js/polykey/v1/secrets/secrets_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/sessions/sessions_pb.js b/src/proto/js/polykey/v1/sessions/sessions_pb.js index c2d81541f..212d584bc 100644 --- a/src/proto/js/polykey/v1/sessions/sessions_pb.js +++ b/src/proto/js/polykey/v1/sessions/sessions_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/test_service_pb.js b/src/proto/js/polykey/v1/test_service_pb.js index f5ab8f2de..56dd0245c 100644 --- a/src/proto/js/polykey/v1/test_service_pb.js +++ b/src/proto/js/polykey/v1/test_service_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/utils/utils_pb.js b/src/proto/js/polykey/v1/utils/utils_pb.js index 852c0903d..39b5c869e 100644 --- a/src/proto/js/polykey/v1/utils/utils_pb.js +++ b/src/proto/js/polykey/v1/utils/utils_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/js/polykey/v1/vaults/vaults_pb.js b/src/proto/js/polykey/v1/vaults/vaults_pb.js index 6b793dc63..153565a46 100644 --- a/src/proto/js/polykey/v1/vaults/vaults_pb.js +++ b/src/proto/js/polykey/v1/vaults/vaults_pb.js @@ -2,6 +2,7 @@ /** * @fileoverview * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. * @suppress {messageConventions} JS Compiler reports an error if a variable or * field starts with 'MSG_' and isn't a translatable message. * @public diff --git a/src/proto/schemas/polykey/v1/client_service.proto b/src/proto/schemas/polykey/v1/client_service.proto index 81782f13b..9c90e0286 100644 --- a/src/proto/schemas/polykey/v1/client_service.proto +++ b/src/proto/schemas/polykey/v1/client_service.proto @@ -22,7 +22,7 @@ service ClientService { rpc AgentUnlock (polykey.v1.utils.EmptyMessage) returns (polykey.v1.utils.EmptyMessage); // Nodes - rpc NodesAdd(polykey.v1.nodes.NodeAddress) returns (polykey.v1.utils.EmptyMessage); + rpc NodesAdd(polykey.v1.nodes.NodeAdd) returns (polykey.v1.utils.EmptyMessage); rpc NodesPing(polykey.v1.nodes.Node) returns (polykey.v1.utils.StatusMessage); rpc NodesClaim(polykey.v1.nodes.Claim) returns (polykey.v1.utils.StatusMessage); rpc NodesFind(polykey.v1.nodes.Node) returns (polykey.v1.nodes.NodeAddress); diff --git a/src/proto/schemas/polykey/v1/nodes/nodes.proto b/src/proto/schemas/polykey/v1/nodes/nodes.proto index bd2b54f85..cd8b23785 100644 --- a/src/proto/schemas/polykey/v1/nodes/nodes.proto +++ b/src/proto/schemas/polykey/v1/nodes/nodes.proto @@ -25,6 +25,13 @@ message Claim { bool force_invite = 2; } +message NodeAdd { + string node_id = 1; + Address address = 2; + bool force = 3; + bool ping = 4; +} + // Bucket index -> a node bucket (from NodeGraph) message NodeBuckets { map buckets = 1; diff --git a/tests/bin/nodes/add.test.ts b/tests/bin/nodes/add.test.ts index 85b598786..b3bd7cc67 100644 --- a/tests/bin/nodes/add.test.ts +++ b/tests/bin/nodes/add.test.ts @@ -9,6 +9,7 @@ import { sysexits } from '@/utils'; import PolykeyAgent from '@/PolykeyAgent'; import * as nodesUtils from '@/nodes/utils'; import * as keysUtils from '@/keys/utils'; +import NodeManager from '@/nodes/NodeManager'; import * as testBinUtils from '../utils'; import * as testUtils from '../../utils'; import * as testNodesUtils from '../../nodes/utils'; @@ -20,12 +21,13 @@ describe('add', () => { const invalidNodeId = IdInternal.fromString('INVALIDID'); const validHost = '0.0.0.0'; const invalidHost = 'INVALIDHOST'; - const port = '55555'; + const port = 55555; let dataDir: string; let nodePath: string; let pkAgent: PolykeyAgent; let mockedGenerateKeyPair: jest.SpyInstance; let mockedGenerateDeterministicKeyPair: jest.SpyInstance; + let mockedPingNode: jest.SpyInstance; beforeAll(async () => { const globalKeyPair = await testUtils.setupGlobalKeypair(); mockedGenerateKeyPair = jest @@ -38,6 +40,7 @@ describe('add', () => { path.join(os.tmpdir(), 'polykey-test-'), ); nodePath = path.join(dataDir, 'polykey'); + mockedPingNode = jest.spyOn(NodeManager.prototype, 'pingNode'); // Cannot use the shared global agent since we can't 'un-add' a node pkAgent = await PolykeyAgent.createPolykeyAgent({ password, @@ -60,10 +63,22 @@ describe('add', () => { }); mockedGenerateKeyPair.mockRestore(); mockedGenerateDeterministicKeyPair.mockRestore(); + mockedPingNode.mockRestore(); + }); + beforeEach(async () => { + await pkAgent.nodeGraph.stop(); + await pkAgent.nodeGraph.start({ fresh: true }); + mockedPingNode.mockImplementation(() => true); }); test('adds a node', async () => { const { exitCode } = await testBinUtils.pkStdio( - ['nodes', 'add', nodesUtils.encodeNodeId(validNodeId), validHost, port], + [ + 'nodes', + 'add', + nodesUtils.encodeNodeId(validNodeId), + validHost, + `${port}`, + ], { PK_NODE_PATH: nodePath, PK_PASSWORD: password, @@ -81,11 +96,17 @@ describe('add', () => { dataDir, ); expect(stdout).toContain(validHost); - expect(stdout).toContain(port); + expect(stdout).toContain(`${port}`); }); test('fails to add a node (invalid node ID)', async () => { const { exitCode } = await testBinUtils.pkStdio( - ['nodes', 'add', nodesUtils.encodeNodeId(invalidNodeId), validHost, port], + [ + 'nodes', + 'add', + nodesUtils.encodeNodeId(invalidNodeId), + validHost, + `${port}`, + ], { PK_NODE_PATH: nodePath, PK_PASSWORD: password, @@ -96,7 +117,13 @@ describe('add', () => { }); test('fails to add a node (invalid IP address)', async () => { const { exitCode } = await testBinUtils.pkStdio( - ['nodes', 'add', nodesUtils.encodeNodeId(validNodeId), invalidHost, port], + [ + 'nodes', + 'add', + nodesUtils.encodeNodeId(validNodeId), + invalidHost, + `${port}`, + ], { PK_NODE_PATH: nodePath, PK_PASSWORD: password, @@ -105,4 +132,65 @@ describe('add', () => { ); expect(exitCode).toBe(sysexits.USAGE); }); + test('adds a node with --force flag', async () => { + const { exitCode } = await testBinUtils.pkStdio( + [ + 'nodes', + 'add', + '--force', + nodesUtils.encodeNodeId(validNodeId), + validHost, + `${port}`, + ], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + expect(exitCode).toBe(0); + // Checking if node was added. + const node = await pkAgent.nodeGraph.getNode(validNodeId); + expect(node?.address).toEqual({ host: validHost, port: port }); + }); + test('fails to add node when ping fails', async () => { + mockedPingNode.mockImplementation(() => false); + const { exitCode } = await testBinUtils.pkStdio( + [ + 'nodes', + 'add', + nodesUtils.encodeNodeId(validNodeId), + validHost, + `${port}`, + ], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + expect(exitCode).toBe(sysexits.NOHOST); + }); + test('adds a node with --no-ping flag', async () => { + mockedPingNode.mockImplementation(() => false); + const { exitCode } = await testBinUtils.pkStdio( + [ + 'nodes', + 'add', + '--no-ping', + nodesUtils.encodeNodeId(validNodeId), + validHost, + `${port}`, + ], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + expect(exitCode).toBe(0); + // Checking if node was added. + const node = await pkAgent.nodeGraph.getNode(validNodeId); + expect(node?.address).toEqual({ host: validHost, port: port }); + }); }); diff --git a/tests/bin/nodes/find.test.ts b/tests/bin/nodes/find.test.ts index 56bffd263..b60804c64 100644 --- a/tests/bin/nodes/find.test.ts +++ b/tests/bin/nodes/find.test.ts @@ -158,31 +158,37 @@ describe('find', () => { port: remoteOfflinePort, }); }); - test('fails to find an unknown node', async () => { - const unknownNodeId = nodesUtils.decodeNodeId( - 'vrcacp9vsb4ht25hds6s4lpp2abfaso0mptcfnh499n35vfcn2gkg', - ); - const { exitCode, stdout } = await testBinUtils.pkStdio( - [ - 'nodes', - 'find', - nodesUtils.encodeNodeId(unknownNodeId!), - '--format', - 'json', - ], - { - PK_NODE_PATH: nodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - expect(exitCode).toBe(sysexits.GENERAL); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: `Failed to find node ${nodesUtils.encodeNodeId(unknownNodeId!)}`, - id: nodesUtils.encodeNodeId(unknownNodeId!), - host: '', - port: 0, - }); - }); + test( + 'fails to find an unknown node', + async () => { + const unknownNodeId = nodesUtils.decodeNodeId( + 'vrcacp9vsb4ht25hds6s4lpp2abfaso0mptcfnh499n35vfcn2gkg', + ); + const { exitCode, stdout } = await testBinUtils.pkStdio( + [ + 'nodes', + 'find', + nodesUtils.encodeNodeId(unknownNodeId!), + '--format', + 'json', + ], + { + PK_NODE_PATH: nodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + expect(exitCode).toBe(sysexits.GENERAL); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: `Failed to find node ${nodesUtils.encodeNodeId( + unknownNodeId!, + )}`, + id: nodesUtils.encodeNodeId(unknownNodeId!), + host: '', + port: 0, + }); + }, + global.failedConnectionTimeout, + ); }); diff --git a/tests/client/service/nodesAdd.test.ts b/tests/client/service/nodesAdd.test.ts index f2c4969a0..f00e62566 100644 --- a/tests/client/service/nodesAdd.test.ts +++ b/tests/client/service/nodesAdd.test.ts @@ -163,13 +163,15 @@ describe('nodesAdd', () => { const addressMessage = new nodesPB.Address(); addressMessage.setHost('127.0.0.1'); addressMessage.setPort(11111); - const request = new nodesPB.NodeAddress(); + const request = new nodesPB.NodeAdd(); request.setNodeId('vrsc24a1er424epq77dtoveo93meij0pc8ig4uvs9jbeld78n9nl0'); request.setAddress(addressMessage); const response = await grpcClient.nodesAdd( request, clientUtils.encodeAuthFromPassword(password), ); + request.setPing(false); + request.setForce(false); expect(response).toBeInstanceOf(utilsPB.EmptyMessage); const result = await nodeGraph.getNode( nodesUtils.decodeNodeId( @@ -184,7 +186,9 @@ describe('nodesAdd', () => { const addressMessage = new nodesPB.Address(); addressMessage.setHost(''); addressMessage.setPort(11111); - const request = new nodesPB.NodeAddress(); + const request = new nodesPB.NodeAdd(); + request.setPing(false); + request.setForce(false); request.setNodeId('vrsc24a1er424epq77dtoveo93meij0pc8ig4uvs9jbeld78n9nl0'); request.setAddress(addressMessage); await expectRemoteError( diff --git a/tests/nodes/NodeConnectionManager.general.test.ts b/tests/nodes/NodeConnectionManager.general.test.ts index f0fe65d4e..17035b4dd 100644 --- a/tests/nodes/NodeConnectionManager.general.test.ts +++ b/tests/nodes/NodeConnectionManager.general.test.ts @@ -141,7 +141,10 @@ describe(`${NodeConnectionManager.name} general test`, () => { password, nodePath: path.join(dataDir2, 'remoteNode1'), networkConfig: { - proxyHost: '127.0.0.1' as Host, + proxyHost: localHost, + agentHost: localHost, + clientHost: localHost, + forwardHost: localHost, }, logger: logger.getChild('remoteNode1'), }); @@ -150,7 +153,10 @@ describe(`${NodeConnectionManager.name} general test`, () => { password, nodePath: path.join(dataDir2, 'remoteNode2'), networkConfig: { - proxyHost: '127.0.0.1' as Host, + proxyHost: localHost, + agentHost: localHost, + clientHost: localHost, + forwardHost: localHost, }, logger: logger.getChild('remoteNode2'), }); @@ -246,7 +252,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { // Case 1: node already exists in the local node graph (no contact required) const nodeId = nodeId1; const nodeAddress: NodeAddress = { - host: '127.0.0.1' as Host, + host: localHost, port: 11111 as Port, }; await nodeGraph.setNode(nodeId, nodeAddress); @@ -261,6 +267,11 @@ describe(`${NodeConnectionManager.name} general test`, () => { test( 'finds node (contacts remote node)', async () => { + const mockedPingNode = jest.spyOn( + NodeConnectionManager.prototype, + 'pingNode', + ); + mockedPingNode.mockImplementation(async () => true); // NodeConnectionManager under test const nodeConnectionManager = new NodeConnectionManager({ keyManager, @@ -274,14 +285,17 @@ describe(`${NodeConnectionManager.name} general test`, () => { // Case 2: node can be found on the remote node const nodeId = nodeId1; const nodeAddress: NodeAddress = { - host: '127.0.0.1' as Host, + host: localHost, port: 11111 as Port, }; const server = await PolykeyAgent.createPolykeyAgent({ nodePath: path.join(dataDir, 'node2'), password, networkConfig: { - proxyHost: '127.0.0.1' as Host, + proxyHost: localHost, + agentHost: localHost, + clientHost: localHost, + forwardHost: localHost, }, logger: nodeConnectionManagerLogger, }); @@ -296,6 +310,7 @@ describe(`${NodeConnectionManager.name} general test`, () => { await server.stop(); } finally { await nodeConnectionManager.stop(); + mockedPingNode.mockRestore(); } }, global.polykeyStartupTimeout, @@ -319,7 +334,10 @@ describe(`${NodeConnectionManager.name} general test`, () => { nodePath: path.join(dataDir, 'node3'), password, networkConfig: { - proxyHost: '127.0.0.1' as Host, + proxyHost: localHost, + agentHost: localHost, + clientHost: localHost, + forwardHost: localHost, }, logger: nodeConnectionManagerLogger, }); @@ -355,7 +373,10 @@ describe(`${NodeConnectionManager.name} general test`, () => { logger: logger.getChild('serverPKAgent'), nodePath: path.join(dataDir, 'serverPKAgent'), networkConfig: { - proxyHost: '127.0.0.1' as Host, + proxyHost: localHost, + agentHost: localHost, + clientHost: localHost, + forwardHost: localHost, }, }); nodeConnectionManager = new NodeConnectionManager({ diff --git a/tests/nodes/NodeConnectionManager.seednodes.test.ts b/tests/nodes/NodeConnectionManager.seednodes.test.ts index e6d91f399..63ba90e9d 100644 --- a/tests/nodes/NodeConnectionManager.seednodes.test.ts +++ b/tests/nodes/NodeConnectionManager.seednodes.test.ts @@ -193,6 +193,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { // Seed nodes test('starting should add seed nodes to the node graph', async () => { let nodeConnectionManager: NodeConnectionManager | undefined; + let nodeManager: NodeManager | undefined; try { nodeConnectionManager = new NodeConnectionManager({ keyManager, @@ -204,7 +205,17 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { seedNodes: dummySeedNodes, logger: logger, }); - await nodeConnectionManager.start({ nodeManager: dummyNodeManager }); + nodeManager = new NodeManager({ + db, + keyManager, + logger, + nodeConnectionManager, + nodeGraph, + queue: {} as Queue, + sigchain: {} as Sigchain, + }); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); const seedNodes = nodeConnectionManager.getSeedNodes(); expect(seedNodes).toContainEqual(nodeId1); expect(seedNodes).toContainEqual(nodeId2); @@ -216,6 +227,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { } finally { // Clean up await nodeConnectionManager?.stop(); + await nodeManager?.stop(); } }); test('should get seed nodes', async () => { @@ -250,6 +262,11 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { 'refreshBucket', ); mockedRefreshBucket.mockImplementation(async () => {}); + const mockedPingNode = jest.spyOn( + NodeConnectionManager.prototype, + 'pingNode', + ); + mockedPingNode.mockImplementation(async () => true); try { const seedNodes: SeedNodes = {}; seedNodes[nodesUtils.encodeNodeId(remoteNodeId1)] = { @@ -295,6 +312,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { expect(await nodeGraph.getNode(dummyNodeId)).toBeUndefined(); } finally { mockedRefreshBucket.mockRestore(); + mockedPingNode.mockRestore(); await nodeManager?.stop(); await nodeConnectionManager?.stop(); await queue?.stop(); @@ -309,6 +327,11 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { 'refreshBucket', ); mockedRefreshBucket.mockImplementation(async () => {}); + const mockedPingNode = jest.spyOn( + NodeConnectionManager.prototype, + 'pingNode', + ); + mockedPingNode.mockImplementation(async () => true); try { const seedNodes: SeedNodes = {}; seedNodes[nodesUtils.encodeNodeId(remoteNodeId1)] = { @@ -353,6 +376,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { expect(mockedRefreshBucket).toHaveBeenCalled(); } finally { mockedRefreshBucket.mockRestore(); + mockedPingNode.mockRestore(); await nodeManager?.stop(); await nodeConnectionManager?.stop(); await queue?.stop(); @@ -367,6 +391,11 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { 'refreshBucket', ); mockedRefreshBucket.mockImplementation(async () => {}); + const mockedPingNode = jest.spyOn( + NodeConnectionManager.prototype, + 'pingNode', + ); + mockedPingNode.mockImplementation(async () => true); try { const seedNodes: SeedNodes = {}; seedNodes[nodesUtils.encodeNodeId(remoteNodeId1)] = { @@ -419,6 +448,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { expect(await nodeGraph.getNode(nodeId2)).toBeDefined(); } finally { mockedRefreshBucket.mockRestore(); + mockedPingNode.mockRestore(); await nodeConnectionManager?.stop(); await nodeManager?.stop(); await queue?.stop(); @@ -440,6 +470,11 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { host: remoteNode2.proxy.getProxyHost(), port: remoteNode2.proxy.getProxyPort(), }; + const mockedPingNode = jest.spyOn( + NodeConnectionManager.prototype, + 'pingNode', + ); + mockedPingNode.mockImplementation(async () => true); try { logger.setLevel(LogLevel.WARN); node1 = await PolykeyAgent.createPolykeyAgent({ @@ -499,6 +534,7 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => { expect(node2Nodes).toContain(nodeIdR2); expect(node2Nodes).toContain(nodeId1); } finally { + mockedPingNode.mockRestore(); logger.setLevel(LogLevel.WARN); await node1?.stop(); await node1?.destroy(); From b3766b64a0785a976c3df5f01c964530b4301989 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 9 Jun 2022 13:58:58 +1000 Subject: [PATCH 109/137] fix: small fixes to nodes utils parsing functions --- src/nodes/NodeGraph.ts | 31 ++++++++++++++----------------- src/nodes/utils.ts | 41 ++++++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/src/nodes/NodeGraph.ts b/src/nodes/NodeGraph.ts index c9ebaf0f3..6bd6b2f2d 100644 --- a/src/nodes/NodeGraph.ts +++ b/src/nodes/NodeGraph.ts @@ -1,4 +1,4 @@ -import type { DB, DBTransaction, LevelPath } from '@matrixai/db'; +import type { DB, DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; import type { NodeId, NodeAddress, @@ -191,14 +191,14 @@ class NodeGraph { }); } - for await (const [key, nodeData] of tran.iterator( + for await (const [keyPath, nodeData] of tran.iterator( { reverse: order !== 'asc', valueAsBuffer: false, }, this.nodeGraphBucketsDbPath, )) { - const { nodeId } = nodesUtils.parseBucketsDbKey(key as Array); + const { nodeId } = nodesUtils.parseBucketsDbKey(keyPath); yield [nodeId, nodeData]; } } @@ -273,13 +273,11 @@ class NodeGraph { const bucketKey = nodesUtils.bucketKey(bucketIndex); // Remove the oldest entry in the bucket const oldestNodeIds: Array = []; - for await (const [key] of tran.iterator({ limit }, [ + for await (const [keyPath] of tran.iterator({ limit }, [ ...this.nodeGraphLastUpdatedDbPath, bucketKey, ])) { - const { nodeId } = nodesUtils.parseLastUpdatedBucketDbKey( - key as Array, - ); + const { nodeId } = nodesUtils.parseLastUpdatedBucketDbKey(keyPath); oldestNodeIds.push(nodeId); } return oldestNodeIds; @@ -421,7 +419,7 @@ class NodeGraph { this.nodeGraphBucketsDbPath, )) { const { bucketIndex: bucketIndex_, nodeId } = - nodesUtils.parseBucketsDbKey(key as Array); + nodesUtils.parseBucketsDbKey(key); if (bucketIndex == null) { // First entry of the first bucket bucketIndex = bucketIndex_; @@ -467,7 +465,7 @@ class NodeGraph { this.nodeGraphLastUpdatedDbPath, )) { const { bucketIndex: bucketIndex_, nodeId } = - nodesUtils.parseLastUpdatedBucketsDbKey(key as Array); + nodesUtils.parseLastUpdatedBucketsDbKey(key); bucketsDbIterator.seek([key[0], key[2]]); // @ts-ignore // eslint-disable-next-line @@ -535,7 +533,7 @@ class NodeGraph { )) { // The key is a combined bucket key and node ID const { bucketIndex: bucketIndexOld, nodeId } = - nodesUtils.parseBucketsDbKey(key as Array); + nodesUtils.parseBucketsDbKey(key); const nodeIdEncoded = nodesUtils.encodeNodeId(nodeId); const nodeIdKey = nodesUtils.bucketDbKey(nodeId); // If the new own node ID is one of the existing node IDs, it is just dropped @@ -555,7 +553,7 @@ class NodeGraph { if (countNew < this.nodeBucketLimit) { await tran.put([...metaPathNew, 'count'], countNew + 1); } else { - let oldestIndexKey: Array | undefined = undefined; + let oldestIndexKey: KeyPath | undefined = undefined; let oldestNodeId: NodeId | undefined = undefined; for await (const [key] of tran.iterator( { @@ -563,10 +561,9 @@ class NodeGraph { }, indexPathNew, )) { - oldestIndexKey = key as Array; - ({ nodeId: oldestNodeId } = nodesUtils.parseLastUpdatedBucketDbKey( - key as Array, - )); + oldestIndexKey = key; + ({ nodeId: oldestNodeId } = + nodesUtils.parseLastUpdatedBucketDbKey(key)); } await tran.del([ ...bucketPathNew, @@ -730,7 +727,7 @@ class NodeGraph { }, this.nodeGraphBucketsDbPath, )) { - const info = nodesUtils.parseBucketsDbKey(key as Array); + const info = nodesUtils.parseBucketsDbKey(key); nodeIds.push([info.nodeId, nodeData]); } } @@ -754,7 +751,7 @@ class NodeGraph { }, this.nodeGraphBucketsDbPath, )) { - const info = nodesUtils.parseBucketsDbKey(key as Array); + const info = nodesUtils.parseBucketsDbKey(key); nodeIds.push([info.nodeId, nodeData]); } } diff --git a/src/nodes/utils.ts b/src/nodes/utils.ts index 0078ef784..1fe3c799d 100644 --- a/src/nodes/utils.ts +++ b/src/nodes/utils.ts @@ -1,9 +1,10 @@ import type { - NodeId, - NodeIdEncoded, NodeBucket, NodeBucketIndex, + NodeId, + NodeIdEncoded, } from './types'; +import type { KeyPath } from '@matrixai/db'; import { IdInternal } from '@matrixai/id'; import lexi from 'lexicographic-integer'; import { utils as dbUtils } from '@matrixai/db'; @@ -143,18 +144,18 @@ function lastUpdatedKey(lastUpdated: number): Buffer { * The keys look like `!!` * It is assumed that the `!` is the sublevel prefix. */ -function parseBucketsDbKey(keyBufferArray: Array): { +function parseBucketsDbKey(keyPath: KeyPath): { bucketIndex: NodeBucketIndex; bucketKey: string; nodeId: NodeId; } { - const [bucketKeyBuffer, nodeIdBuffer] = keyBufferArray; - if (bucketKeyBuffer == null || nodeIdBuffer == null) { + const [bucketKeyPath, nodeIdKey] = keyPath; + if (bucketKeyPath == null || nodeIdKey == null) { throw new TypeError('Buffer is not an NodeGraph buckets key'); } - const bucketKey = bucketKeyBuffer.toString(); + const bucketKey = bucketKeyPath.toString(); const bucketIndex = lexi.unpack(bucketKey); - const nodeId = IdInternal.fromBuffer(nodeIdBuffer); + const nodeId = IdInternal.fromBuffer(Buffer.from(nodeIdKey)); return { bucketIndex, bucketKey, @@ -167,8 +168,7 @@ function parseBucketsDbKey(keyBufferArray: Array): { * The keys look like `` */ function parseBucketDbKey(keyBuffer: Buffer): NodeId { - const nodeId = IdInternal.fromBuffer(keyBuffer); - return nodeId; + return IdInternal.fromBuffer(keyBuffer); } /** @@ -176,24 +176,23 @@ function parseBucketDbKey(keyBuffer: Buffer): NodeId { * The keys look like `!!-` * It is assumed that the `!` is the sublevel prefix. */ -function parseLastUpdatedBucketsDbKey(keyBufferArray: Array): { +function parseLastUpdatedBucketsDbKey(keyPath: KeyPath): { bucketIndex: NodeBucketIndex; bucketKey: string; lastUpdated: number; nodeId: NodeId; } { - const [bucketKeyBuffer, ...lastUpdatedBufferArray] = keyBufferArray; - if (bucketKeyBuffer == null || lastUpdatedBufferArray == null) { + const [bucketLevel, ...lastUpdatedKeyPath] = keyPath; + if (bucketLevel == null || lastUpdatedKeyPath == null) { throw new TypeError('Buffer is not an NodeGraph index key'); } - const bucketKey = bucketKeyBuffer.toString(); + const bucketKey = bucketLevel.toString(); const bucketIndex = lexi.unpack(bucketKey); if (bucketIndex == null) { throw new TypeError('Buffer is not an NodeGraph index key'); } - const { lastUpdated, nodeId } = parseLastUpdatedBucketDbKey( - lastUpdatedBufferArray, - ); + const { lastUpdated, nodeId } = + parseLastUpdatedBucketDbKey(lastUpdatedKeyPath); return { bucketIndex, bucketKey, @@ -207,19 +206,19 @@ function parseLastUpdatedBucketsDbKey(keyBufferArray: Array): { * The keys look like `-` * It is assumed that the `!` is the sublevel prefix. */ -function parseLastUpdatedBucketDbKey(keyBufferArray: Array): { +function parseLastUpdatedBucketDbKey(keyPath: KeyPath): { lastUpdated: number; nodeId: NodeId; } { - const [lastUpdatedBuffer, nodeIdBuffer] = keyBufferArray; - if (lastUpdatedBuffer == null || nodeIdBuffer == null) { + const [lastUpdatedLevel, nodeIdKey] = keyPath; + if (lastUpdatedLevel == null || nodeIdKey == null) { throw new TypeError('Buffer is not an NodeGraph index bucket key'); } - const lastUpdated = lexi.unpack(lastUpdatedBuffer.toString()); + const lastUpdated = lexi.unpack(lastUpdatedLevel.toString()); if (lastUpdated == null) { throw new TypeError('Buffer is not an NodeGraph index bucket key'); } - const nodeId = IdInternal.fromBuffer(nodeIdBuffer); + const nodeId = IdInternal.fromBuffer(Buffer.from(nodeIdKey)); return { lastUpdated, nodeId, From 19f4796a934f359b74caf30102b6821a24ede6b2 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 9 Jun 2022 18:14:01 +1000 Subject: [PATCH 110/137] tests: expanding tests for root keypair changing Added some tests to check that a root keyPair change propagates properly. Also added tests for the change for existing and new node connections. #317 --- tests/PolykeyAgent.test.ts | 74 ++++++ tests/nodes/NodeConnection.test.ts | 362 +++++++++++++++++++++++++++++ 2 files changed, 436 insertions(+) diff --git a/tests/PolykeyAgent.test.ts b/tests/PolykeyAgent.test.ts index 9423050ab..7cb1f2fc7 100644 --- a/tests/PolykeyAgent.test.ts +++ b/tests/PolykeyAgent.test.ts @@ -1,4 +1,5 @@ import type { StateVersion } from '@/schema/types'; +import type { KeyManagerChangeData } from '@/keys/types'; import os from 'os'; import path from 'path'; import fs from 'fs'; @@ -9,6 +10,7 @@ import { Status } from '@/status'; import { Schema } from '@/schema'; import * as errors from '@/errors'; import config from '@/config'; +import { promise } from '@/utils/index'; import * as testUtils from './utils'; describe('PolykeyAgent', () => { @@ -175,4 +177,76 @@ describe('PolykeyAgent', () => { }), ).rejects.toThrow(errors.ErrorSchemaVersionTooOld); }); + test('renewRootKeyPair change event propagates', async () => { + const nodePath = `${dataDir}/polykey`; + let pkAgent: PolykeyAgent | undefined; + try { + pkAgent = await PolykeyAgent.createPolykeyAgent({ + password, + nodePath, + logger, + }); + const prom = promise(); + pkAgent.events.on( + PolykeyAgent.eventSymbols.KeyManager, + async (data: KeyManagerChangeData) => { + prom.resolveP(data); + }, + ); + await pkAgent.keyManager.renewRootKeyPair(password); + + await expect(prom.p).resolves.toBeDefined(); + } finally { + await pkAgent?.stop(); + await pkAgent?.destroy(); + } + }); + test('resetRootKeyPair change event propagates', async () => { + const nodePath = `${dataDir}/polykey`; + let pkAgent: PolykeyAgent | undefined; + try { + pkAgent = await PolykeyAgent.createPolykeyAgent({ + password, + nodePath, + logger, + }); + const prom = promise(); + pkAgent.events.on( + PolykeyAgent.eventSymbols.KeyManager, + async (data: KeyManagerChangeData) => { + prom.resolveP(data); + }, + ); + await pkAgent.keyManager.resetRootKeyPair(password); + + await expect(prom.p).resolves.toBeDefined(); + } finally { + await pkAgent?.stop(); + await pkAgent?.destroy(); + } + }); + test('resetRootCert change event propagates', async () => { + const nodePath = `${dataDir}/polykey`; + let pkAgent: PolykeyAgent | undefined; + try { + pkAgent = await PolykeyAgent.createPolykeyAgent({ + password, + nodePath, + logger, + }); + const prom = promise(); + pkAgent.events.on( + PolykeyAgent.eventSymbols.KeyManager, + async (data: KeyManagerChangeData) => { + prom.resolveP(data); + }, + ); + await pkAgent.keyManager.resetRootCert(); + + await expect(prom.p).resolves.toBeDefined(); + } finally { + await pkAgent?.stop(); + await pkAgent?.destroy(); + } + }); }); diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index dbd95397e..b5bac69e5 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -174,6 +174,13 @@ describe(`${NodeConnection.name} test`, () => { }; } + const newTlsConfig = async (keyManager: KeyManager): Promise => { + return { + keyPrivatePem: keyManager.getRootKeyPairPem().privateKey, + certChainPem: await keyManager.getRootCertChainPem(), + }; + }; + beforeEach(async () => { // Server setup serverDataDir = await fs.promises.mkdtemp( @@ -852,4 +859,359 @@ describe(`${NodeConnection.name} test`, () => { }, global.defaultTimeout * 2, ); + + test('existing connection handles a resetRootKeyPair on sending side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await clientKeyManager.resetRootKeyPair(password); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('existing connection handles a renewRootKeyPair on sending side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await clientKeyManager.renewRootKeyPair(password); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('existing connection handles a resetRootCert on sending side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await clientKeyManager.resetRootCert(); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('existing connection handles a resetRootKeyPair on receiving side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await serverKeyManager.resetRootKeyPair(password); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('existing connection handles a renewRootKeyPair on receiving side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await serverKeyManager.renewRootKeyPair(password); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('existing connection handles a resetRootCert on receiving side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await serverKeyManager.resetRootCert(); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a resetRootKeyPair on sending side', async () => { + let conn: NodeConnection | undefined; + try { + // Simulate key change + await clientKeyManager.resetRootKeyPair(password); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a renewRootKeyPair on sending side', async () => { + let conn: NodeConnection | undefined; + try { + // Simulate key change + await clientKeyManager.renewRootKeyPair(password); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a resetRootCert on sending side', async () => { + let conn: NodeConnection | undefined; + try { + // Simulate key change + await clientKeyManager.resetRootCert(); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a resetRootKeyPair on receiving side', async () => { + // Simulate key change + await serverKeyManager.resetRootKeyPair(password); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + const connProm = NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + await expect(connProm).rejects.toThrow( + nodesErrors.ErrorNodeConnectionTimeout, + ); + + // Connect with the new NodeId + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: serverKeyManager.getNodeId(), + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a renewRootKeyPair on receiving side', async () => { + let conn: NodeConnection | undefined; + try { + // Simulate key change + await serverKeyManager.renewRootKeyPair(password); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a resetRootCert on receiving side', async () => { + let conn: NodeConnection | undefined; + try { + // Simulate key change + await serverKeyManager.resetRootCert(); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); }); From 551b7b625024141ed77f91f2104c95cd10f2d502 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 10 Jun 2022 16:26:23 +1000 Subject: [PATCH 111/137] build: updating package-lock.json --- package-lock.json | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8674bf340..97cd45f6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,7 +54,7 @@ "@types/jest": "^27.0.2", "@types/nexpect": "^0.4.31", "@types/node": "^16.11.7", - "@types/node-forge": "^0.9.7", + "@types/node-forge": "^0.10.4", "@types/pako": "^1.0.2", "@types/prompts": "^2.0.13", "@types/readable-stream": "^2.3.11", @@ -2645,9 +2645,10 @@ "license": "MIT" }, "node_modules/@types/node-forge": { - "version": "0.9.10", + "version": "0.10.10", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-0.10.10.tgz", + "integrity": "sha512-iixn5bedlE9fm/5mN7fPpXraXlxCVrnNWHZekys8c5fknridLVWGnNRqlaWpenwaijIuB3bNI0lEOm+JD6hZUA==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -12378,7 +12379,9 @@ "version": "16.11.35" }, "@types/node-forge": { - "version": "0.9.10", + "version": "0.10.10", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-0.10.10.tgz", + "integrity": "sha512-iixn5bedlE9fm/5mN7fPpXraXlxCVrnNWHZekys8c5fknridLVWGnNRqlaWpenwaijIuB3bNI0lEOm+JD6hZUA==", "dev": true, "requires": { "@types/node": "*" From 9900d7afc6d1cc7aa1349658e14ca8b8d0a8d7a2 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 10 Jun 2022 17:23:17 +1000 Subject: [PATCH 112/137] fix: removed unneeded timer from NodeConnection test --- tests/nodes/NodeConnection.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index b5bac69e5..beeb841ed 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -1152,7 +1152,6 @@ describe(`${NodeConnection.name} test`, () => { logger: logger, clientFactory: async (args) => GRPCClientAgent.createGRPCClientAgent(args), - timer: timerStart(2000), }); const client = conn.getClient(); await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); From fcfaa01c9bad43d5d92e52b10c225aa02b623428 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Mon, 6 Jun 2022 15:57:22 +1000 Subject: [PATCH 113/137] ci: staging branch and CI/CD changes --- .eslintrc | 2 +- .github/workflows/codesee-arch-diagram.yml | 87 ++++ .gitignore | 5 + .gitlab-ci.yml | 548 +++++++++++++++++---- .npmignore | 7 +- README.md | 3 +- default.nix | 28 +- jest.config.js | 47 +- nix/leveldown.patch | 14 - package-lock.json | 143 ++++++ package.json | 20 +- release.nix | 71 +-- scripts/pkg.js | 174 +++++++ scripts/test-pipelines.sh | 62 ++- shell.nix | 13 +- utils.nix | 49 +- 16 files changed, 1021 insertions(+), 252 deletions(-) create mode 100644 .github/workflows/codesee-arch-diagram.yml delete mode 100644 nix/leveldown.patch create mode 100755 scripts/pkg.js diff --git a/.eslintrc b/.eslintrc index bc8d334e5..277fc3956 100644 --- a/.eslintrc +++ b/.eslintrc @@ -26,7 +26,7 @@ "no-useless-catch": 1, "no-prototype-builtins": 1, "no-constant-condition": 0, - "no-useless-escape" : 0, + "no-useless-escape": 0, "no-console": "error", "require-yield": 0, "eqeqeq": ["error", "smart"], diff --git a/.github/workflows/codesee-arch-diagram.yml b/.github/workflows/codesee-arch-diagram.yml new file mode 100644 index 000000000..fe56ca3f8 --- /dev/null +++ b/.github/workflows/codesee-arch-diagram.yml @@ -0,0 +1,87 @@ +on: + push: + branches: + - master + pull_request_target: + types: [opened, synchronize, reopened] + +name: CodeSee Map + +jobs: + test_map_action: + runs-on: ubuntu-latest + continue-on-error: true + name: Run CodeSee Map Analysis + steps: + - name: checkout + id: checkout + uses: actions/checkout@v2 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + fetch-depth: 0 + + # codesee-detect-languages has an output with id languages. + - name: Detect Languages + id: detect-languages + uses: Codesee-io/codesee-detect-languages-action@latest + + - name: Configure JDK 16 + uses: actions/setup-java@v2 + if: ${{ fromJSON(steps.detect-languages.outputs.languages).java }} + with: + java-version: '16' + distribution: 'zulu' + + # CodeSee Maps Go support uses a static binary so there's no setup step required. + + - name: Configure Node.js 14 + uses: actions/setup-node@v2 + if: ${{ fromJSON(steps.detect-languages.outputs.languages).javascript }} + with: + node-version: '14' + + - name: Configure Python 3.x + uses: actions/setup-python@v2 + if: ${{ fromJSON(steps.detect-languages.outputs.languages).python }} + with: + python-version: '3.10' + architecture: 'x64' + + - name: Configure Ruby '3.x' + uses: ruby/setup-ruby@v1 + if: ${{ fromJSON(steps.detect-languages.outputs.languages).ruby }} + with: + ruby-version: '3.0' + + # We need the rust toolchain because it uses rustc and cargo to inspect the package + - name: Configure Rust 1.x stable + uses: actions-rs/toolchain@v1 + if: ${{ fromJSON(steps.detect-languages.outputs.languages).rust }} + with: + toolchain: stable + + - name: Generate Map + id: generate-map + uses: Codesee-io/codesee-map-action@latest + with: + step: map + api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }} + github_ref: ${{ github.ref }} + languages: ${{ steps.detect-languages.outputs.languages }} + + - name: Upload Map + id: upload-map + uses: Codesee-io/codesee-map-action@latest + with: + step: mapUpload + api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }} + github_ref: ${{ github.ref }} + + - name: Insights + id: insights + uses: Codesee-io/codesee-map-action@latest + with: + step: insights + api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }} + github_ref: ${{ github.ref }} diff --git a/.gitignore b/.gitignore index cd3216165..78a1b31bb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,13 @@ /dist .env* !.env.example +# nix /result* /builds +# node-gyp +/build +# prebuildify +/prebuilds # Logs logs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 11a1eb825..9742adbca 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,85 +1,253 @@ +workflow: + rules: + # Disable merge request pipelines + - if: $CI_MERGE_REQUEST_ID + when: never + - when: always + +default: + interruptible: true + variables: - GIT_SUBMODULE_STRATEGY: "recursive" + GH_PROJECT_PATH: "MatrixAI/${CI_PROJECT_NAME}" + GH_PROJECT_URL: "https://${GITHUB_TOKEN}@github.com/${GH_PROJECT_PATH}.git" + GIT_SUBMODULE_STRATEGY: recursive # Cache .npm - NPM_CONFIG_CACHE: "./tmp/npm" + NPM_CONFIG_CACHE: "${CI_PROJECT_DIR}/tmp/npm" # Prefer offline node module installation NPM_CONFIG_PREFER_OFFLINE: "true" # `ts-node` has its own cache - # It must use an absolute path, otherwise ts-node calls will CWD TS_CACHED_TRANSPILE_CACHE: "${CI_PROJECT_DIR}/tmp/ts-node-cache" TS_CACHED_TRANSPILE_PORTABLE: "true" + # Homebrew cache only used by macos runner + HOMEBREW_CACHE: "${CI_PROJECT_DIR}/tmp/Homebrew" -# Cached directories shared between jobs & pipelines per-branch +# Cached directories shared between jobs & pipelines per-branch per-runner cache: key: $CI_COMMIT_REF_SLUG paths: - ./tmp/npm/ - ./tmp/ts-node-cache/ + # Homebrew cache is only used by the macos runner + - ./tmp/Homebrew # `jest` cache is configured in jest.config.js - ./tmp/jest/ stages: - - check - - test - - build - - quality - - release - -lint: - image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner + - check # Linting, unit tests + - build # Cross-platform library compilation, unit tests + - integration # Cross-platform application bundling, integration tests, and pre-release + - release # Cross-platform distribution and deployment + +image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner + +check:lint: stage: check - interruptible: true + needs: [] script: - > - nix-shell -I nixpkgs=./pkgs.nix --packages nodejs --run ' - npm ci; + nix-shell --run ' npm run lint; ' + rules: + # Runs on feature and staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH =~ /^(?:feature.*|staging)$/ && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Manually run on commits other than master and ignore version commits + - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != 'master' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + when: manual -nix-dry: +check:nix-dry: stage: check - image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner + needs: [] script: - - nix-build -v -v --dry-run ./release.nix --attr application - - nix-build -v -v --dry-run ./release.nix --attr docker - - nix-build -v -v --dry-run ./release.nix --attr package.linux.x64.elf - - nix-build -v -v --dry-run ./release.nix --attr package.windows.x64.exe - - nix-build -v -v --dry-run ./release.nix --attr package.macos.x64.macho + - nix-build -v -v --dry-run ./release.nix + rules: + # Runs on feature and staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH =~ /^(?:feature.*|staging)$/ && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Manually run on commits other than master and ignore version commits + - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != 'master' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + when: manual -test-generate: - image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner +check:test-generate: stage: check interruptible: true script: - mkdir -p ./tmp - > - nix-shell -I nixpkgs=./pkgs.nix --packages bash --run ' + nix-shell --run ' ./scripts/test-pipelines.sh > ./tmp/test-pipelines.yml ' artifacts: + when: always paths: - ./tmp/test-pipelines.yml + rules: + # Runs on feature and staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH =~ /^(?:feature.*|staging)$/ && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Manually run on commits other than master and ignore version commits + - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != 'master' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + when: manual -test: - stage: test - # Don't implicitly inherit top-level variables in child pipeline - # All inherited variables should be explicitly defined here - # Note that variables defined here override any variables defined in the child pipeline - # This causes a bug with $CI_PROJECT_DIR, which is expanded into an empty string +check:test: + stage: check + needs: + - check:test-generate inherit: variables: false trigger: include: - artifact: tmp/test-pipelines.yml - job: test-generate + job: check:test-generate strategy: depend + rules: + # Runs on feature and staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH =~ /^(?:feature.*|staging)$/ && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Manually run on commits other than master and ignore version commits + - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != 'master' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + when: manual + +build:merge: + stage: build + needs: [] + allow_failure: true + script: + # Required for `gh pr create` + - git remote add upstream "$GH_PROJECT_URL" + - > + nix-shell -I nixpkgs=./pkgs.nix --packages gitAndTools.gh --run ' + gh pr create \ + --head staging \ + --base master \ + --title "ci: merge staging to master" \ + --body "This is an automatic PR generated by the pipeline CI/CD. This will be automatically fast-forward merged if successful." \ + --assignee "@me" \ + --no-maintainer-edit \ + --repo "$GH_PROJECT_PATH" || true; + printf "Pipeline Attempt on ${CI_PIPELINE_ID} for ${CI_COMMIT_SHA}\n\n${CI_PIPELINE_URL}" \ + | gh pr comment staging \ + --body-file - \ + --repo "$GH_PROJECT_PATH"; + ' + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +build:linux: + stage: build + needs: [] + script: + - > + nix-shell --run ' + npm run build --verbose; + ' + artifacts: + when: always + paths: + # Only the build:linux preserves the dist + - ./dist + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +build:windows: + stage: build + needs: [] + tags: + - windows + before_script: + - choco install nodejs --version=16.14.2 -y + - refreshenv + script: + - npm config set msvs_version 2019 + - npm install --ignore-scripts + - $env:Path = "$(npm bin);" + $env:Path + - npm run build --verbose + # - npm test -- --ci + # artifacts: + # when: always + # reports: + # junit: + # - ./tmp/junit/junit.xml + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +build:macos: + stage: build + needs: [] + tags: + - shared-macos-amd64 + image: macos-11-xcode-12 + variables: + HOMEBREW_NO_INSTALL_UPGRADE: "true" + HOMEBREW_NO_INSTALL_CLEANUP: "true" + before_script: + - brew install node@16 + - brew link --overwrite node@16 + - hash -r + script: + - npm install --ignore-scripts + - export PATH="$(npm bin):$PATH" + - npm run build --verbose + # - npm test -- --ci + # artifacts: + # when: always + # reports: + # junit: + # - ./tmp/junit/junit.xml + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ -nix: +build:prerelease: stage: build - image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner + needs: + - build:linux + - build:windows + - build:macos + # Don't interrupt publishing job + interruptible: false + before_script: + - echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ./.npmrc + script: + - echo 'Publishing library prerelease' + - > + nix-shell --run ' + npm publish --tag prerelease --access public; + ' + after_script: + - rm -f ./.npmrc + rules: + # Only runs on tag pipeline where the tag is a prerelease version + # This requires dependencies to also run on tag pipeline + # However version tag comes with a version commit + # Dependencies must not run on the version commit + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+-.*[0-9]+$/ + +integration:builds: + stage: integration + needs: + - build:linux + - build:windows + - build:macos script: - mkdir -p ./builds - # nix-specific application target - > build_application="$(nix-build \ --max-jobs "$(nproc)" --cores "$(nproc)" \ @@ -98,19 +266,40 @@ nix: --attr docker \ --attr package.linux.x64.elf \ --attr package.windows.x64.exe \ - --attr package.macos.x64.macho)" + --attr package.macos.x64.macho \ + --attr package.macos.arm64.macho)" - cp -r $builds ./builds/ - only: - - master artifacts: paths: - ./builds/ + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +integration:deployment: + stage: integration + needs: + - integration:builds + # Don't interrupt deploying job + interruptible: false + # Requires mutual exclusion + resource_group: integration:deployment + script: + - echo 'Perform service deployment for integration testing' + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ -application run: - stage: quality - image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner - dependencies: - - nix +integration:nix: + stage: integration + needs: + - integration:builds + - job: integration:deployment + optional: true script: - > build_application="$( \ @@ -119,14 +308,19 @@ application run: tail -1 \ )" - $build_application/bin/polykey - only: - - master + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ -docker run: - stage: quality +integration:docker: + stage: integration + needs: + - integration:builds + - job: integration:deployment + optional: true image: docker:20.10.11 - dependencies: - - nix services: - docker:20.10.11-dind variables: @@ -136,61 +330,233 @@ docker run: script: - image="$(docker load --input ./builds/*docker* | cut -d' ' -f3)" - docker run "$image" - only: - - master + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ -linux run: - stage: quality +integration:linux: + stage: integration + needs: + - integration:builds + - job: integration:deployment + optional: true image: ubuntu:latest - dependencies: - - nix script: - for f in ./builds/*-linux-*; do "$f"; done - only: - - master + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ -windows run: - stage: quality - dependencies: - - nix - script: - - Get-ChildItem -File ./builds/*-win32-* | ForEach {& $_.FullName} +integration:windows: + stage: integration + needs: + - integration:builds + - job: integration:deployment + optional: true tags: - windows - only: - - master - -macos run: - stage: quality - image: macos-11-xcode-12 - dependencies: - - nix - script: - - for f in ./builds/*-macos-*; do "$f"; done - only: - - master - tags: - - shared-macos-amd64 - -packages: + script: + - Get-ChildItem -File ./builds/*-win-* | ForEach {& $_.FullName} + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +integration:macos: + stage: integration + needs: + - integration:builds + - job: integration:deployment + optional: true + tags: + - shared-macos-amd64 + image: macos-11-xcode-12 + script: + - for f in ./builds/*-macos-x64*; do "$f"; done + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +integration:prerelease: + stage: integration + needs: + - integration:builds + - job: build:prerelease + optional: true + - job: integration:nix + optional: true + - job: integration:docker + optional: true + - job: integration:linux + optional: true + - job: integration:windows + optional: true + - job: integration:macos + optional: true + # Don't interrupt publishing job + interruptible: false + script: + - echo 'Publishing application prerelease' + - > + nix-shell -I nixpkgs=./pkgs.nix --packages gitAndTools.gh --run ' + if gh release view "$CI_COMMIT_TAG" --repo "$GH_PROJECT_PATH" >/dev/null; then \ + gh release \ + upload "$CI_COMMIT_TAG" \ + builds/*.closure.gz \ + builds/*-docker-* \ + builds/*-linux-* \ + builds/*-win-* \ + builds/*-macos-* \ + --clobber \ + --repo "$GH_PROJECT_PATH"; \ + else \ + gh release \ + create "$CI_COMMIT_TAG" \ + builds/*.closure.gz \ + builds/*-docker-* \ + builds/*-linux-* \ + builds/*-win-* \ + builds/*-macos-* \ + --title "${CI_COMMIT_TAG}-$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \ + --notes "" \ + --prerelease \ + --target staging \ + --repo "$GH_PROJECT_PATH"; \ + fi; + ' + rules: + # Only runs on tag pipeline where the tag is a prerelease version + # This requires dependencies to also run on tag pipeline + # However version tag comes with a version commit + # Dependencies must not run on the version commit + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+-.*[0-9]+$/ + +integration:merge: + stage: integration + needs: + - build:merge + - job: build:linux + optional: true + - job: build:windows + optional: true + - job: build:macos + optional: true + - job: integration:nix + optional: true + - job: integration:docker + optional: true + - job: integration:linux + optional: true + - job: integration:windows + optional: true + - job: integration:macos + optional: true + # Requires mutual exclusion + resource_group: integration:merge + allow_failure: true + variables: + # Ensure that CI/CD is fetching all commits + # this is necessary to checkout origin/master + # and to also merge origin/staging + GIT_DEPTH: 0 + script: + - > + nix-shell -I nixpkgs=./pkgs.nix --packages gitAndTools.gh --run ' + printf "Pipeline Succeeded on ${CI_PIPELINE_ID} for ${CI_COMMIT_SHA}\n\n${CI_PIPELINE_URL}" \ + | gh pr comment staging \ + --body-file - \ + --repo "$GH_PROJECT_PATH"; + ' + - git remote add upstream "$GH_PROJECT_URL" + - git checkout origin/master + # Merge up to the current commit (not the latest commit) + - git merge --ff-only "$CI_COMMIT_SHA" + - git push upstream HEAD:master + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +release:deployment:branch: stage: release - image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner - dependencies: - - nix + # Only needs integration:builds from the staging branch pipeline + needs: + - project: $CI_PROJECT_PATH + job: integration:builds + ref: staging + artifacts: true + # Don't interrupt deploying job + interruptible: false + # Requires mutual exclusion (also with release:deployment:tag) + resource_group: release:deployment script: + - echo 'Perform service deployment for production' + rules: + # Runs on master commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'master' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +release:deployment:tag: + stage: release + # Tag pipelines run independently + needs: + - integration:builds + - integration:merge + # Don't interrupt deploying job + interruptible: false + # Requires mutual exclusion (also with release:deployment:branch) + resource_group: release:deployment + script: + - echo 'Perform service deployment for production' + rules: + # Runs on tag pipeline where the tag is a release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/ + +release:distribution: + stage: release + needs: + - build:linux + - build:windows + - build:macos + - integration:builds + - integration:merge + - release:deployment:tag + # Don't interrupt publishing job + interruptible: false + before_script: + - echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ./.npmrc + script: + - echo 'Publishing library & application release' + - > + nix-shell --run ' + npm publish --access public; + ' - > - nix-shell -I nixpkgs=./pkgs.nix --packages git gitAndTools.gh --run ' - commit="$(git rev-parse --short HEAD)"; + nix-shell -I nixpkgs=./pkgs.nix --packages gitAndTools.gh --run ' gh release \ - create "$commit" \ + create "$CI_COMMIT_TAG" \ builds/*.closure.gz \ + builds/*-docker-* \ builds/*-linux-* \ - builds/*-win32-* \ + builds/*-win-* \ builds/*-macos-* \ - --title "Build-$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \ - --prerelease \ + --title "${CI_COMMIT_TAG}-$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \ --notes "" \ - --repo MatrixAI/js-polykey; + --target master \ + --repo "$GH_PROJECT_PATH"; ' - only: - - master + after_script: + - rm -f ./.npmrc + rules: + # Only runs on tag pipeline where the tag is a release version + # This requires dependencies to also run on tag pipeline + # However version tag comes with a version commit + # Dependencies must not run on the version commit + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/ diff --git a/.npmignore b/.npmignore index 3e70e24c7..6bb02a31f 100644 --- a/.npmignore +++ b/.npmignore @@ -1,17 +1,16 @@ .* +/*.nix /nix -/pkgs.nix -/default.nix -/shell.nix -/release.nix /tsconfig.json /tsconfig.build.json /babel.config.js /jest.config.js /src +/scripts /tests /tmp /docs /benches +/build /builds /dist/tsbuildinfo diff --git a/README.md b/README.md index 04e68a90f..73da94d71 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Polykey -[![pipeline status](https://gitlab.com/MatrixAI/open-source/js-polykey/badges/master/pipeline.svg)](https://gitlab.com/MatrixAI/open-source/js-polykey/commits/master) +staging:[![pipeline status](https://gitlab.com/MatrixAI/open-source/js-polykey/badges/staging/pipeline.svg)](https://gitlab.com/MatrixAI/open-source/js-polykey/commits/staging) +master:[![pipeline status](https://gitlab.com/MatrixAI/open-source/js-polykey/badges/master/pipeline.svg)](https://gitlab.com/MatrixAI/open-source/js-polykey/commits/master) This is the core library for running PolyKey. It provides a CLI `polykey` or `pk` for interacting with the PolyKey system. diff --git a/default.nix b/default.nix index 183bc8b27..283de7665 100644 --- a/default.nix +++ b/default.nix @@ -12,32 +12,44 @@ let packageName = utils.node2nixDev.packageName; } '' - mkdir -p $out/lib/node_modules/${utils.node2nixDev.packageName} + mkdir -p "$out/lib/node_modules/$packageName" # copy the package.json - cp ${utils.node2nixDev}/lib/node_modules/${utils.node2nixDev.packageName}/package.json $out/lib/node_modules/${utils.node2nixDev.packageName}/ + cp \ + "${utils.node2nixDev}/lib/node_modules/$packageName/package.json" \ + "$out/lib/node_modules/$packageName/" + # copy the native addons + if [ -d "${utils.node2nixDev}/lib/node_modules/$packageName/prebuilds" ]; then + cp -r \ + "${utils.node2nixDev}/lib/node_modules/$packageName/prebuilds" \ + "$out/lib/node_modules/$packageName/" + fi # copy the dist - cp -r ${utils.node2nixDev}/lib/node_modules/${utils.node2nixDev.packageName}/dist $out/lib/node_modules/${utils.node2nixDev.packageName}/ + cp -r \ + "${utils.node2nixDev}/lib/node_modules/$packageName/dist" \ + "$out/lib/node_modules/$packageName/" # copy over the production dependencies if [ -d "${utils.node2nixProd}/lib/node_modules" ]; then - cp -r ${utils.node2nixProd}/lib/node_modules $out/lib/node_modules/${utils.node2nixDev.packageName}/ + cp -r \ + "${utils.node2nixProd}/lib/node_modules" \ + "$out/lib/node_modules/$packageName/" fi # symlink bin executables if [ \ - "$(${jq}/bin/jq 'has("bin")' "$out/lib/node_modules/${utils.node2nixDev.packageName}/package.json")" \ + "$(${jq}/bin/jq 'has("bin")' "$out/lib/node_modules/$packageName/package.json")" \ == \ "true" \ ]; then mkdir -p "$out/bin" while IFS= read -r bin_name && IFS= read -r bin_path; do # make files executable - chmod a+x "$out/lib/node_modules/${utils.node2nixDev.packageName}/$bin_path" + chmod a+x "$out/lib/node_modules/$packageName/$bin_path" # create the symlink ln -s \ - "../lib/node_modules/${utils.node2nixDev.packageName}/$bin_path" \ + "../lib/node_modules/$packageName/$bin_path" \ "$out/bin/$bin_name" done < <( ${jq}/bin/jq -r 'select(.bin != null) | .bin | to_entries[] | (.key, .value)' \ - "$out/lib/node_modules/${utils.node2nixDev.packageName}/package.json" + "$out/lib/node_modules/$packageName/package.json" ) fi ''; diff --git a/jest.config.js b/jest.config.js index f811716a8..39d84744b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -5,17 +5,16 @@ const process = require('process'); const { pathsToModuleNameMapper } = require('ts-jest'); const { compilerOptions } = require('./tsconfig'); -const moduleNameMapper = pathsToModuleNameMapper( - compilerOptions.paths, - { prefix: "/src/" } -); +const moduleNameMapper = pathsToModuleNameMapper(compilerOptions.paths, { + prefix: '/src/', +}); // using panva/jose with jest requires subpath exports // https://github.com/panva/jose/discussions/105 moduleNameMapper['^jose/(.*)$'] = "/node_modules/jose/dist/node/cjs/$1"; // Global variables that are shared across the jest worker pool -// These variables must be static and serialisable +// These variables must be static and serializable const globals = { // Absolute directory to the project root projectDir: __dirname, @@ -39,34 +38,34 @@ const globals = { process.env['GLOBAL_DATA_DIR'] = globals.dataDir; module.exports = { - testEnvironment: "node", - cacheDirectory: '/tmp/jest', + testEnvironment: 'node', verbose: true, - roots: [ - "/tests" - ], - testMatch: [ - "**/?(*.)+(spec|test|unit.test).+(ts|tsx|js)" - ], + collectCoverage: false, + cacheDirectory: '/tmp/jest', + coverageDirectory: '/tmp/coverage', + roots: ['/tests'], + testMatch: ['**/?(*.)+(spec|test|unit.test).+(ts|tsx|js|jsx)'], transform: { - "^.+\\.tsx?$": "ts-jest", - "^.+\\.jsx?$": "babel-jest" + '^.+\\.tsx?$': 'ts-jest', + '^.+\\.jsx?$': 'babel-jest', }, + reporters: [ + 'default', + ['jest-junit', { outputDirectory: '/tmp/junit' }], + ], + collectCoverageFrom: ['src/**/*.{ts,tsx,js,jsx}', '!src/**/*.d.ts'], + coverageReporters: ['text', 'cobertura'], globals, // Global setup script executed once before all test files - globalSetup: "/tests/globalSetup.ts", + globalSetup: '/tests/globalSetup.ts', // Global teardown script executed once after all test files - globalTeardown: "/tests/globalTeardown.ts", + globalTeardown: '/tests/globalTeardown.ts', // Setup files are executed before each test file // Can access globals - setupFiles: [ - "/tests/setup.ts" - ], + setupFiles: ['/tests/setup.ts'], // Setup files after env are executed before each test file // after the jest test environment is installed // Can access globals - setupFilesAfterEnv: [ - "/tests/setupAfterEnv.ts" - ], - moduleNameMapper: moduleNameMapper + setupFilesAfterEnv: ['/tests/setupAfterEnv.ts'], + moduleNameMapper: moduleNameMapper, }; diff --git a/nix/leveldown.patch b/nix/leveldown.patch deleted file mode 100644 index 0d35bab41..000000000 --- a/nix/leveldown.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- dictionary/leveldown.js 2021-08-04 15:43:31.836337623 +1000 -+++ dictionary/leveldown_.js 2021-08-04 15:43:11.977266316 +1000 -@@ -1,10 +1,3 @@ - 'use strict'; - --module.exports = { -- pkg: { -- patches: { -- 'binding.js': ['__dirname', "require('path').dirname(process.execPath)"], -- }, -- deployFiles: [['prebuilds', 'prebuilds', 'directory']], -- }, --}; -+module.exports = {}; diff --git a/package-lock.json b/package-lock.json index 97cd45f6a..d0a5a8765 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "google-protobuf": "^3.14.0", "ip-num": "^1.3.3-0", "isomorphic-git": "^1.8.1", + "jest-junit": "^13.2.0", "jose": "^4.3.6", "lexicographic-integer": "^1.1.0", "multiformats": "^9.4.8", @@ -75,6 +76,7 @@ "node-gyp-build": "4.4.0", "pkg": "5.6.0", "prettier": "^2.6.2", + "shx": "^0.3.4", "ts-jest": "^27.0.5", "ts-node": "^10.4.0", "tsconfig-paths": "^3.9.0", @@ -5677,6 +5679,15 @@ "node": ">= 0.4" } }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/into-stream": { "version": "6.0.0", "dev": true, @@ -6710,6 +6721,20 @@ "node": ">=8" } }, + "node_modules/jest-junit": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-13.2.0.tgz", + "integrity": "sha512-B0XNlotl1rdsvFZkFfoa19mc634+rrd8E4Sskb92Bb8MmSXeWV9XJGUyctunZS1W410uAxcyYuPUGVnbcOH8cg==", + "dependencies": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/jest-leak-detector": { "version": "27.5.1", "dev": true, @@ -8105,6 +8130,17 @@ "minimist": "^1.2.5" } }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/mkdirp-classic": { "version": "0.5.3", "dev": true, @@ -9160,6 +9196,18 @@ "node": ">= 6" } }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/regenerate": { "version": "1.4.2", "dev": true, @@ -9471,6 +9519,23 @@ "node": ">=8" } }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/shiki": { "version": "0.10.1", "dev": true, @@ -9481,6 +9546,22 @@ "vscode-textmate": "5.2.0" } }, + "node_modules/shx": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", + "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", + "dev": true, + "dependencies": { + "minimist": "^1.2.3", + "shelljs": "^0.8.5" + }, + "bin": { + "shx": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/side-channel": { "version": "1.0.4", "license": "MIT", @@ -10648,6 +10729,11 @@ } } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" + }, "node_modules/xml-name-validator": { "version": "3.0.0", "dev": true, @@ -14315,6 +14401,12 @@ "side-channel": "^1.0.4" } }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, "into-stream": { "version": "6.0.0", "dev": true, @@ -14944,6 +15036,17 @@ } } }, + "jest-junit": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-13.2.0.tgz", + "integrity": "sha512-B0XNlotl1rdsvFZkFfoa19mc634+rrd8E4Sskb92Bb8MmSXeWV9XJGUyctunZS1W410uAxcyYuPUGVnbcOH8cg==", + "requires": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + } + }, "jest-leak-detector": { "version": "27.5.1", "dev": true, @@ -15841,6 +15944,11 @@ "minimist": "^1.2.5" } }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, "mkdirp-classic": { "version": "0.5.3", "dev": true @@ -16491,6 +16599,15 @@ "util-deprecate": "^1.0.1" } }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, "regenerate": { "version": "1.4.2", "dev": true @@ -16660,6 +16777,17 @@ "shebang-regex": { "version": "3.0.0" }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, "shiki": { "version": "0.10.1", "dev": true, @@ -16669,6 +16797,16 @@ "vscode-textmate": "5.2.0" } }, + "shx": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", + "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", + "dev": true, + "requires": { + "minimist": "^1.2.3", + "shelljs": "^0.8.5" + } + }, "side-channel": { "version": "1.0.4", "requires": { @@ -17416,6 +17554,11 @@ "dev": true, "requires": {} }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" + }, "xml-name-validator": { "version": "3.0.0", "dev": true diff --git a/package.json b/package.json index 96e74b3f6..83a5806a2 100644 --- a/package.json +++ b/package.json @@ -51,24 +51,26 @@ "pkg": { "assets": [ "node_modules/jose/**/*", - "node_modules/utp-native/**/*", - "node_modules/leveldown/**/*", - "node_modules/fd-lock/**/*", "dist/**/*.json" ], - "scripts": "dist/workers/polykeyWorker.js" + "scripts": [ + "dist/workers/polykeyWorker.js", + "dist/bin/polykey-agent.js" + ] }, "scripts": { "prepare": "tsc -p ./tsconfig.build.json", - "build": "rm -r ./dist || true; tsc -p ./tsconfig.build.json", - "postbuild": "cp -fR src/proto dist; cp src/notifications/*.json dist/notifications/; cp src/claims/*.json dist/claims/; cp src/status/*.json dist/status/;", + "build": "shx rm -rf ./dist && tsc -p ./tsconfig.build.json", + "postbuild": "shx cp -fR src/proto dist && shx cp src/notifications/*.json dist/notifications/ && shx cp src/claims/*.json dist/claims/ && shx cp src/status/*.json dist/status/", + "postversion": "npm install --package-lock-only --ignore-scripts --silent", "ts-node": "ts-node --require tsconfig-paths/register", "test": "jest", "lint": "eslint '{src,tests}/**/*.{js,ts}'", "lintfix": "eslint '{src,tests}/**/*.{js,ts}' --fix", - "docs": "rm -r ./docs || true; typedoc --gitRevision master --tsconfig ./tsconfig.build.json --out ./docs src", - "bench": "rm -r ./benches/results || true; ts-node --require tsconfig-paths/register --compiler typescript-cached-transpile --transpile-only ./benches", + "docs": "shx rm -rf ./docs && typedoc --gitRevision master --tsconfig ./tsconfig.build.json --out ./docs src", + "bench": "shx rm -rf ./benches/results && ts-node --require tsconfig-paths/register --compiler typescript-cached-transpile --transpile-only ./benches", "proto-generate": "scripts/proto-generate.sh", + "pkg": "./scripts/pkg.js --no-dict=leveldown.js", "polykey": "ts-node --require tsconfig-paths/register --compiler typescript-cached-transpile --transpile-only src/bin/polykey.ts" }, "dependencies": { @@ -94,6 +96,7 @@ "google-protobuf": "^3.14.0", "ip-num": "^1.3.3-0", "isomorphic-git": "^1.8.1", + "jest-junit": "^13.2.0", "jose": "^4.3.6", "lexicographic-integer": "^1.1.0", "multiformats": "^9.4.8", @@ -134,6 +137,7 @@ "node-gyp-build": "4.4.0", "pkg": "5.6.0", "prettier": "^2.6.2", + "shx": "^0.3.4", "ts-jest": "^27.0.5", "ts-node": "^10.4.0", "tsconfig-paths": "^3.9.0", diff --git a/release.nix b/release.nix index e778a0073..2544eb403 100644 --- a/release.nix +++ b/release.nix @@ -8,21 +8,16 @@ let name = "${utils.basename}-${version}-linux-${arch}"; version = utils.node2nixDev.version; src = "${utils.node2nixDev}/lib/node_modules/${utils.node2nixDev.packageName}"; - buildInputs = [ - utils.pkg - ]; + nativeBuildInputs = [ nodejs ]; PKG_CACHE_PATH = utils.pkgCachePath; PKG_IGNORE_TAG = 1; - # ensure that native modules are built from source - npm_config_build_from_source = "true"; buildPhase = '' - cp ${./package.json} package.json - pkg . \ - --targets node${utils.nodeVersion}-linux-${arch} \ - --no-bytecode \ - --public \ - --public-packages "*" \ - --output out + npm run pkg -- \ + --output=out \ + --bin=polykey \ + --node-version=${utils.nodeVersion} \ + --platform=linux \ + --arch=${arch} ''; installPhase = '' cp out $out @@ -31,24 +26,19 @@ let }; buildExe = arch: stdenv.mkDerivation rec { - name = "${utils.basename}-${version}-win32-${arch}.exe"; + name = "${utils.basename}-${version}-win-${arch}.exe"; version = utils.node2nixDev.version; src = "${utils.node2nixDev}/lib/node_modules/${utils.node2nixDev.packageName}"; - buildInputs = [ - utils.pkg - ]; + nativeBuildInputs = [ nodejs ]; PKG_CACHE_PATH = utils.pkgCachePath; PKG_IGNORE_TAG = 1; - # ensure that native modules are built from source - npm_config_build_from_source = "true"; buildPhase = '' - cp ${./package.json} package.json - pkg . \ - --targets node${utils.nodeVersion}-win-${arch} \ - --no-bytecode \ - --public \ - --public-packages "*" \ - --output out.exe + npm run pkg -- \ + --output=out.exe \ + --bin=polykey \ + --node-version=${utils.nodeVersion} \ + --platform=win32 \ + --arch=${arch} ''; installPhase = '' cp out.exe $out @@ -60,44 +50,34 @@ let name = "${utils.basename}-${version}-macos-${arch}"; version = utils.node2nixDev.version; src = "${utils.node2nixDev}/lib/node_modules/${utils.node2nixDev.packageName}"; - buildInputs = [ - utils.pkg - ]; + nativeBuildInputs = [ nodejs ]; PKG_CACHE_PATH = utils.pkgCachePath; PKG_IGNORE_TAG = 1; - # ensure that native modules are built from source - npm_config_build_from_source = "true"; buildPhase = '' - cp ${./package.json} package.json - pkg . \ - --targets node${utils.nodeVersion}-macos-${arch} \ - --no-bytecode \ - --public \ - --public-packages "*" \ - --output out + npm run pkg -- \ + --output=out \ + --bin=polykey \ + --node-version=${utils.nodeVersion} \ + --platform=darwin \ + --arch=${arch} ''; installPhase = '' cp out $out ''; dontFixup = true; }; - # allow resolution of localhost - nsswitch = writeTextDir "etc/nsswitch.conf" - '' - hosts: files dns myhostname - ''; in rec { application = callPackage ./default.nix {}; docker = dockerTools.buildImage { name = application.name; - contents = [ application cacert nsswitch ]; + contents = [ application ]; keepContentsDirlinks = true; extraCommands = '' mkdir -m 1777 tmp ''; config = { - Entrypoint = [ "/bin/polykey" ]; + Cmd = [ "/bin/polykey" ]; }; }; package = { @@ -115,6 +95,9 @@ in x64 = { macho = buildMacho "x64"; }; + arm64 = { + macho = buildMacho "arm64"; + }; }; }; } diff --git a/scripts/pkg.js b/scripts/pkg.js new file mode 100755 index 000000000..d5e55c10b --- /dev/null +++ b/scripts/pkg.js @@ -0,0 +1,174 @@ +#!/usr/bin/env node + +const os = require('os'); +const fs = require('fs'); +const path = require('path'); +const process = require('process'); +const crypto = require('crypto'); +const child_process = require('child_process'); +const packageJSON = require('../package.json'); + +/** + * Supported platforms + * Maps os.platform() to pkg platform + */ +const platforms = { + 'linux': 'linux', + 'win32': 'win', + 'darwin': 'macos', +}; + +/** + * Supported architectures + * Maps os.arch() to pkg arch + */ +const archs = { + 'x64': 'x64', + 'arm64': 'arm64', +}; + +function randomString(l) { + return crypto + .randomBytes(l) + .toString('base64') + .replace(/\//, '_'); +} + +async function find(dirPath, pattern) { + const found = []; + let entries; + try { + entries = await fs.promises.readdir(dirPath); + } catch (e) { + if (e.code === 'ENOENT') { + return found ; + } + throw e; + } + for (const entry of entries) { + const entryPath = path.join(dirPath, entry); + const stat = await fs.promises.lstat(entryPath); + if (stat.isDirectory()) { + found.push(...(await find(entryPath, pattern))); + } else if (pattern.test(entryPath)) { + found.push(entryPath); + } + } + return found; +}; + +async function main(argv = process.argv) { + argv = argv.slice(2); + let outPath; + let binTarget; + let nodeVersion = process.versions.node.match(/\d+/)[0]; + let platform = os.platform(); + let arch = os.arch(); + const restArgs = []; + while (argv.length > 0) { + const option = argv.shift(); + let match; + if (match = option.match(/--output(?:=(.+)|$)/)) { + outPath = match[1] ?? argv.shift(); + } else if (match = option.match(/--bin(?:=(.+)|$)/)) { + binTarget = match[1] ?? argv.shift(); + } else if (match = option.match(/--node-version(?:=(.+)|$)/)) { + nodeVersion = match[1] ?? argv.shift(); + } else if (match = option.match(/--platform(?:=(.+)|$)/)) { + platform = match[1] ?? argv.shift(); + } else if (match = option.match(/--arch(?:=(.+)|$)/)) { + arch = match[1] ?? argv.shift(); + } else { + restArgs.push(option); + } + } + let entryPoint; + if (binTarget == null) { + entryPoint = Object.values(packageJSON.bin ?? {})[0]; + } else { + entryPoint = packageJSON.bin[binTarget]; + } + if (entryPoint == null) { + throw new Error('Bin executable is required'); + } + if (typeof outPath !== 'string') { + throw new Error('Output path is required'); + } + if (entryPoint == null) { + throw new Error(`Unknown bin target: ${binTarget}`); + } + if (isNaN(parseInt(nodeVersion))) { + throw new Error(`Unsupported node version: ${nodeVersion}`); + } + if (!(platform in platforms)) { + throw new Error(`Unsupported platform: ${platform}`); + } + if (!(arch in archs)) { + throw new Error(`Unsupported architecture: ${arch}`); + } + // Monkey patch the os.platform and os.arch for node-gyp-build + os.platform = () => platform; + os.arch = () => arch; + const nodeGypBuild = require('node-gyp-build'); + const pkgConfig = packageJSON.pkg ?? {}; + pkgConfig.assets = pkgConfig.assets ?? {}; + const npmLsOut = child_process.execFileSync( + 'npm', + ['ls', '--all', '--prod', '--parseable'], + { + windowsHide: true, + encoding: 'utf-8' + } + ); + const nodePackages = npmLsOut.trim().split('\n'); + const projectRoot = path.join(__dirname, '..'); + for (const nodePackage of nodePackages) { + // If `build` or `prebuilds` directory exists with a `.node` file + // then we expect to find the appropriate native addon + // The `node-gyp-build` will look in these 2 directories + const buildPath = path.join(nodePackage, 'build'); + const prebuildsPath = path.join(nodePackage, 'prebuilds'); + const buildFinds = await find(buildPath, /.node$/); + const prebuildsFinds = await find(prebuildsPath, /.node$/); + if (buildFinds.length > 0 || prebuildsFinds.length > 0) { + let nativeAddonPath = nodeGypBuild.path(nodePackage); + // Must use relative paths + // so that assets are added relative to the project + nativeAddonPath = path.relative(projectRoot, nativeAddonPath); + pkgConfig.assets.push(nativeAddonPath); + } + } + console.error('Configured pkg with:'); + console.error(pkgConfig); + // The pkg config must be in the same directory as the `package.json` + // otherwise the relative paths won't work + const pkgConfigPath = path.join(projectRoot, 'pkg.json'); + await fs.promises.writeFile(pkgConfigPath, JSON.stringify(pkgConfig)); + const pkgPlatform = platforms[platform]; + const pkgArch = archs[arch]; + const pkgArgs = [ + entryPoint, + `--config=${pkgConfigPath}`, + `--targets=node${nodeVersion}-${pkgPlatform}-${pkgArch}`, + '--no-bytecode', + '--no-native-build', + '--public', + '--public-packages=\'*\'', + `--output=${outPath}`, + ...restArgs + ]; + console.error('Running pkg:') + console.error(['pkg', ...pkgArgs].join(' ')); + child_process.execFileSync( + 'pkg', + pkgArgs, + { + stdio: ['inherit', 'inherit', 'inherit'], + windowsHide: true, + encoding: 'utf-8' + } + ); + await fs.promises.rm(pkgConfigPath); +} + +void main(); diff --git a/scripts/test-pipelines.sh b/scripts/test-pipelines.sh index 323850fdd..4864af4fb 100755 --- a/scripts/test-pipelines.sh +++ b/scripts/test-pipelines.sh @@ -5,7 +5,19 @@ shopt -s nullglob # Quote the heredoc to prevent shell expansion cat << "EOF" +workflow: + rules: + # Disable merge request pipelines + - if: $CI_MERGE_REQUEST_ID + when: never + - when: always + +default: + interruptible: true + variables: + GH_PROJECT_PATH: "MatrixAI/${CI_PROJECT_NAME}" + GH_PROJECT_URL: "https://${GITHUB_TOKEN}@github.com/${GH_PROJECT_PATH}.git" GIT_SUBMODULE_STRATEGY: "recursive" # Cache .npm NPM_CONFIG_CACHE: "./tmp/npm" @@ -16,7 +28,7 @@ variables: TS_CACHED_TRANSPILE_CACHE: "${CI_PROJECT_DIR}/tmp/ts-node-cache" TS_CACHED_TRANSPILE_PORTABLE: "true" -# Cached directories shared between jobs & pipelines per-branch +# Cached directories shared between jobs & pipelines per-branch per-runner cache: key: $CI_COMMIT_REF_SLUG paths: @@ -24,24 +36,12 @@ cache: - ./tmp/ts-node-cache/ # `jest` cache is configured in jest.config.js - ./tmp/jest/ + +image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner EOF printf "\n" -# # SPECIAL CASE -# cat << EOF -# test binagent: -# image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner -# stage: test -# interruptible: true -# script: -# - > -# nix-shell -I nixpkgs=./pkgs.nix --packages nodejs --run ' -# npm ci; -# npm test -- ./tests/bin/agent; -# ' -# EOF - # Each test directory has its own job for test_dir in tests/**/*/; do test_files=("$test_dir"*.test.ts) @@ -53,16 +53,20 @@ for test_dir in tests/**/*/; do # Remove `tests/` prefix test_dir="${test_dir#*/}" cat << EOF -test $test_dir: - image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner +check:test $test_dir: stage: test - interruptible: true + needs: [] script: - > - nix-shell -I nixpkgs=./pkgs.nix --packages nodejs --run ' - npm ci; - npm test -- ${test_files[@]}; + nix-shell --run ' + npm run build --verbose; + npm test -- --ci ${test_files[@]}; ' + artifacts: + when: always + reports: + junit: + - ./tmp/junit/junit.xml EOF printf "\n" done @@ -70,14 +74,18 @@ done # All top-level test files are accumulated into 1 job test_files=(tests/*.test.ts) cat << EOF -test index: - image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner +check:test index: stage: test - interruptible: true + needs: [] script: - > - nix-shell -I nixpkgs=./pkgs.nix --packages nodejs --run ' - npm ci; - npm test -- ${test_files[@]}; + nix-shell --run ' + npm run build --verbose; + npm test -- --ci ${test_files[@]}; ' + artifacts: + when: always + reports: + junit: + - ./tmp/junit/junit.xml EOF diff --git a/shell.nix b/shell.nix index 3b4bd595f..961a13c8a 100644 --- a/shell.nix +++ b/shell.nix @@ -4,13 +4,12 @@ with pkgs; let utils = callPackage ./utils.nix {}; in - pkgs.mkShell { + mkShell { nativeBuildInputs = [ nodejs utils.node2nix grpc-tools grpcurl - utils.pkg ]; PKG_CACHE_PATH = utils.pkgCachePath; PKG_IGNORE_TAG = 1; @@ -26,18 +25,10 @@ in # Built executables and NPM executables export PATH="$(pwd)/dist/bin:$(npm bin):$PATH" - # pkg is installed in package.json - # this ensures that in nix-shell we are using the nix packaged versions - export PATH="${lib.makeBinPath - [ - utils.pkg - ] - }:$PATH" - # Enables npm link to work export npm_config_prefix=~/.npm - npm install + npm install --ignore-scripts set +v ''; diff --git a/utils.nix b/utils.nix index e63e463df..31f0b1055 100644 --- a/utils.nix +++ b/utils.nix @@ -2,7 +2,6 @@ , linkFarm , nix-gitignore , nodejs -, nodePackages , pkgs , lib , fetchurl @@ -12,7 +11,7 @@ rec { # this removes the org scoping basename = builtins.baseNameOf node2nixDev.packageName; - src = nix-gitignore.gitignoreSource [".git"] ./.; + src = nix-gitignore.gitignoreSource [".git" "/*.nix"] ./.; nodeVersion = builtins.elemAt (lib.versions.splitVersion nodejs.version) 0; # custom node2nix directly from GitHub node2nixSrc = fetchFromGitHub { @@ -33,21 +32,30 @@ rec { --composition $out/default.nix \ --nodejs-${nodeVersion} ''; - # the shell attribute has the nodeDependencies, whereas the package does not - node2nixProd = ( - (import (node2nixDrv false) { inherit pkgs nodejs; }).shell.override (attrs: { - buildInputs = attrs.buildInputs ++ [ nodePackages.node-gyp-build ]; - dontNpmInstall = true; - }) - ).nodeDependencies; - node2nixDev = (import (node2nixDrv true) { inherit pkgs nodejs; }).package.override (attrs: { + node2nixProd = (import (node2nixDrv false) { inherit pkgs nodejs; }).nodeDependencies.override (attrs: { + # Use filtered source src = src; - buildInputs = attrs.buildInputs ++ [ nodePackages.node-gyp-build ]; + # Do not run build scripts during npm rebuild and npm install + npmFlags = "--ignore-scripts"; + # Do not run npm install, dependencies are installed by nix dontNpmInstall = true; + }); + node2nixDev = (import (node2nixDrv true) { inherit pkgs nodejs; }).package.override (attrs: { + # Use filtered source + src = src; + # Do not run build scripts during npm rebuild and npm install + # They will be executed in the postInstall hook + npmFlags = "--ignore-scripts"; + # Show full compilation flags + NIX_DEBUG = 1; + # Don't set rpath for native addons + # Native addons do not require their own runtime search path + # because they dynamically loaded by the nodejs runtime + NIX_DONT_SET_RPATH = true; + NIX_NO_SELF_RPATH = true; postInstall = '' - # The dependencies were prepared in the installphase - # See `node2nix` generated `node-env.nix` for details - npm run build + # This will setup the typescript build + npm --nodedir=${nodejs} run build ''; }); pkgBuilds = { @@ -64,6 +72,10 @@ rec { url = "https://github.com/vercel/pkg-fetch/releases/download/v3.3/node-v16.14.2-macos-x64"; sha256 = "1hq7v40vzc2bfr29y71lm0snaxcc8rys5w0da7pi5nmx4pyybc2v"; }; + "macos-arm64" = fetchurl { + url = "https://github.com/vercel/pkg-fetch/releases/download/v3.3/node-v16.14.2-macos-arm64"; + sha256 = "05q350aw7fhirmlqg6ckyi5hg9pwcvs0w5r047r8mf3ivy1hxra4"; + }; }; }; pkgCachePath = @@ -85,10 +97,9 @@ rec { name = fetchedName pkgBuild.macos-x64.name; path = pkgBuild.macos-x64; } + { + name = fetchedName pkgBuild.macos-arm64.name; + path = pkgBuild.macos-arm64; + } ]; - pkg = nodePackages.pkg.override { - postFixup = '' - patch -p0 < ${./nix/leveldown.patch} - ''; - }; } From fdae3d14cd00cce3221cce0ec7003d0b921f2996 Mon Sep 17 00:00:00 2001 From: Roger Qiu Date: Tue, 14 Jun 2022 15:55:39 +1000 Subject: [PATCH 114/137] nix: fixed building node2nix attribute in utils.nix The package-lock.json was corrupted or not parseable by node2nix After destroying the `node_modules` directory and deleting the `package-lock.json`, we were able to recreate a working `package-lock.json` file If this occurs again, just destroy the `package-lock.json` and `node_modules` directory and regenerate. --- package-lock.json | 6702 +++++++++++++++++++++++++++++++++------------ package.json | 2 +- utils.nix | 4 +- 3 files changed, 4898 insertions(+), 1810 deletions(-) diff --git a/package-lock.json b/package-lock.json index d0a5a8765..f7dc2510e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,7 +73,7 @@ "jest-mock-props": "^1.9.0", "mocked-env": "^1.3.5", "nexpect": "^0.6.0", - "node-gyp-build": "4.4.0", + "node-gyp-build": "^4.4.0", "pkg": "5.6.0", "prettier": "^2.6.2", "shx": "^0.3.4", @@ -87,8 +87,9 @@ }, "node_modules/@ampproject/remapping": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -99,8 +100,9 @@ }, "node_modules/@babel/code-frame": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/highlight": "^7.16.7" }, @@ -109,28 +111,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.17.10", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.5.tgz", + "integrity": "sha512-BxhE40PVCBxVEJsSBhB6UWyAuqJRxGsAw8BdHMJ3AKGydcwuWW4kOO3HmqBQAdcq/OP+/DlTVxLvsCzRTnZuGg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.17.10", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.5.tgz", + "integrity": "sha512-MGY8vg3DxMnctw0LdvSEojOsumc70g0t18gNyUdAZqB1Rpd1Bqo/svHGvt+UJ6JcGX+DIekGFDxxIWofBxLCnQ==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.10", - "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helpers": "^7.17.9", - "@babel/parser": "^7.17.10", + "@babel/generator": "^7.18.2", + "@babel/helper-compilation-targets": "^7.18.2", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helpers": "^7.18.2", + "@babel/parser": "^7.18.5", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.10", - "@babel/types": "^7.17.10", + "@babel/traverse": "^7.18.5", + "@babel/types": "^7.18.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -146,22 +150,38 @@ } }, "node_modules/@babel/generator": { - "version": "7.17.10", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.17.10", - "@jridgewell/gen-mapping": "^0.1.0", + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", + "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, @@ -171,8 +191,9 @@ }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-explode-assignable-expression": "^7.16.7", "@babel/types": "^7.16.7" @@ -182,9 +203,10 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.17.10", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", + "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/compat-data": "^7.17.10", "@babel/helper-validator-option": "^7.16.7", @@ -199,9 +221,10 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.17.9", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.0.tgz", + "integrity": "sha512-Kh8zTGR9de3J63e5nS0rQUdRs/kbtwoeQQ0sriS0lItjC96u8XXZN6lKpuyWd2coKSU13py/y+LTmThLuVX0Pg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-environment-visitor": "^7.16.7", @@ -219,9 +242,10 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz", + "integrity": "sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.7", "regexpu-core": "^5.0.1" @@ -235,8 +259,9 @@ }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.13.0", "@babel/helper-module-imports": "^7.12.13", @@ -252,20 +277,19 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", + "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.16.7" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-explode-assignable-expression": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, @@ -275,8 +299,9 @@ }, "node_modules/@babel/helper-function-name": { "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.16.7", "@babel/types": "^7.17.0" @@ -287,8 +312,9 @@ }, "node_modules/@babel/helper-hoist-variables": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, @@ -298,8 +324,9 @@ }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.17.0" }, @@ -309,8 +336,9 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, @@ -319,9 +347,10 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.17.7", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", + "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", @@ -329,8 +358,8 @@ "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0" + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" }, "engines": { "node": ">=6.9.0" @@ -338,8 +367,9 @@ }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, @@ -348,17 +378,19 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", + "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-wrap-function": "^7.16.8", @@ -369,26 +401,28 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.16.7", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.2.tgz", + "integrity": "sha512-XzAIyxx+vFnrOxiQrToSUOzUOn0e1J2Li40ntddek1Y69AXUTXoDJ40/D5RdjFu7s7qHiaeoTiempZcbuVXh2Q==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-member-expression-to-functions": "^7.17.7", "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.17.7", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", + "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.17.0" + "@babel/types": "^7.18.2" }, "engines": { "node": ">=6.9.0" @@ -396,8 +430,9 @@ }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.16.0" }, @@ -407,8 +442,9 @@ }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, @@ -418,24 +454,27 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-function-name": "^7.16.7", "@babel/template": "^7.16.7", @@ -447,22 +486,24 @@ } }, "node_modules/@babel/helpers": { - "version": "7.17.9", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", + "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.9", - "@babel/types": "^7.17.0" + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.17.9", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", + "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", @@ -473,9 +514,10 @@ } }, "node_modules/@babel/parser": { - "version": "7.17.10", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.5.tgz", + "integrity": "sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw==", "dev": true, - "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, @@ -484,11 +526,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.17.12.tgz", + "integrity": "sha512-xCJQXl4EeQ3J9C4yOmpTrtVGmzpm2iSzyxbkZHw7UCnZBftHpF/hpII80uWVyVrc40ytIClHjgWGTG1g/yB+aw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -498,13 +541,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.17.12.tgz", + "integrity": "sha512-/vt0hpIw0x4b6BLKUkwlvEoiGZYYLNZ96CzyHYPbtG2jZGz6LBe7/V+drYrc/d+ovrF9NBi0pmtvmNb/FsWtRQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" + "@babel/plugin-proposal-optional-chaining": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -514,11 +558,12 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz", + "integrity": "sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-remap-async-to-generator": "^7.16.8", "@babel/plugin-syntax-async-generators": "^7.8.4" }, @@ -530,12 +575,13 @@ } }, "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz", + "integrity": "sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -545,12 +591,13 @@ } }, "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.17.6", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.0.tgz", + "integrity": "sha512-t+8LsRMMDE74c6sV7KShIw13sqbqd58tlqNrsWoWBTIMw7SVQ0cZ905wLNS/FBCy/3PyooRHLFFlfrUNyyz5lA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.17.6", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -562,8 +609,9 @@ }, "node_modules/@babel/plugin-proposal-dynamic-import": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" @@ -576,11 +624,12 @@ } }, "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz", + "integrity": "sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -591,11 +640,12 @@ } }, "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.17.12.tgz", + "integrity": "sha512-rKJ+rKBoXwLnIn7n6o6fulViHMrOThz99ybH+hKHcOZbnN14VuMnH9fo2eHE69C8pO4uX1Q7t2HYYIDmv8VYkg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -606,11 +656,12 @@ } }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.17.12.tgz", + "integrity": "sha512-EqFo2s1Z5yy+JeJu7SFfbIUtToJTVlC61/C7WLKDntSw4Sz6JNAIfL7zQ74VvirxpjB5kz/kIx0gCcb+5OEo2Q==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -621,11 +672,12 @@ } }, "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz", + "integrity": "sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -637,8 +689,9 @@ }, "node_modules/@babel/plugin-proposal-numeric-separator": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -651,15 +704,16 @@ } }, "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.0.tgz", + "integrity": "sha512-nbTv371eTrFabDfHLElkn9oyf9VG+VKK6WMzhY2o4eHKaG19BToD9947zzGMO6I/Irstx9d8CwX6njPNIAR/yw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" + "@babel/plugin-transform-parameters": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -670,8 +724,9 @@ }, "node_modules/@babel/plugin-proposal-optional-catch-binding": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" @@ -684,11 +739,12 @@ } }, "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz", + "integrity": "sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, @@ -700,12 +756,13 @@ } }, "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.11", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.17.12.tgz", + "integrity": "sha512-SllXoxo19HmxhDWm3luPz+cPhtoTSKLJE9PXshsfrOzBqs60QP0r8OaJItrPhAj0d7mZMnNF0Y1UUggCDgMz1A==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -715,13 +772,14 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.17.12.tgz", + "integrity": "sha512-/6BtVi57CJfrtDNKfK5b66ydK2J5pXUKBKSPD2G1whamMuEnZWgoOIfO8Vf9F/DoD4izBLD/Au4NMQfruzzykg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -732,12 +790,13 @@ } }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz", + "integrity": "sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=4" @@ -748,8 +807,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -759,8 +819,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -770,8 +831,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -781,8 +843,9 @@ }, "node_modules/@babel/plugin-syntax-class-static-block": { "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -795,8 +858,9 @@ }, "node_modules/@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -806,8 +870,9 @@ }, "node_modules/@babel/plugin-syntax-export-namespace-from": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.3" }, @@ -815,10 +880,26 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.17.12.tgz", + "integrity": "sha512-n/loy2zkq9ZEM8tEOwON9wTQSTNDTDEz6NujPtJGLU7qObzT1N4c4YZZf8E6ATB2AjNQg/Ib2AIpO03EZaCehw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -828,8 +909,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -839,8 +921,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -850,8 +933,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -861,8 +945,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -872,8 +957,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -883,8 +969,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -894,8 +981,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -905,8 +993,9 @@ }, "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -919,8 +1008,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -932,11 +1022,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.17.10", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz", + "integrity": "sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -946,11 +1037,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz", + "integrity": "sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -960,12 +1052,13 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.17.12.tgz", + "integrity": "sha512-J8dbrWIOO3orDzir57NRsjg4uxucvhby0L/KZuGsWDj0g7twWK3g7JhJhOrXtuXiw8MeiSdJ3E0OW9H8LYEzLQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-remap-async-to-generator": "^7.16.8" }, "engines": { @@ -977,8 +1070,9 @@ }, "node_modules/@babel/plugin-transform-block-scoped-functions": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, @@ -990,11 +1084,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.16.7", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.4.tgz", + "integrity": "sha512-+Hq10ye+jlvLEogSOtq4mKvtk7qwcUQ1f0Mrueai866C82f844Yom2cttfJdMdqRLTxWpsbfbkIkOIfovyUQXw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1004,16 +1099,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.16.7", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.4.tgz", + "integrity": "sha512-e42NSG2mlKWgxKUAD9EJJSkZxR67+wZqzNxLSpc51T8tRU5SLFHsPmgYR5yr7sdgX4u+iHA1C5VafJ6AyImV3A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-function-name": "^7.17.9", "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-replace-supers": "^7.18.2", "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" }, @@ -1025,11 +1121,12 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz", + "integrity": "sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1039,11 +1136,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.17.7", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.0.tgz", + "integrity": "sha512-Mo69klS79z6KEfrLg/1WkmVnB8javh75HX4pi2btjvlIoasuxilEyjtsQW6XPrubNd7AQy0MMaNIaQE4e7+PQw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1054,8 +1152,9 @@ }, "node_modules/@babel/plugin-transform-dotall-regex": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.16.7", "@babel/helper-plugin-utils": "^7.16.7" @@ -1068,11 +1167,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.17.12.tgz", + "integrity": "sha512-EA5eYFUG6xeerdabina/xIoB95jJ17mAkR8ivx6ZSu9frKShBjpOGZPn511MTDTkiCO+zXnzNczvUM69YSf3Zw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1083,8 +1183,9 @@ }, "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", "@babel/helper-plugin-utils": "^7.16.7" @@ -1097,11 +1198,12 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.16.7", + "version": "7.18.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.1.tgz", + "integrity": "sha512-+TTB5XwvJ5hZbO8xvl2H4XaMDOAK57zF4miuC9qQJgysPNEAZZ9Z69rdF5LJkozGdZrjBIUAIyKUWRMmebI7vg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1112,8 +1214,9 @@ }, "node_modules/@babel/plugin-transform-function-name": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.16.7", "@babel/helper-function-name": "^7.16.7", @@ -1127,11 +1230,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz", + "integrity": "sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1142,8 +1246,9 @@ }, "node_modules/@babel/plugin-transform-member-expression-literals": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, @@ -1155,12 +1260,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.16.7", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.0.tgz", + "integrity": "sha512-h8FjOlYmdZwl7Xm2Ug4iX2j7Qy63NANI+NQVWQzv6r25fqgg7k2dZl03p95kvqNclglHs4FZ+isv4p1uXMA+QA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -1171,13 +1277,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.17.9", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.2.tgz", + "integrity": "sha512-f5A865gFPAJAEE0K7F/+nm5CmAE3y8AWlMBG9unu5j9+tk50UQVK0QS8RNxSp7MJf0wh97uYyLWt3Zvu71zyOQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-simple-access": "^7.18.2", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -1188,13 +1295,14 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.17.8", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.5.tgz", + "integrity": "sha512-SEewrhPpcqMF1V7DhnEbhVJLrC+nnYfe1E0piZMZXBpxi9WvZqWGwpsk7JYP7wPWeqaBh4gyKlBhHJu3uz5g4Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, @@ -1206,12 +1314,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.16.7", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.0.tgz", + "integrity": "sha512-d/zZ8I3BWli1tmROLxXLc9A6YXvGK8egMxHp+E/rRwMh1Kip0AP77VwZae3snEJ33iiWwvNv2+UIIhfalqhzZA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1221,11 +1330,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.17.10", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz", + "integrity": "sha512-vWoWFM5CKaTeHrdUJ/3SIOTRV+MBVGybOC9mhJkaprGNt5demMymDW24yC74avb915/mIRe3TgNb/d8idvnCRA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.17.0" + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1235,11 +1346,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.16.7", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.5.tgz", + "integrity": "sha512-TuRL5uGW4KXU6OsRj+mLp9BM7pO8e7SGNTEokQRRxHFkXYMFiy2jlKSZPFtI/mKORDzciH+hneskcSOp0gU8hg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1250,8 +1362,9 @@ }, "node_modules/@babel/plugin-transform-object-super": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-replace-supers": "^7.16.7" @@ -1264,11 +1377,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz", + "integrity": "sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1279,8 +1393,9 @@ }, "node_modules/@babel/plugin-transform-property-literals": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, @@ -1292,10 +1407,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.17.9", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.0.tgz", + "integrity": "sha512-C8YdRw9uzx25HSIzwA7EM7YP0FhCe5wNvJbZzjVNHHPGVcDJ3Aie+qGYYdS1oVQgn+B3eAIJbWFLrJ4Jipv7nw==", "dev": true, - "license": "MIT", "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", "regenerator-transform": "^0.15.0" }, "engines": { @@ -1306,11 +1423,12 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.17.12.tgz", + "integrity": "sha512-1KYqwbJV3Co03NIi14uEHW8P50Md6KqFgt0FfpHdK6oyAHQVTosgPuPSiWud1HX0oYJ1hGRRlk0fP87jFpqXZA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1321,8 +1439,9 @@ }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, @@ -1334,11 +1453,12 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz", + "integrity": "sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" }, "engines": { @@ -1350,8 +1470,9 @@ }, "node_modules/@babel/plugin-transform-sticky-regex": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, @@ -1363,11 +1484,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.16.7", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.2.tgz", + "integrity": "sha512-/cmuBVw9sZBGZVOMkpAEaVLwm4JmK2GZ1dFKOGGpMzEHWFmyZZ59lUU0PdRr8YNYeQdNzTDwuxP2X2gzydTc9g==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1377,11 +1499,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.17.12.tgz", + "integrity": "sha512-Q8y+Jp7ZdtSPXCThB6zjQ74N3lj0f6TDh1Hnf5B+sYlzQ8i5Pjp8gW0My79iekSpT4WnI06blqP6DT0OmaXXmw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -1392,8 +1515,9 @@ }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, @@ -1406,8 +1530,9 @@ }, "node_modules/@babel/plugin-transform-unicode-regex": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.16.7", "@babel/helper-plugin-utils": "^7.16.7" @@ -1420,36 +1545,38 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.17.10", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.2.tgz", + "integrity": "sha512-PfpdxotV6afmXMU47S08F9ZKIm2bJIQ0YbAAtDfIENX7G1NUAXigLREh69CWDjtgUy7dYn7bsMzkgdtAlmS68Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/compat-data": "^7.17.10", - "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-compilation-targets": "^7.18.2", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.17.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.17.12", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-async-generator-functions": "^7.17.12", + "@babel/plugin-proposal-class-properties": "^7.17.12", + "@babel/plugin-proposal-class-static-block": "^7.18.0", "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.17.12", + "@babel/plugin-proposal-json-strings": "^7.17.12", + "@babel/plugin-proposal-logical-assignment-operators": "^7.17.12", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12", "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.17.3", + "@babel/plugin-proposal-object-rest-spread": "^7.18.0", "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-private-methods": "^7.17.12", + "@babel/plugin-proposal-private-property-in-object": "^7.17.12", + "@babel/plugin-proposal-unicode-property-regex": "^7.17.12", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.17.12", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -1459,40 +1586,40 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", + "@babel/plugin-transform-arrow-functions": "^7.17.12", + "@babel/plugin-transform-async-to-generator": "^7.17.12", "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.17.7", + "@babel/plugin-transform-block-scoping": "^7.17.12", + "@babel/plugin-transform-classes": "^7.17.12", + "@babel/plugin-transform-computed-properties": "^7.17.12", + "@babel/plugin-transform-destructuring": "^7.18.0", "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.17.12", "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.18.1", "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", + "@babel/plugin-transform-literals": "^7.17.12", "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.17.9", - "@babel/plugin-transform-modules-systemjs": "^7.17.8", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.10", - "@babel/plugin-transform-new-target": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.18.0", + "@babel/plugin-transform-modules-commonjs": "^7.18.2", + "@babel/plugin-transform-modules-systemjs": "^7.18.0", + "@babel/plugin-transform-modules-umd": "^7.18.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.12", + "@babel/plugin-transform-new-target": "^7.17.12", "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.17.12", "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.17.9", - "@babel/plugin-transform-reserved-words": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.18.0", + "@babel/plugin-transform-reserved-words": "^7.17.12", "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", + "@babel/plugin-transform-spread": "^7.17.12", "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.18.2", + "@babel/plugin-transform-typeof-symbol": "^7.17.12", "@babel/plugin-transform-unicode-escapes": "^7.16.7", "@babel/plugin-transform-unicode-regex": "^7.16.7", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.17.10", + "@babel/types": "^7.18.2", "babel-plugin-polyfill-corejs2": "^0.3.0", "babel-plugin-polyfill-corejs3": "^0.5.0", "babel-plugin-polyfill-regenerator": "^0.3.0", @@ -1508,8 +1635,9 @@ }, "node_modules/@babel/preset-modules": { "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", @@ -1522,9 +1650,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.17.9", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.3.tgz", + "integrity": "sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==", "dev": true, - "license": "MIT", "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -1534,8 +1663,9 @@ }, "node_modules/@babel/template": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.16.7", "@babel/parser": "^7.16.7", @@ -1546,18 +1676,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.17.10", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.5.tgz", + "integrity": "sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.10", - "@babel/helper-environment-visitor": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-environment-visitor": "^7.18.2", "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.10", - "@babel/types": "^7.17.10", + "@babel/parser": "^7.18.5", + "@babel/types": "^7.18.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1566,9 +1697,10 @@ } }, "node_modules/@babel/types": { - "version": "7.17.10", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", + "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" @@ -1579,37 +1711,42 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspotcode/source-map-consumer": { - "version": "0.8.0", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 12" - } + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true }, "node_modules/@cspotcode/source-map-support": { - "version": "0.7.0", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "license": "MIT", "dependencies": { - "@cspotcode/source-map-consumer": "0.8.0" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { "node": ">=12" } }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.2.3", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.3.2", - "globals": "^13.9.0", + "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -1622,8 +1759,9 @@ }, "node_modules/@eslint/eslintrc/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, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1637,13 +1775,15 @@ }, "node_modules/@eslint/eslintrc/node_modules/argparse": { "version": "2.0.1", - "dev": true, - "license": "Python-2.0" + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -1656,8 +1796,9 @@ }, "node_modules/@eslint/eslintrc/node_modules/js-yaml": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -1667,13 +1808,15 @@ }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", - "dev": true, - "license": "MIT" + "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/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -1683,7 +1826,8 @@ }, "node_modules/@grpc/grpc-js": { "version": "1.6.7", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.6.7.tgz", + "integrity": "sha512-eBM03pu9hd3VqDQG+kHahiG1x80RGkkqqRb1Pchcwqej/KkAH95gAvKs6laqaHCycYaPK+TKuNQnOz9UXYA8qw==", "dependencies": { "@grpc/proto-loader": "^0.6.4", "@types/node": ">=12.12.47" @@ -1693,13 +1837,14 @@ } }, "node_modules/@grpc/proto-loader": { - "version": "0.6.12", - "license": "Apache-2.0", + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.13.tgz", + "integrity": "sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g==", "dependencies": { "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", "long": "^4.0.0", - "protobufjs": "^6.10.0", + "protobufjs": "^6.11.3", "yargs": "^16.2.0" }, "bin": { @@ -1711,8 +1856,9 @@ }, "node_modules/@humanwhocodes/config-array": { "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -1724,13 +1870,15 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true }, "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, - "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -1744,16 +1892,18 @@ }, "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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/console": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", "@types/node": "*", @@ -1768,8 +1918,9 @@ }, "node_modules/@jest/console/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -1782,8 +1933,9 @@ }, "node_modules/@jest/console/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1797,8 +1949,9 @@ }, "node_modules/@jest/console/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -1808,21 +1961,24 @@ }, "node_modules/@jest/console/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/@jest/console/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/console/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -1832,8 +1988,9 @@ }, "node_modules/@jest/core": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^27.5.1", "@jest/reporters": "^27.5.1", @@ -1878,8 +2035,9 @@ }, "node_modules/@jest/core/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -1892,8 +2050,9 @@ }, "node_modules/@jest/core/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1907,8 +2066,9 @@ }, "node_modules/@jest/core/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -1918,21 +2078,24 @@ }, "node_modules/@jest/core/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/@jest/core/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/core/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -1942,8 +2105,9 @@ }, "node_modules/@jest/environment": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", "dev": true, - "license": "MIT", "dependencies": { "@jest/fake-timers": "^27.5.1", "@jest/types": "^27.5.1", @@ -1956,8 +2120,9 @@ }, "node_modules/@jest/fake-timers": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", "@sinonjs/fake-timers": "^8.0.1", @@ -1972,8 +2137,9 @@ }, "node_modules/@jest/globals": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^27.5.1", "@jest/types": "^27.5.1", @@ -1985,8 +2151,9 @@ }, "node_modules/@jest/reporters": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", "dev": true, - "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^27.5.1", @@ -2028,8 +2195,9 @@ }, "node_modules/@jest/reporters/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2042,8 +2210,9 @@ }, "node_modules/@jest/reporters/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2057,8 +2226,9 @@ }, "node_modules/@jest/reporters/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2068,21 +2238,24 @@ }, "node_modules/@jest/reporters/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/reporters/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2092,8 +2265,9 @@ }, "node_modules/@jest/source-map": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", "dev": true, - "license": "MIT", "dependencies": { "callsites": "^3.0.0", "graceful-fs": "^4.2.9", @@ -2105,8 +2279,9 @@ }, "node_modules/@jest/test-result": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^27.5.1", "@jest/types": "^27.5.1", @@ -2119,8 +2294,9 @@ }, "node_modules/@jest/test-sequencer": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/test-result": "^27.5.1", "graceful-fs": "^4.2.9", @@ -2133,8 +2309,9 @@ }, "node_modules/@jest/transform": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.1.0", "@jest/types": "^27.5.1", @@ -2158,8 +2335,9 @@ }, "node_modules/@jest/transform/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2172,8 +2350,9 @@ }, "node_modules/@jest/transform/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2187,8 +2366,9 @@ }, "node_modules/@jest/transform/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2198,21 +2378,24 @@ }, "node_modules/@jest/transform/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/@jest/transform/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/transform/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2222,8 +2405,9 @@ }, "node_modules/@jest/types": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", "dev": true, - "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", @@ -2237,8 +2421,9 @@ }, "node_modules/@jest/types/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2251,8 +2436,9 @@ }, "node_modules/@jest/types/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2266,8 +2452,9 @@ }, "node_modules/@jest/types/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2277,21 +2464,24 @@ }, "node_modules/@jest/types/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/@jest/types/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/types/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2301,8 +2491,9 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -2313,29 +2504,33 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.13", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "dev": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", + "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -2343,7 +2538,8 @@ }, "node_modules/@matrixai/async-init": { "version": "1.7.3", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.7.3.tgz", + "integrity": "sha512-Sf3q5ODhVJqrYiAdGXmwj606956lgEMKGM9LMFU5scIOh13WokHo3GthjB1yh/umCV75NYvHJn60R9gnudVZ3Q==", "dependencies": { "@matrixai/async-locks": "^2.2.4", "@matrixai/errors": "^1.1.1" @@ -2353,7 +2549,6 @@ "version": "2.2.5", "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.2.5.tgz", "integrity": "sha512-Yokd3p64FciLNSW04Qox+UHJulxnWQIhHt3h9sMmgoiTsyZcOgeYfPAJrtZiRnhaUXhfBczPy4VPP2e5lrXgig==", - "license": "Apache-2.0", "dependencies": { "@matrixai/errors": "^1.1.1", "@matrixai/resources": "^1.1.3", @@ -2376,15 +2571,17 @@ } }, "node_modules/@matrixai/errors": { - "version": "1.1.1", - "license": "Apache-2.0", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.1.2.tgz", + "integrity": "sha512-JSi2SIqdlqqDruANrTG8RMvLrJZAwduY19y26LZHx7DDkqhkqzF9fblbWaE9Fo1lhSTGk65oKRx2UjGn3v5gWw==", "dependencies": { "ts-custom-error": "^3.2.0" } }, "node_modules/@matrixai/id": { "version": "3.3.3", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@matrixai/id/-/id-3.3.3.tgz", + "integrity": "sha512-eXkxv68sCT17f6XQU8zMwgLLqwbdFm+8DoL3gXfBqfiDYxOCCQBS4L9kjUby8gRdlP7mIpkJ6oVAWCUnykGInA==", "dependencies": { "multiformats": "^9.4.8", "uuid": "^8.3.2" @@ -2392,15 +2589,18 @@ }, "node_modules/@matrixai/logger": { "version": "2.1.1", - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.1.1.tgz", + "integrity": "sha512-79KM0PyJTpfkALf9DK2xGniU+9gngsb5O8hcdUviWz+zR2W0hnTQq/g7tJW0YnIEhmDe/GkJf0Bnbs+gWfj3BA==" }, "node_modules/@matrixai/resources": { "version": "1.1.3", - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/@matrixai/resources/-/resources-1.1.3.tgz", + "integrity": "sha512-9zbA0NtgCtA+2hILpojshH6Pd679bIPtB8DcsPLVDzvGZP1TDwvtvZWCC3SG7oJUTzxqBI2Bfe+hypqwpvYPCw==" }, "node_modules/@matrixai/workers": { "version": "1.3.3", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@matrixai/workers/-/workers-1.3.3.tgz", + "integrity": "sha512-ID1sSJDXjM0hdWC10euWGcFofuys7+IDP+XTBh8Gq6jirn18xJs71wSy357qxLVSa7mL00qRJJfW6rljcFUK4A==", "dependencies": { "@matrixai/async-init": "^1.7.3", "@matrixai/errors": "^1.1.1", @@ -2410,8 +2610,9 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -2422,16 +2623,18 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -2442,23 +2645,28 @@ }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -2466,76 +2674,90 @@ }, "node_modules/@protobufjs/float": { "version": "1.0.2", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" }, "node_modules/@protobufjs/path": { "version": "1.1.2", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "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, - "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", "dev": true, - "license": "BSD-3-Clause", "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, - "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/@tsconfig/node10": { - "version": "1.0.8", - "dev": true, - "license": "MIT" + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true }, "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "dev": true, - "license": "MIT" + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.10.tgz", + "integrity": "sha512-N+srakvPaYMGkwjNDx3ASx65Zl3QG8dJgVtIB+YMOkucU+zctlv/hdP5250VKdDHSDoW9PFZoCqbqNcAPjCjXA==", + "dev": true }, "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "dev": true, - "license": "MIT" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.2.tgz", + "integrity": "sha512-YwrUA5ysDXHFYfL0Xed9x3sNS4P+aKlCOnnbqUa2E5HdQshHFleCJVrj1PlGTb4GgFUCDyte1v3JWLy2sz8Oqg==", + "dev": true }, "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "dev": true, - "license": "MIT" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true }, "node_modules/@types/abstract-leveldown": { "version": "7.2.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-q5veSX6zjUy/DlDhR4Y4cU0k2Ar+DT2LUraP00T19WLmTO6Se1djepCCaqU6nQrwcJ5Hyo/CWqxTzrrFg8eqbQ==" }, "node_modules/@types/babel__core": { "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0", @@ -2546,16 +2768,18 @@ }, "node_modules/@types/babel__generator": { "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -2563,58 +2787,66 @@ }, "node_modules/@types/babel__traverse": { "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.3.0" } }, "node_modules/@types/cross-spawn": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.2.tgz", + "integrity": "sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/google-protobuf": { "version": "3.15.6", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.6.tgz", + "integrity": "sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw==", + "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, - "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "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, - "license": "MIT", "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, - "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/jest": { - "version": "27.5.1", + "version": "27.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz", + "integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==", "dev": true, - "license": "MIT", "dependencies": { "jest-matcher-utils": "^27.0.0", "pretty-format": "^27.0.0" @@ -2622,29 +2854,34 @@ }, "node_modules/@types/json-schema": { "version": "7.0.11", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true }, "node_modules/@types/json5": { "version": "0.0.29", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true }, "node_modules/@types/long": { "version": "4.0.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "node_modules/@types/nexpect": { "version": "0.4.31", + "resolved": "https://registry.npmjs.org/@types/nexpect/-/nexpect-0.4.31.tgz", + "integrity": "sha512-Plh9Dlj2AKdsblgF1Pv7s2BjlojqW93d1zIUtK5xVVrUjkZQezyWIOAq0Xfwp0e0SDQ70YmaDqzhoJru2kqVPA==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/node": { - "version": "16.11.35", - "license": "MIT" + "version": "16.11.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.39.tgz", + "integrity": "sha512-K0MsdV42vPwm9L6UwhIxMAOmcvH/1OoVkZyCgEtVu4Wx7sElGloy/W7kMBNe/oJ7V/jW9BVt1F6RahH6e7tPXw==" }, "node_modules/@types/node-forge": { "version": "0.10.10", @@ -2657,26 +2894,30 @@ }, "node_modules/@types/pako": { "version": "1.0.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.4.tgz", + "integrity": "sha512-Z+5bJSm28EXBSUJEgx29ioWeEEHUh6TiMkZHDhLwjc9wVFH+ressbkmX6waUZc5R3Gobn4Qu5llGxaoflZ+yhA==", + "dev": true }, "node_modules/@types/prettier": { - "version": "2.6.1", - "dev": true, - "license": "MIT" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", + "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", + "dev": true }, "node_modules/@types/prompts": { "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.14.tgz", + "integrity": "sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/readable-stream": { "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.13.tgz", + "integrity": "sha512-4JSCx8EUzaW9Idevt+9lsRAt1lcSccoQfE+AouM1gk8sFxnnytKNIO3wTl9Dy+4m6jRJ1yXhboLHHT/LXBQiEw==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "safe-buffer": "*" @@ -2684,40 +2925,45 @@ }, "node_modules/@types/stack-utils": { "version": "2.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true }, "node_modules/@types/uuid": { "version": "8.3.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true }, "node_modules/@types/yargs": { "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", "dev": true, - "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { "version": "21.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.28.0.tgz", + "integrity": "sha512-DXVU6Cg29H2M6EybqSg2A+x8DgO9TCUBRp4QEXQHJceLS7ogVDP0g3Lkg/SZCqcvkAP/RruuQqK0gdlkgmhSUA==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "5.23.0", - "@typescript-eslint/type-utils": "5.23.0", - "@typescript-eslint/utils": "5.23.0", - "debug": "^4.3.2", + "@typescript-eslint/scope-manager": "5.28.0", + "@typescript-eslint/type-utils": "5.28.0", + "@typescript-eslint/utils": "5.28.0", + "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", + "ignore": "^5.2.0", "regexpp": "^3.2.0", - "semver": "^7.3.5", + "semver": "^7.3.7", "tsutils": "^3.21.0" }, "engines": { @@ -2739,8 +2985,9 @@ }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -2752,14 +2999,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.28.0.tgz", + "integrity": "sha512-ekqoNRNK1lAcKhZESN/PdpVsWbP9jtiNqzFWkp/yAUdZvJalw2heCYuqRmM5eUJSIYEkgq5sGOjq+ZqsLMjtRA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "5.23.0", - "@typescript-eslint/types": "5.23.0", - "@typescript-eslint/typescript-estree": "5.23.0", - "debug": "^4.3.2" + "@typescript-eslint/scope-manager": "5.28.0", + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/typescript-estree": "5.28.0", + "debug": "^4.3.4" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2778,12 +3026,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.28.0.tgz", + "integrity": "sha512-LeBLTqF/he1Z+boRhSqnso6YrzcKMTQ8bO/YKEe+6+O/JGof9M0g3IJlIsqfrK/6K03MlFIlycbf1uQR1IjE+w==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.23.0", - "@typescript-eslint/visitor-keys": "5.23.0" + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/visitor-keys": "5.28.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2794,12 +3043,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.28.0.tgz", + "integrity": "sha512-SyKjKh4CXPglueyC6ceAFytjYWMoPHMswPQae236zqe1YbhvCVQyIawesYywGiu98L9DwrxsBN69vGIVxJ4mQQ==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "5.23.0", - "debug": "^4.3.2", + "@typescript-eslint/utils": "5.28.0", + "debug": "^4.3.4", "tsutils": "^3.21.0" }, "engines": { @@ -2819,9 +3069,10 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.28.0.tgz", + "integrity": "sha512-2OOm8ZTOQxqkPbf+DAo8oc16sDlVR5owgJfKheBkxBKg1vAfw2JsSofH9+16VPlN9PWtv8Wzhklkqw3k/zCVxA==", "dev": true, - "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -2831,16 +3082,17 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.28.0.tgz", + "integrity": "sha512-9GX+GfpV+F4hdTtYc6OV9ZkyYilGXPmQpm6AThInpBmKJEyRSIjORJd1G9+bknb7OTFYL+Vd4FBJAO6T78OVqA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "5.23.0", - "@typescript-eslint/visitor-keys": "5.23.0", - "debug": "^4.3.2", - "globby": "^11.0.4", + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/visitor-keys": "5.28.0", + "debug": "^4.3.4", + "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.5", + "semver": "^7.3.7", "tsutils": "^3.21.0" }, "engines": { @@ -2858,8 +3110,9 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -2871,14 +3124,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.28.0.tgz", + "integrity": "sha512-E60N5L0fjv7iPJV3UGc4EC+A3Lcj4jle9zzR0gW7vXhflO7/J29kwiTGITA2RlrmPokKiZbBy2DgaclCaEUs6g==", "dev": true, - "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.23.0", - "@typescript-eslint/types": "5.23.0", - "@typescript-eslint/typescript-estree": "5.23.0", + "@typescript-eslint/scope-manager": "5.28.0", + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/typescript-estree": "5.28.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -2894,12 +3148,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.28.0.tgz", + "integrity": "sha512-BtfP1vCor8cWacovzzPFOoeW4kBQxzmhxGoOpt0v1SFvG+nJ0cWaVdJk7cky1ArTcFHHKNIxyo2LLr3oNkSuXA==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.23.0", - "eslint-visitor-keys": "^3.0.0" + "@typescript-eslint/types": "5.28.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2911,12 +3166,14 @@ }, "node_modules/abab": { "version": "2.0.6", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true }, "node_modules/abstract-leveldown": { "version": "7.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", "dependencies": { "buffer": "^6.0.3", "catering": "^2.0.0", @@ -2931,8 +3188,9 @@ }, "node_modules/acorn": { "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2942,8 +3200,9 @@ }, "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, - "license": "MIT", "dependencies": { "acorn": "^7.1.1", "acorn-walk": "^7.1.1" @@ -2951,8 +3210,9 @@ }, "node_modules/acorn-globals/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, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2962,24 +3222,27 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "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, - "license": "MIT", "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, - "license": "MIT", "dependencies": { "debug": "4" }, @@ -2989,7 +3252,8 @@ }, "node_modules/ajv": { "version": "7.2.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.4.tgz", + "integrity": "sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -3003,8 +3267,9 @@ }, "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, - "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -3017,15 +3282,17 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "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, - "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -3035,8 +3302,9 @@ }, "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, - "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -3047,13 +3315,15 @@ }, "node_modules/aproba": { "version": "1.2.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true }, "node_modules/are-we-there-yet": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", "dev": true, - "license": "ISC", "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -3061,8 +3331,9 @@ }, "node_modules/are-we-there-yet/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, - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3075,34 +3346,39 @@ }, "node_modules/are-we-there-yet/node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/are-we-there-yet/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, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/arg": { "version": "4.1.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true }, "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, - "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } }, "node_modules/array-includes": { "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -3119,16 +3395,18 @@ }, "node_modules/array-union": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/array.prototype.flat": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -3142,34 +3420,57 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.reduce": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz", + "integrity": "sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/async-lock": { "version": "1.3.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.3.1.tgz", + "integrity": "sha512-zK7xap9UnttfbE23JmcrNIyueAn6jWshihJqA33U/hEnKprF/lVGBDsBv/bqLm2YMMl1DnpHhUY044eA0t1TUw==" }, "node_modules/async-mutex": { "version": "0.3.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", + "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", "dependencies": { "tslib": "^2.3.1" } }, "node_modules/asynckit": { "version": "0.4.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true }, "node_modules/at-least-node": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, - "license": "ISC", "engines": { "node": ">= 4.0.0" } }, "node_modules/babel-jest": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/transform": "^27.5.1", "@jest/types": "^27.5.1", @@ -3189,8 +3490,9 @@ }, "node_modules/babel-jest/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3203,8 +3505,9 @@ }, "node_modules/babel-jest/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3218,8 +3521,9 @@ }, "node_modules/babel-jest/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3229,21 +3533,24 @@ }, "node_modules/babel-jest/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/babel-jest/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/babel-jest/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3253,16 +3560,18 @@ }, "node_modules/babel-plugin-dynamic-import-node": { "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", "dev": true, - "license": "MIT", "dependencies": { "object.assign": "^4.1.0" } }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -3276,8 +3585,9 @@ }, "node_modules/babel-plugin-jest-hoist": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -3290,8 +3600,9 @@ }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", "dev": true, - "license": "MIT", "dependencies": { "@babel/compat-data": "^7.13.11", "@babel/helper-define-polyfill-provider": "^0.3.1", @@ -3303,8 +3614,9 @@ }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.3.1", "core-js-compat": "^3.21.0" @@ -3315,8 +3627,9 @@ }, "node_modules/babel-plugin-polyfill-regenerator": { "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.3.1" }, @@ -3326,8 +3639,9 @@ }, "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, - "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -3348,8 +3662,9 @@ }, "node_modules/babel-preset-jest": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", "dev": true, - "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^27.5.1", "babel-preset-current-node-syntax": "^1.0.0" @@ -3363,7 +3678,8 @@ }, "node_modules/babel-runtime": { "version": "6.26.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", "dependencies": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" @@ -3371,15 +3687,19 @@ }, "node_modules/babel-runtime/node_modules/regenerator-runtime": { "version": "0.11.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, "node_modules/balanced-match": { "version": "1.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/base64-js": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -3393,12 +3713,12 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/bip39": { "version": "3.0.4", - "license": "ISC", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz", + "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==", "dependencies": { "@types/node": "11.11.6", "create-hash": "^1.1.0", @@ -3408,19 +3728,22 @@ }, "node_modules/bip39/node_modules/@types/node": { "version": "11.11.6", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", + "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" }, "node_modules/bitset": { "version": "5.1.1", - "license": "MIT OR GPL-2.0", + "resolved": "https://registry.npmjs.org/bitset/-/bitset-5.1.1.tgz", + "integrity": "sha512-oKaRp6mzXedJ1Npo86PKhWfDelI6HxxJo+it9nAcBB0HLVvYVp+5i6yj6DT5hfFgo+TS5T57MRWtw8zhwdTs3g==", "engines": { "node": "*" } }, "node_modules/bl": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, - "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -3429,6 +3752,8 @@ }, "node_modules/bl/node_modules/buffer": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "funding": [ { @@ -3444,7 +3769,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -3452,12 +3776,14 @@ }, "node_modules/boolbase": { "version": "1.0.0", - "license": "ISC" + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, "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, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3465,8 +3791,9 @@ }, "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, - "license": "MIT", "dependencies": { "fill-range": "^7.0.1" }, @@ -3476,11 +3803,14 @@ }, "node_modules/browser-process-hrtime": { "version": "1.0.0", - "dev": true, - "license": "BSD-2-Clause" + "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.20.3", + "version": "4.20.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.4.tgz", + "integrity": "sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw==", "dev": true, "funding": [ { @@ -3492,12 +3822,11 @@ "url": "https://tidelift.com/funding/github/npm/browserslist" } ], - "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", + "caniuse-lite": "^1.0.30001349", + "electron-to-chromium": "^1.4.147", "escalade": "^3.1.1", - "node-releases": "^2.0.3", + "node-releases": "^2.0.5", "picocolors": "^1.0.0" }, "bin": { @@ -3509,8 +3838,9 @@ }, "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, - "license": "MIT", "dependencies": { "fast-json-stable-stringify": "2.x" }, @@ -3520,14 +3850,17 @@ }, "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, - "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } }, "node_modules/buffer": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -3542,7 +3875,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -3550,12 +3882,14 @@ }, "node_modules/buffer-from": { "version": "1.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true }, "node_modules/call-bind": { "version": "1.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -3566,21 +3900,25 @@ }, "node_modules/callsites": { "version": "3.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "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, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001340", + "version": "1.0.30001352", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz", + "integrity": "sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA==", "dev": true, "funding": [ { @@ -3591,24 +3929,26 @@ "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" } - ], - "license": "CC-BY-4.0" + ] }, "node_modules/canonicalize": { "version": "1.0.8", - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-1.0.8.tgz", + "integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==" }, "node_modules/catering": { "version": "2.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", "engines": { "node": ">=6" } }, "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, - "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -3620,31 +3960,35 @@ }, "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, - "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/check-more-types": { "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/cheerio": { - "version": "1.0.0-rc.10", - "license": "MIT", + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.11.tgz", + "integrity": "sha512-bQwNaDIBKID5ts/DsdhxrjqFXYfLw4ste+wMKqWA8DyKcS4qwsPP4Bk8ZNaTJjvpiX/qW3BT4sU7d6Bh5i+dag==", "dependencies": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "tslib": "^2.4.0" }, "engines": { "node": ">= 6" @@ -3654,14 +3998,16 @@ } }, "node_modules/cheerio-select": { - "version": "1.6.0", - "license": "BSD-2-Clause", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", "dependencies": { - "css-select": "^4.3.0", - "css-what": "^6.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.3.1", - "domutils": "^2.8.0" + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" }, "funding": { "url": "https://github.com/sponsors/fb55" @@ -3669,17 +4015,20 @@ }, "node_modules/chownr": { "version": "1.1.4", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true }, "node_modules/ci-info": { "version": "3.3.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", + "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==", + "dev": true }, "node_modules/cipher-base": { "version": "1.0.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -3687,16 +4036,19 @@ }, "node_modules/cjs-module-lexer": { "version": "1.2.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true }, "node_modules/clean-git-ref": { "version": "2.0.1", - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", + "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==" }, "node_modules/cliui": { "version": "7.0.4", - "license": "ISC", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -3705,14 +4057,16 @@ }, "node_modules/cliui/node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { "node": ">=8" } }, "node_modules/cliui/node_modules/string-width": { "version": "4.2.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3724,8 +4078,9 @@ }, "node_modules/co": { "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, - "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -3733,34 +4088,39 @@ }, "node_modules/code-point-at": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/collect-v8-coverage": { "version": "1.0.1", - "dev": true, - "license": "MIT" + "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, - "license": "MIT", "dependencies": { "color-name": "1.1.3" } }, "node_modules/color-name": { "version": "1.1.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "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, - "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -3770,45 +4130,53 @@ }, "node_modules/commander": { "version": "8.3.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "engines": { "node": ">= 12" } }, "node_modules/concat-map": { "version": "0.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "node_modules/console-control-strings": { "version": "1.1.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "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, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.1" } }, "node_modules/convert-source-map/node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/core-js": { "version": "2.6.12", - "hasInstallScript": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.", + "hasInstallScript": true }, "node_modules/core-js-compat": { - "version": "3.22.5", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.0.tgz", + "integrity": "sha512-i4FgbtahOArZBEteiL+czI5N/bp17w16bXmLagGThdA2zuX1a5X4HbBmOVD7ERRtk3wMtPOFEmlXpVV4lsvwNw==", "dev": true, - "license": "MIT", "dependencies": { - "browserslist": "^4.20.3", + "browserslist": "^4.20.4", "semver": "7.0.0" }, "funding": { @@ -3818,20 +4186,23 @@ }, "node_modules/core-js-compat/node_modules/semver": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/core-util-is": { "version": "1.0.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true }, "node_modules/crc-32": { "version": "1.2.2", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "bin": { "crc32": "bin/crc32.njs" }, @@ -3841,7 +4212,8 @@ }, "node_modules/create-hash": { "version": "1.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -3852,7 +4224,8 @@ }, "node_modules/create-hmac": { "version": "1.1.7", - "license": "MIT", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -3864,19 +4237,22 @@ }, "node_modules/create-require": { "version": "1.1.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true }, "node_modules/cross-fetch": { "version": "3.1.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", "dependencies": { "node-fetch": "2.6.7" } }, "node_modules/cross-spawn": { "version": "7.0.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3887,13 +4263,14 @@ } }, "node_modules/css-select": { - "version": "4.3.0", - "license": "BSD-2-Clause", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dependencies": { "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", "nth-check": "^2.0.1" }, "funding": { @@ -3902,7 +4279,8 @@ }, "node_modules/css-what": { "version": "6.1.0", - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "engines": { "node": ">= 6" }, @@ -3912,13 +4290,15 @@ }, "node_modules/cssom": { "version": "0.4.4", - "dev": true, - "license": "MIT" + "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, - "license": "MIT", "dependencies": { "cssom": "~0.3.6" }, @@ -3928,13 +4308,15 @@ }, "node_modules/cssstyle/node_modules/cssom": { "version": "0.3.8", - "dev": true, - "license": "MIT" + "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, - "license": "MIT", "dependencies": { "abab": "^2.0.3", "whatwg-mimetype": "^2.3.0", @@ -3946,7 +4328,8 @@ }, "node_modules/debug": { "version": "4.3.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -3961,12 +4344,14 @@ }, "node_modules/decimal.js": { "version": "10.3.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true }, "node_modules/decompress-response": { "version": "6.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dependencies": { "mimic-response": "^3.1.0" }, @@ -3979,33 +4364,38 @@ }, "node_modules/dedent": { "version": "0.7.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true }, "node_modules/deep-extend": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4.0.0" } }, "node_modules/deep-is": { "version": "0.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "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, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/deferred-leveldown": { "version": "7.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-7.0.0.tgz", + "integrity": "sha512-QKN8NtuS3BC6m0B8vAnBls44tX1WXAFATUsJlruyAYbZpysWV3siH6o/i3g9DCHauzodksO60bdj5NazNbjCmg==", "dependencies": { "abstract-leveldown": "^7.2.0", "inherits": "^2.0.3" @@ -4016,7 +4406,8 @@ }, "node_modules/define-properties": { "version": "1.1.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -4030,21 +4421,24 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/delegates": { "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true }, "node_modules/detect-libc": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true, - "license": "Apache-2.0", "bin": { "detect-libc": "bin/detect-libc.js" }, @@ -4054,36 +4448,41 @@ }, "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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/diff": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, "node_modules/diff-sequences": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", "dev": true, - "license": "MIT", "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/diff3": { "version": "0.0.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==" }, "node_modules/dir-glob": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, - "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -4093,8 +4492,9 @@ }, "node_modules/doctrine": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -4103,12 +4503,13 @@ } }, "node_modules/dom-serializer": { - "version": "1.4.1", - "license": "MIT", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" }, "funding": { "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" @@ -4116,18 +4517,20 @@ }, "node_modules/domelementtype": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/fb55" } - ], - "license": "BSD-2-Clause" + ] }, "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, - "license": "MIT", "dependencies": { "webidl-conversions": "^5.0.0" }, @@ -4137,17 +4540,19 @@ }, "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, - "license": "BSD-2-Clause", "engines": { "node": ">=8" } }, "node_modules/domhandler": { - "version": "4.3.1", - "license": "BSD-2-Clause", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dependencies": { - "domelementtype": "^2.2.0" + "domelementtype": "^2.3.0" }, "engines": { "node": ">= 4" @@ -4157,26 +4562,29 @@ } }, "node_modules/domutils": { - "version": "2.8.0", - "license": "BSD-2-Clause", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" }, "funding": { "url": "https://github.com/fb55/domutils?sponsor=1" } }, "node_modules/electron-to-chromium": { - "version": "1.4.137", - "dev": true, - "license": "ISC" + "version": "1.4.154", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.154.tgz", + "integrity": "sha512-GbV9djOkrnj6xmW+YYVVEI3VCQnJ0pnSTu7TW2JyjKd5cakoiSaG5R4RbEtfaD92GsY10DzbU3GYRe+IOA9kqA==", + "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, - "license": "MIT", "engines": { "node": ">=10" }, @@ -4186,11 +4594,13 @@ }, "node_modules/emoji-regex": { "version": "8.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/encoding-down": { "version": "7.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-7.1.0.tgz", + "integrity": "sha512-ky47X5jP84ryk5EQmvedQzELwVJPjCgXDQZGeb9F6r4PdChByCGHTBrVcF3h8ynKVJ1wVbkxTsDC8zBROPypgQ==", "dependencies": { "abstract-leveldown": "^7.2.0", "inherits": "^2.0.3", @@ -4205,7 +4615,6 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/encryptedfs/-/encryptedfs-3.5.3.tgz", "integrity": "sha512-2cTz6/8lUF2WFv6YNA9RwSASBh6bHIJqCbOWFr1RCo/vEHeR1+OKK0F+Xu4ujBlLsz3/a6NwT6/UoHl8Zn5rCg==", - "license": "Apache-2.0", "dependencies": { "@matrixai/async-init": "^1.7.3", "@matrixai/async-locks": "^2.2.4", @@ -4225,29 +4634,36 @@ }, "node_modules/encryptedfs/node_modules/node-forge": { "version": "1.3.1", - "license": "(BSD-3-Clause OR GPL-2.0)", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "engines": { "node": ">= 6.13.0" } }, "node_modules/end-of-stream": { "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, - "license": "MIT", "dependencies": { "once": "^1.4.0" } }, "node_modules/entities": { - "version": "2.2.0", - "license": "BSD-2-Clause", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.0.tgz", + "integrity": "sha512-/iP1rZrSEJ0DTlPiX+jbzlA3eVkY/e8L8SozroF395fIqE3TYF/Nz7YOMAawta+vLmyJ/hkGNNPcSbMADCCXbg==", + "engines": { + "node": ">=0.12" + }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/errno": { "version": "0.1.8", - "license": "MIT", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dependencies": { "prr": "~1.0.1" }, @@ -4257,15 +4673,17 @@ }, "node_modules/error-ex": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, - "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-abstract": { - "version": "1.20.0", - "license": "MIT", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -4286,7 +4704,7 @@ "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.1", + "regexp.prototype.flags": "^1.4.3", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" @@ -4298,17 +4716,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, "node_modules/es-shim-unscopables": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", "dev": true, - "license": "MIT", "dependencies": { "has": "^1.0.3" } }, "node_modules/es-to-primitive": { "version": "1.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -4323,23 +4748,26 @@ }, "node_modules/escalade": { "version": "3.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "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": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, - "license": "MIT", "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, - "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", @@ -4359,16 +4787,18 @@ }, "node_modules/escodegen/node_modules/estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "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": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "dev": true, - "license": "MIT", "dependencies": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -4379,8 +4809,9 @@ }, "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, - "license": "MIT", "dependencies": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.6", @@ -4395,6 +4826,8 @@ }, "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": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -4402,8 +4835,9 @@ }, "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": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", "dev": true, - "license": "MIT", "dependencies": { "prelude-ls": "~1.1.2" }, @@ -4412,11 +4846,12 @@ } }, "node_modules/eslint": { - "version": "8.15.0", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.17.0.tgz", + "integrity": "sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw==", "dev": true, - "license": "MIT", "dependencies": { - "@eslint/eslintrc": "^1.2.3", + "@eslint/eslintrc": "^1.3.0", "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", @@ -4434,7 +4869,7 @@ "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", - "globals": "^13.6.0", + "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -4464,8 +4899,9 @@ }, "node_modules/eslint-config-prettier": { "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", "dev": true, - "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -4475,8 +4911,9 @@ }, "node_modules/eslint-import-resolver-node": { "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^3.2.7", "resolve": "^1.20.0" @@ -4484,16 +4921,18 @@ }, "node_modules/eslint-import-resolver-node/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-module-utils": { "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^3.2.7", "find-up": "^2.1.0" @@ -4504,16 +4943,18 @@ }, "node_modules/eslint-module-utils/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-module-utils/node_modules/find-up": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", "dev": true, - "license": "MIT", "dependencies": { "locate-path": "^2.0.0" }, @@ -4523,8 +4964,9 @@ }, "node_modules/eslint-module-utils/node_modules/locate-path": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", "dev": true, - "license": "MIT", "dependencies": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" @@ -4535,8 +4977,9 @@ }, "node_modules/eslint-module-utils/node_modules/p-limit": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, - "license": "MIT", "dependencies": { "p-try": "^1.0.0" }, @@ -4546,8 +4989,9 @@ }, "node_modules/eslint-module-utils/node_modules/p-locate": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", "dev": true, - "license": "MIT", "dependencies": { "p-limit": "^1.1.0" }, @@ -4557,24 +5001,27 @@ }, "node_modules/eslint-module-utils/node_modules/p-try": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/eslint-module-utils/node_modules/path-exists": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/eslint-plugin-import": { "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, - "license": "MIT", "dependencies": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", @@ -4599,16 +5046,18 @@ }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -4618,13 +5067,15 @@ }, "node_modules/eslint-plugin-import/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true }, "node_modules/eslint-plugin-prettier": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", + "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", "dev": true, - "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.0" }, @@ -4643,8 +5094,9 @@ }, "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, - "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -4655,8 +5107,9 @@ }, "node_modules/eslint-utils": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, - "license": "MIT", "dependencies": { "eslint-visitor-keys": "^2.0.0" }, @@ -4672,24 +5125,27 @@ }, "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10" } }, "node_modules/eslint-visitor-keys": { "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/eslint/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, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -4703,8 +5159,9 @@ }, "node_modules/eslint/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -4717,13 +5174,15 @@ }, "node_modules/eslint/node_modules/argparse": { "version": "2.0.1", - "dev": true, - "license": "Python-2.0" + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -4737,8 +5196,9 @@ }, "node_modules/eslint/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -4748,13 +5208,15 @@ }, "node_modules/eslint/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -4764,8 +5226,9 @@ }, "node_modules/eslint/node_modules/eslint-scope": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -4776,16 +5239,18 @@ }, "node_modules/eslint/node_modules/estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/eslint/node_modules/globals": { "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -4798,16 +5263,18 @@ }, "node_modules/eslint/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/eslint/node_modules/js-yaml": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -4817,13 +5284,15 @@ }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", - "dev": true, - "license": "MIT" + "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/eslint/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -4833,8 +5302,9 @@ }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -4844,7 +5314,8 @@ }, "node_modules/esm": { "version": "3.2.25", - "license": "MIT", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", "optional": true, "engines": { "node": ">=6" @@ -4852,8 +5323,9 @@ }, "node_modules/espree": { "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.7.1", "acorn-jsx": "^5.3.2", @@ -4865,8 +5337,9 @@ }, "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, - "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -4877,8 +5350,9 @@ }, "node_modules/esquery": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -4888,16 +5362,18 @@ }, "node_modules/esquery/node_modules/estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "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, - "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -4907,32 +5383,36 @@ }, "node_modules/esrecurse/node_modules/estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "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, - "license": "BSD-2-Clause", "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, - "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/execa": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, - "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -4953,6 +5433,8 @@ }, "node_modules/exit": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -4960,16 +5442,18 @@ }, "node_modules/expand-template": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "dev": true, - "license": "(MIT OR WTFPL)", "engines": { "node": ">=6" } }, "node_modules/expect": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", "jest-get-type": "^27.5.1", @@ -4982,24 +5466,28 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-diff": { "version": "1.2.0", - "dev": true, - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true }, "node_modules/fast-fuzzy": { - "version": "1.11.1", - "license": "ISC", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/fast-fuzzy/-/fast-fuzzy-1.11.2.tgz", + "integrity": "sha512-H1ct10Pzx+pSO4h7F1uBXET91ay2hy67J1aQZFKL23EXsOoanpwjPNQQoc+NhClKJMmlGGN+0bXhIdFJX70BJw==", "dependencies": { "graphemesplit": "^2.4.1" } }, "node_modules/fast-glob": { "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -5013,8 +5501,9 @@ }, "node_modules/fast-glob/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, - "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -5024,34 +5513,39 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "dev": true, - "license": "MIT" + "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", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true }, "node_modules/fastq": { "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, - "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "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, - "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } }, "node_modules/fd-lock": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fd-lock/-/fd-lock-1.2.0.tgz", + "integrity": "sha512-Lk/pKH2DldLpG4Yh/sOOY84k5VqNzxHPffGwf1+yYI+/qMXzTPp9KJMX+Wh6n4xqGSA1Mu7JPmaDArfJGw2O/A==", "hasInstallScript": true, - "license": "MIT", "dependencies": { "napi-macros": "^2.0.0", "node-gyp-build": "^4.2.2" @@ -5059,8 +5553,9 @@ }, "node_modules/file-entry-cache": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -5070,8 +5565,9 @@ }, "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, - "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5081,8 +5577,9 @@ }, "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, - "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -5093,8 +5590,9 @@ }, "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, - "license": "MIT", "dependencies": { "flatted": "^3.1.0", "rimraf": "^3.0.2" @@ -5105,13 +5603,15 @@ }, "node_modules/flatted": { "version": "3.2.5", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": 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, - "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -5123,8 +5623,9 @@ }, "node_modules/from2": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", "dev": true, - "license": "MIT", "dependencies": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" @@ -5132,8 +5633,9 @@ }, "node_modules/from2/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, - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -5146,26 +5648,30 @@ }, "node_modules/from2/node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/from2/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, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/fs-constants": { "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true }, "node_modules/fs-extra": { "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, - "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -5178,16 +5684,33 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "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, - "license": "ISC" + "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", - "license": "MIT" + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/function.prototype.name": { "version": "1.1.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -5203,20 +5726,23 @@ }, "node_modules/functional-red-black-tree": { "version": "1.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true }, "node_modules/functions-have-names": { "version": "1.2.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/gauge": { "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", "dev": true, - "license": "ISC", "dependencies": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -5230,16 +5756,18 @@ }, "node_modules/gauge/node_modules/ansi-regex": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/gauge/node_modules/strip-ansi": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -5249,26 +5777,29 @@ }, "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, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/get-caller-file": { "version": "2.0.5", - "license": "ISC", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "license": "MIT", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5276,16 +5807,18 @@ }, "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, - "license": "MIT", "engines": { "node": ">=8.0.0" } }, "node_modules/get-stream": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -5295,7 +5828,8 @@ }, "node_modules/get-symbol-description": { "version": "1.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -5309,18 +5843,20 @@ }, "node_modules/github-from-package": { "version": "0.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true }, "node_modules/glob": { - "version": "7.2.0", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, - "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -5333,8 +5869,9 @@ }, "node_modules/glob-parent": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -5344,16 +5881,18 @@ }, "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, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/globby": { "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -5371,16 +5910,19 @@ }, "node_modules/google-protobuf": { "version": "3.20.1", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.20.1.tgz", + "integrity": "sha512-XMf1+O32FjYIV3CYu6Tuh5PNbfNEU5Xu22X+Xkdb/DUexFlCzhvv7d5Iirm4AOwn8lv4al1YvIhzGrg2j9Zfzw==" }, "node_modules/graceful-fs": { "version": "4.2.10", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true }, "node_modules/graphemesplit": { "version": "2.4.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/graphemesplit/-/graphemesplit-2.4.4.tgz", + "integrity": "sha512-lKrpp1mk1NH26USxC/Asw4OHbhSQf5XfrWZ+CDv/dFVvd1j17kFgMotdJvOesmHkbFX9P9sBfpH8VogxOWLg8w==", "dependencies": { "js-base64": "^3.6.0", "unicode-trie": "^2.0.0" @@ -5388,8 +5930,9 @@ }, "node_modules/grpc_tools_node_protoc_ts": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/grpc_tools_node_protoc_ts/-/grpc_tools_node_protoc_ts-5.3.2.tgz", + "integrity": "sha512-7xPSeu8bwjcird3i9R5+9O4BF2Lhv9fMBdeobfUc2Bys9tSVtm/VB3WjTpKV78WlLYJyD94+wL/8hJqaMZ53Hw==", "dev": true, - "license": "MIT", "dependencies": { "google-protobuf": "3.15.8", "handlebars": "4.7.7" @@ -5400,13 +5943,15 @@ }, "node_modules/grpc_tools_node_protoc_ts/node_modules/google-protobuf": { "version": "3.15.8", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.15.8.tgz", + "integrity": "sha512-2jtfdqTaSxk0cuBJBtTTWsot4WtR9RVr2rXg7x7OoqiuOKopPrwXpM1G4dXIkLcUNRh3RKzz76C8IOkksZSeOw==", + "dev": true }, "node_modules/handlebars": { "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, - "license": "MIT", "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.0", @@ -5425,7 +5970,8 @@ }, "node_modules/has": { "version": "1.0.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dependencies": { "function-bind": "^1.1.1" }, @@ -5435,22 +5981,25 @@ }, "node_modules/has-bigints": { "version": "1.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/has-property-descriptors": { "version": "1.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", "dependencies": { "get-intrinsic": "^1.1.1" }, @@ -5460,7 +6009,8 @@ }, "node_modules/has-symbols": { "version": "1.0.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "engines": { "node": ">= 0.4" }, @@ -5470,7 +6020,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dependencies": { "has-symbols": "^1.0.2" }, @@ -5483,12 +6034,14 @@ }, "node_modules/has-unicode": { "version": "2.0.1", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true }, "node_modules/hash-base": { "version": "3.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "dependencies": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", @@ -5500,8 +6053,9 @@ }, "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, - "license": "MIT", "dependencies": { "whatwg-encoding": "^1.0.5" }, @@ -5511,11 +6065,14 @@ }, "node_modules/html-escaper": { "version": "2.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true }, "node_modules/htmlparser2": { - "version": "6.1.0", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -5523,18 +6080,18 @@ "url": "https://github.com/sponsors/fb55" } ], - "license": "MIT", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" } }, "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, - "license": "MIT", "dependencies": { "@tootallnate/once": "1", "agent-base": "6", @@ -5546,8 +6103,9 @@ }, "node_modules/https-proxy-agent": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, - "license": "MIT", "dependencies": { "agent-base": "6", "debug": "4" @@ -5558,16 +6116,18 @@ }, "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, - "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, "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, - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -5577,6 +6137,8 @@ }, "node_modules/ieee754": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -5590,20 +6152,21 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "BSD-3-Clause" + ] }, "node_modules/ignore": { "version": "5.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "engines": { "node": ">= 4" } }, "node_modules/import-fresh": { "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, - "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -5617,16 +6180,18 @@ }, "node_modules/import-fresh/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, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/import-local": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, - "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -5643,16 +6208,18 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.8.19" } }, "node_modules/inflight": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, - "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -5660,16 +6227,19 @@ }, "node_modules/inherits": { "version": "2.0.4", - "license": "ISC" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "1.3.8", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true }, "node_modules/internal-slot": { "version": "1.0.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "dependencies": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", @@ -5690,8 +6260,9 @@ }, "node_modules/into-stream": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", + "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", "dev": true, - "license": "MIT", "dependencies": { "from2": "^2.3.0", "p-is-promise": "^3.0.0" @@ -5705,16 +6276,19 @@ }, "node_modules/ip-num": { "version": "1.4.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/ip-num/-/ip-num-1.4.0.tgz", + "integrity": "sha512-MP+gq4uBvrvm+G7EwP14GcJeFK49/p6sZrNOarMUoExLRodULJQM8mnkb/SbT1YKxRsZfh8rgwei2pUJIa35jA==" }, "node_modules/is-arrayish": { "version": "0.2.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true }, "node_modules/is-bigint": { "version": "1.0.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dependencies": { "has-bigints": "^1.0.1" }, @@ -5724,7 +6298,8 @@ }, "node_modules/is-boolean-object": { "version": "1.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -5738,6 +6313,8 @@ }, "node_modules/is-buffer": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", "funding": [ { "type": "github", @@ -5752,14 +6329,14 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/is-callable": { "version": "1.2.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "engines": { "node": ">= 0.4" }, @@ -5769,8 +6346,9 @@ }, "node_modules/is-core-module": { "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, - "license": "MIT", "dependencies": { "has": "^1.0.3" }, @@ -5780,7 +6358,8 @@ }, "node_modules/is-date-object": { "version": "1.0.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5793,16 +6372,18 @@ }, "node_modules/is-extglob": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-fullwidth-code-point": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "dev": true, - "license": "MIT", "dependencies": { "number-is-nan": "^1.0.0" }, @@ -5812,16 +6393,18 @@ }, "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, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/is-glob": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, - "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -5831,7 +6414,8 @@ }, "node_modules/is-negative-zero": { "version": "2.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "engines": { "node": ">= 0.4" }, @@ -5841,15 +6425,17 @@ }, "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, - "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-number-object": { "version": "1.0.7", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5862,7 +6448,8 @@ }, "node_modules/is-observable": { "version": "2.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-2.1.0.tgz", + "integrity": "sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw==", "engines": { "node": ">=8" }, @@ -5872,12 +6459,14 @@ }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", - "dev": true, - "license": "MIT" + "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-regex": { "version": "1.1.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -5891,7 +6480,8 @@ }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dependencies": { "call-bind": "^1.0.2" }, @@ -5901,8 +6491,9 @@ }, "node_modules/is-stream": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -5912,7 +6503,8 @@ }, "node_modules/is-string": { "version": "1.0.7", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5925,7 +6517,8 @@ }, "node_modules/is-symbol": { "version": "1.0.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dependencies": { "has-symbols": "^1.0.2" }, @@ -5938,12 +6531,14 @@ }, "node_modules/is-typedarray": { "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true }, "node_modules/is-weakref": { "version": "1.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dependencies": { "call-bind": "^1.0.2" }, @@ -5953,16 +6548,19 @@ }, "node_modules/isarray": { "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true }, "node_modules/isexe": { "version": "2.0.0", - "license": "ISC" + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/isomorphic-git": { - "version": "1.17.2", - "license": "MIT", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.18.1.tgz", + "integrity": "sha512-SNYmHxzDMwmB0N5jNaac9xmUOYv9VpWqBoPVQFvPEp47dfREOfsWy32IDEM00jzrDLGn+GsaPL2j6RYIDaKtJw==", "dependencies": { "async-lock": "^1.1.0", "clean-git-ref": "^2.0.1", @@ -5985,16 +6583,18 @@ }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -6008,8 +6608,9 @@ }, "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, - "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^3.0.0", @@ -6021,16 +6622,18 @@ }, "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, - "license": "MIT", "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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6040,8 +6643,9 @@ }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -6053,8 +6657,9 @@ }, "node_modules/istanbul-reports": { "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -6065,8 +6670,9 @@ }, "node_modules/jest": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/core": "^27.5.1", "import-local": "^3.0.2", @@ -6089,8 +6695,9 @@ }, "node_modules/jest-changed-files": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", "execa": "^5.0.0", @@ -6102,8 +6709,9 @@ }, "node_modules/jest-circus": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^27.5.1", "@jest/test-result": "^27.5.1", @@ -6131,8 +6739,9 @@ }, "node_modules/jest-circus/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6145,8 +6754,9 @@ }, "node_modules/jest-circus/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6160,8 +6770,9 @@ }, "node_modules/jest-circus/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -6171,21 +6782,24 @@ }, "node_modules/jest-circus/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-circus/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-circus/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6195,8 +6809,9 @@ }, "node_modules/jest-cli": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/core": "^27.5.1", "@jest/test-result": "^27.5.1", @@ -6228,8 +6843,9 @@ }, "node_modules/jest-cli/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6242,8 +6858,9 @@ }, "node_modules/jest-cli/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6257,8 +6874,9 @@ }, "node_modules/jest-cli/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -6268,21 +6886,24 @@ }, "node_modules/jest-cli/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-cli/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-cli/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6292,8 +6913,9 @@ }, "node_modules/jest-config": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.8.0", "@jest/test-sequencer": "^27.5.1", @@ -6334,8 +6956,9 @@ }, "node_modules/jest-config/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6348,8 +6971,9 @@ }, "node_modules/jest-config/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6363,8 +6987,9 @@ }, "node_modules/jest-config/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -6374,21 +6999,24 @@ }, "node_modules/jest-config/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-config/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-config/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6398,8 +7026,9 @@ }, "node_modules/jest-diff": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^27.5.1", @@ -6412,8 +7041,9 @@ }, "node_modules/jest-diff/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6426,8 +7056,9 @@ }, "node_modules/jest-diff/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6441,8 +7072,9 @@ }, "node_modules/jest-diff/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -6452,21 +7084,24 @@ }, "node_modules/jest-diff/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-diff/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-diff/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6476,8 +7111,9 @@ }, "node_modules/jest-docblock": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", "dev": true, - "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" }, @@ -6487,8 +7123,9 @@ }, "node_modules/jest-each": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", "chalk": "^4.0.0", @@ -6502,8 +7139,9 @@ }, "node_modules/jest-each/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6516,8 +7154,9 @@ }, "node_modules/jest-each/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6531,8 +7170,9 @@ }, "node_modules/jest-each/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -6542,21 +7182,24 @@ }, "node_modules/jest-each/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-each/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-each/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6566,8 +7209,9 @@ }, "node_modules/jest-environment-jsdom": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^27.5.1", "@jest/fake-timers": "^27.5.1", @@ -6583,8 +7227,9 @@ }, "node_modules/jest-environment-node": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^27.5.1", "@jest/fake-timers": "^27.5.1", @@ -6599,16 +7244,18 @@ }, "node_modules/jest-get-type": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", "dev": true, - "license": "MIT", "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-haste-map": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", "@types/graceful-fs": "^4.1.2", @@ -6632,8 +7279,9 @@ }, "node_modules/jest-jasmine2": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^27.5.1", "@jest/source-map": "^27.5.1", @@ -6659,8 +7307,9 @@ }, "node_modules/jest-jasmine2/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6673,8 +7322,9 @@ }, "node_modules/jest-jasmine2/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6688,8 +7338,9 @@ }, "node_modules/jest-jasmine2/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -6699,21 +7350,24 @@ }, "node_modules/jest-jasmine2/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-jasmine2/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-jasmine2/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6737,8 +7391,9 @@ }, "node_modules/jest-leak-detector": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", "dev": true, - "license": "MIT", "dependencies": { "jest-get-type": "^27.5.1", "pretty-format": "^27.5.1" @@ -6749,8 +7404,9 @@ }, "node_modules/jest-matcher-utils": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^27.5.1", @@ -6763,8 +7419,9 @@ }, "node_modules/jest-matcher-utils/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6777,8 +7434,9 @@ }, "node_modules/jest-matcher-utils/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6792,8 +7450,9 @@ }, "node_modules/jest-matcher-utils/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -6803,21 +7462,24 @@ }, "node_modules/jest-matcher-utils/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-matcher-utils/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-matcher-utils/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6827,8 +7489,9 @@ }, "node_modules/jest-message-util": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^27.5.1", @@ -6846,8 +7509,9 @@ }, "node_modules/jest-message-util/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6860,8 +7524,9 @@ }, "node_modules/jest-message-util/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6875,8 +7540,9 @@ }, "node_modules/jest-message-util/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -6886,21 +7552,24 @@ }, "node_modules/jest-message-util/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-message-util/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-message-util/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6910,8 +7579,9 @@ }, "node_modules/jest-mock": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", "@types/node": "*" @@ -6921,17 +7591,19 @@ } }, "node_modules/jest-mock-process": { - "version": "1.4.1", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/jest-mock-process/-/jest-mock-process-1.5.1.tgz", + "integrity": "sha512-CPu46KyUiVSxE+LkqBuscqGmy1bvW2vJQuNstt83iLtFaFjgrgmp6LY04IKuOhhlGhcrdi86Gqq5/fTE2wG6lg==", "dev": true, - "license": "MIT", "peerDependencies": { - "jest": ">=23.4 <28" + "jest": ">=23.4 <29" } }, "node_modules/jest-mock-props": { "version": "1.9.1", + "resolved": "https://registry.npmjs.org/jest-mock-props/-/jest-mock-props-1.9.1.tgz", + "integrity": "sha512-PvTySOTw/K4dwL7XrVGq/VUZRm/qXPrV4+NuhgxuWkmE3h/Fd+g+qB0evK5vSBAkI8TaxvTXYv17IdxWdEze1g==", "dev": true, - "license": "Unlicense", "engines": { "node": ">=8.0.0" }, @@ -6941,8 +7613,9 @@ }, "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, - "license": "MIT", "engines": { "node": ">=6" }, @@ -6957,16 +7630,18 @@ }, "node_modules/jest-regex-util": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "dev": true, - "license": "MIT", "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-resolve": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", "chalk": "^4.0.0", @@ -6985,8 +7660,9 @@ }, "node_modules/jest-resolve-dependencies": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", "jest-regex-util": "^27.5.1", @@ -6998,8 +7674,9 @@ }, "node_modules/jest-resolve/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7012,8 +7689,9 @@ }, "node_modules/jest-resolve/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7027,8 +7705,9 @@ }, "node_modules/jest-resolve/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7038,21 +7717,24 @@ }, "node_modules/jest-resolve/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-resolve/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-resolve/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7062,8 +7744,9 @@ }, "node_modules/jest-runner": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^27.5.1", "@jest/environment": "^27.5.1", @@ -7093,8 +7776,9 @@ }, "node_modules/jest-runner/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7107,8 +7791,9 @@ }, "node_modules/jest-runner/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7122,8 +7807,9 @@ }, "node_modules/jest-runner/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7133,21 +7819,24 @@ }, "node_modules/jest-runner/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-runner/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7157,8 +7846,9 @@ }, "node_modules/jest-runtime": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^27.5.1", "@jest/fake-timers": "^27.5.1", @@ -7189,8 +7879,9 @@ }, "node_modules/jest-runtime/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7203,8 +7894,9 @@ }, "node_modules/jest-runtime/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7218,8 +7910,9 @@ }, "node_modules/jest-runtime/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7229,21 +7922,24 @@ }, "node_modules/jest-runtime/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-runtime/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-runtime/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7253,8 +7949,9 @@ }, "node_modules/jest-serializer": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "graceful-fs": "^4.2.9" @@ -7265,8 +7962,9 @@ }, "node_modules/jest-snapshot": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.7.2", "@babel/generator": "^7.7.2", @@ -7297,8 +7995,9 @@ }, "node_modules/jest-snapshot/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7311,8 +8010,9 @@ }, "node_modules/jest-snapshot/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7326,8 +8026,9 @@ }, "node_modules/jest-snapshot/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7337,21 +8038,24 @@ }, "node_modules/jest-snapshot/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-snapshot/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-snapshot/node_modules/semver": { "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -7364,8 +8068,9 @@ }, "node_modules/jest-snapshot/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7375,8 +8080,9 @@ }, "node_modules/jest-util": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", "@types/node": "*", @@ -7391,8 +8097,9 @@ }, "node_modules/jest-util/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7405,8 +8112,9 @@ }, "node_modules/jest-util/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7420,8 +8128,9 @@ }, "node_modules/jest-util/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7431,21 +8140,24 @@ }, "node_modules/jest-util/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-util/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-util/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7455,8 +8167,9 @@ }, "node_modules/jest-validate": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", "camelcase": "^6.2.0", @@ -7471,8 +8184,9 @@ }, "node_modules/jest-validate/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7485,8 +8199,9 @@ }, "node_modules/jest-validate/node_modules/camelcase": { "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -7496,8 +8211,9 @@ }, "node_modules/jest-validate/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7511,8 +8227,9 @@ }, "node_modules/jest-validate/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7522,21 +8239,24 @@ }, "node_modules/jest-validate/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-validate/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-validate/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7546,8 +8266,9 @@ }, "node_modules/jest-watcher": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/test-result": "^27.5.1", "@jest/types": "^27.5.1", @@ -7563,8 +8284,9 @@ }, "node_modules/jest-watcher/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7577,8 +8299,9 @@ }, "node_modules/jest-watcher/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7592,8 +8315,9 @@ }, "node_modules/jest-watcher/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7603,21 +8327,24 @@ }, "node_modules/jest-watcher/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/jest-watcher/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-watcher/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7627,8 +8354,9 @@ }, "node_modules/jest-worker": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -7640,16 +8368,18 @@ }, "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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-worker/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7662,24 +8392,28 @@ }, "node_modules/jose": { "version": "4.8.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.8.1.tgz", + "integrity": "sha512-+/hpTbRcCw9YC0TOfN1W47pej4a9lRmltdOVdRLz5FP5UvUq3CenhXjQK7u/8NdMIIShMXYAh9VLPhc7TjhvFw==", "funding": { "url": "https://github.com/sponsors/panva" } }, "node_modules/js-base64": { "version": "3.7.2", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.2.tgz", + "integrity": "sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==" }, "node_modules/js-tokens": { "version": "4.0.0", - "dev": true, - "license": "MIT" + "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, - "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -7690,8 +8424,9 @@ }, "node_modules/jsdom": { "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, - "license": "MIT", "dependencies": { "abab": "^2.0.5", "acorn": "^8.2.4", @@ -7733,10 +8468,17 @@ } } }, + "node_modules/jsdom/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/jsesc": { "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, - "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -7746,22 +8488,26 @@ }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true }, "node_modules/json-schema-traverse": { "version": "1.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true }, "node_modules/json5": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "dev": true, - "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -7771,13 +8517,15 @@ }, "node_modules/jsonc-parser": { "version": "3.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true }, "node_modules/jsonfile": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, - "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -7787,22 +8535,25 @@ }, "node_modules/kleur": { "version": "3.0.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "engines": { "node": ">=6" } }, "node_modules/lazy-ass": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", "dev": true, - "license": "MIT", "engines": { "node": "> 0.8" } }, "node_modules/level": { "version": "7.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/level/-/level-7.0.1.tgz", + "integrity": "sha512-w3E64+ALx2eZf8RV5JL4kIcE0BFAvQscRYd1yU4YVqZN9RGTQxXSvH202xvK15yZwFFxRXe60f13LJjcJ//I4Q==", "dependencies": { "level-js": "^6.1.0", "level-packager": "^6.0.1", @@ -7818,7 +8569,8 @@ }, "node_modules/level-codec": { "version": "10.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-10.0.0.tgz", + "integrity": "sha512-QW3VteVNAp6c/LuV6nDjg7XDXx9XHK4abmQarxZmlRSDyXYk20UdaJTSX6yzVvQ4i0JyWSB7jert0DsyD/kk6g==", "dependencies": { "buffer": "^6.0.3" }, @@ -7828,7 +8580,8 @@ }, "node_modules/level-concat-iterator": { "version": "3.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", + "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", "dependencies": { "catering": "^2.1.0" }, @@ -7838,14 +8591,16 @@ }, "node_modules/level-errors": { "version": "3.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-3.0.1.tgz", + "integrity": "sha512-tqTL2DxzPDzpwl0iV5+rBCv65HWbHp6eutluHNcVIftKZlQN//b6GEnZDM2CvGZvzGYMwyPtYppYnydBQd2SMQ==", "engines": { "node": ">=10" } }, "node_modules/level-iterator-stream": { "version": "5.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-5.0.0.tgz", + "integrity": "sha512-wnb1+o+CVFUDdiSMR/ZymE2prPs3cjVLlXuDeSq9Zb8o032XrabGEXcTCsBxprAtseO3qvFeGzh6406z9sOTRA==", "dependencies": { "inherits": "^2.0.4", "readable-stream": "^3.4.0" @@ -7856,7 +8611,8 @@ }, "node_modules/level-js": { "version": "6.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/level-js/-/level-js-6.1.0.tgz", + "integrity": "sha512-i7mPtkZm68aewfv0FnIUWvFUFfoyzIvVKnUmuQGrelEkP72vSPTaA1SGneWWoCV5KZJG4wlzbJLp1WxVNGuc6A==", "dependencies": { "abstract-leveldown": "^7.2.0", "buffer": "^6.0.3", @@ -7867,7 +8623,8 @@ }, "node_modules/level-packager": { "version": "6.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-6.0.1.tgz", + "integrity": "sha512-8Ezr0XM6hmAwqX9uu8IGzGNkWz/9doyPA8Oo9/D7qcMI6meJC+XhIbNYHukJhIn8OGdlzQs/JPcL9B8lA2F6EQ==", "dependencies": { "encoding-down": "^7.1.0", "levelup": "^5.1.1" @@ -7878,15 +8635,17 @@ }, "node_modules/level-supports": { "version": "2.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", + "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", "engines": { "node": ">=10" } }, "node_modules/leveldown": { "version": "6.1.1", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.1.tgz", + "integrity": "sha512-88c+E+Eizn4CkQOBHwqlCJaTNEjGpaEIikn1S+cINc5E9HEvJ77bqY4JY/HxT5u0caWqsc3P3DcFIKBI1vHt+A==", "hasInstallScript": true, - "license": "MIT", "dependencies": { "abstract-leveldown": "^7.2.0", "napi-macros": "~2.0.0", @@ -7898,7 +8657,8 @@ }, "node_modules/levelup": { "version": "5.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-5.1.1.tgz", + "integrity": "sha512-0mFCcHcEebOwsQuk00WJwjLI6oCjbBuEYdh/RaRqhjnyVlzqf41T1NnDtCedumZ56qyIh8euLFDqV1KfzTAVhg==", "dependencies": { "catering": "^2.0.0", "deferred-leveldown": "^7.0.0", @@ -7913,16 +8673,18 @@ }, "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, - "license": "MIT", "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, - "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -7933,17 +8695,20 @@ }, "node_modules/lexicographic-integer": { "version": "1.1.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/lexicographic-integer/-/lexicographic-integer-1.1.0.tgz", + "integrity": "sha512-MQCrf1gG31DJSNQDiIfgk7CQVlXkO6xC+DFGExs5WQWlxWSSAroH5k/UrKrS6LThHDHBoc3X1pNoYHDKOCPWRQ==" }, "node_modules/lines-and-columns": { "version": "1.2.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true }, "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, - "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -7953,36 +8718,43 @@ }, "node_modules/lodash": { "version": "4.17.21", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "node_modules/lodash.camelcase": { "version": "4.3.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" }, "node_modules/lodash.debounce": { "version": "4.0.8", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true }, "node_modules/lodash.memoize": { "version": "4.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true }, "node_modules/lodash.merge": { "version": "4.6.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true }, "node_modules/long": { "version": "4.0.0", - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "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, - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -7992,17 +8764,20 @@ }, "node_modules/ltgt": { "version": "2.2.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", + "integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==" }, "node_modules/lunr": { "version": "2.3.9", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true }, "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, - "license": "MIT", "dependencies": { "semver": "^6.0.0" }, @@ -8015,21 +8790,24 @@ }, "node_modules/make-error": { "version": "1.3.6", - "dev": true, - "license": "ISC" + "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.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } }, "node_modules/marked": { - "version": "4.0.15", + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz", + "integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==", "dev": true, - "license": "MIT", "bin": { "marked": "bin/marked.js" }, @@ -8039,7 +8817,8 @@ }, "node_modules/md5.js": { "version": "1.3.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -8048,21 +8827,24 @@ }, "node_modules/merge-stream": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true }, "node_modules/merge2": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromatch": { "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, - "license": "MIT", "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -8073,16 +8855,18 @@ }, "node_modules/mime-db": { "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, - "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -8092,15 +8876,17 @@ }, "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, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/mimic-response": { "version": "3.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "engines": { "node": ">=10" }, @@ -8110,8 +8896,9 @@ }, "node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -8121,11 +8908,13 @@ }, "node_modules/minimist": { "version": "1.2.6", - "license": "MIT" + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/minimisted": { "version": "2.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", + "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", "dependencies": { "minimist": "^1.2.5" } @@ -8143,13 +8932,15 @@ }, "node_modules/mkdirp-classic": { "version": "0.5.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true }, "node_modules/mocked-env": { "version": "1.3.5", + "resolved": "https://registry.npmjs.org/mocked-env/-/mocked-env-1.3.5.tgz", + "integrity": "sha512-GyYY6ynVOdEoRlaGpaq8UYwdWkvrsU2xRme9B+WPSuJcNjh17+3QIxSYU6zwee0SbehhV6f06VZ4ahjG+9zdrA==", "dev": true, - "license": "MIT", "dependencies": { "check-more-types": "2.24.0", "debug": "4.3.2", @@ -8162,8 +8953,9 @@ }, "node_modules/mocked-env/node_modules/debug": { "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -8178,14 +8970,18 @@ }, "node_modules/ms": { "version": "2.1.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multiformats": { "version": "9.6.5", - "license": "(Apache-2.0 AND MIT)" + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.6.5.tgz", + "integrity": "sha512-vMwf/FUO+qAPvl3vlSZEgEVFY/AxeZq5yg761ScF3CZsXgmTi/HGkicUiNN0CI4PW8FiY2P0OLklOcmQjdQJhw==" }, "node_modules/multistream": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", + "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", "dev": true, "funding": [ { @@ -8201,7 +8997,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "once": "^1.4.0", "readable-stream": "^3.6.0" @@ -8209,27 +9004,32 @@ }, "node_modules/napi-build-utils": { "version": "1.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true }, "node_modules/napi-macros": { "version": "2.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", + "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" }, "node_modules/natural-compare": { "version": "1.4.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true }, "node_modules/neo-async": { "version": "2.6.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true }, "node_modules/nexpect": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/nexpect/-/nexpect-0.6.0.tgz", + "integrity": "sha512-gG4cO0zoNG+kaPesw516hPVEKLW3YizGU8UWMr5lpkHKOgoTWcu4sPQN7rWVAIL4Ck87zM4N8immPUhYPdDz3g==", "dev": true, - "license": "MIT", "dependencies": { "cross-spawn": "^6.0.5" }, @@ -8239,8 +9039,9 @@ }, "node_modules/nexpect/node_modules/cross-spawn": { "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, - "license": "MIT", "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -8254,24 +9055,27 @@ }, "node_modules/nexpect/node_modules/path-key": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/nexpect/node_modules/semver": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/nexpect/node_modules/shebang-command": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, - "license": "MIT", "dependencies": { "shebang-regex": "^1.0.0" }, @@ -8281,16 +9085,18 @@ }, "node_modules/nexpect/node_modules/shebang-regex": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/nexpect/node_modules/which": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -8300,28 +9106,32 @@ }, "node_modules/nice-try": { "version": "1.0.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true }, "node_modules/node-abi": { "version": "2.30.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", + "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", "dev": true, - "license": "MIT", "dependencies": { "semver": "^5.4.1" } }, "node_modules/node-abi/node_modules/semver": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/node-fetch": { "version": "2.6.7", - "license": "MIT", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -8339,15 +9149,18 @@ }, "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", - "license": "BSD-2-Clause" + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -8355,14 +9168,16 @@ }, "node_modules/node-forge": { "version": "0.10.0", - "license": "(BSD-3-Clause OR GPL-2.0)", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", "engines": { "node": ">= 6.0.0" } }, "node_modules/node-gyp-build": { "version": "4.4.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -8371,26 +9186,30 @@ }, "node_modules/node-int64": { "version": "0.4.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true }, "node_modules/node-releases": { - "version": "2.0.4", - "dev": true, - "license": "MIT" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "dev": true }, "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, - "license": "MIT", "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, - "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -8400,8 +9219,9 @@ }, "node_modules/npmlog": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, - "license": "ISC", "dependencies": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -8410,8 +9230,9 @@ } }, "node_modules/nth-check": { - "version": "2.0.1", - "license": "BSD-2-Clause", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dependencies": { "boolbase": "^1.0.0" }, @@ -8421,42 +9242,48 @@ }, "node_modules/number-is-nan": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/nwsapi": { "version": "2.2.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true }, "node_modules/object-assign": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { - "version": "1.12.0", - "license": "MIT", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object-keys": { "version": "1.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { "version": "4.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -8471,12 +9298,14 @@ } }, "node_modules/object.getownpropertydescriptors": { - "version": "2.1.3", - "license": "MIT", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz", + "integrity": "sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ==", "dependencies": { + "array.prototype.reduce": "^1.0.4", "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.1" }, "engines": { "node": ">= 0.8" @@ -8487,8 +9316,9 @@ }, "node_modules/object.values": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -8503,19 +9333,22 @@ }, "node_modules/observable-fns": { "version": "0.6.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/observable-fns/-/observable-fns-0.6.1.tgz", + "integrity": "sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==" }, "node_modules/once": { "version": "1.4.0", - "license": "ISC", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "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, - "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -8528,8 +9361,9 @@ }, "node_modules/optionator": { "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, - "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -8544,16 +9378,18 @@ }, "node_modules/p-is-promise": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "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, - "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -8566,8 +9402,9 @@ }, "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, - "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -8577,20 +9414,23 @@ }, "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, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/pako": { "version": "1.0.11", - "license": "(MIT AND Zlib)" + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "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, - "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -8600,8 +9440,9 @@ }, "node_modules/parse-json": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -8616,55 +9457,73 @@ } }, "node_modules/parse5": { - "version": "6.0.1", - "license": "MIT" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", + "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", + "dependencies": { + "entities": "^4.3.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } }, "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "license": "MIT", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", "dependencies": { - "parse5": "^6.0.1" + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, "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, - "license": "MIT", "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": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/path-key": { "version": "3.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "engines": { "node": ">=8" } }, "node_modules/path-parse": { "version": "1.0.7", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "node_modules/path-type": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/pbkdf2": { "version": "3.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "dependencies": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -8678,13 +9537,15 @@ }, "node_modules/picocolors": { "version": "1.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "license": "MIT", "engines": { "node": ">=8.6" }, @@ -8694,23 +9555,26 @@ }, "node_modules/pify": { "version": "4.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "engines": { "node": ">=6" } }, "node_modules/pirates": { "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/pkg": { "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.6.0.tgz", + "integrity": "sha512-mHrAVSQWmHA41RnUmRpC7pK9lNnMfdA16CF3cqOI22a8LZxOQzF7M8YWtA2nfs+d7I0MTDXOtkDsAsFXeCpYjg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "7.16.2", "@babel/types": "7.16.0", @@ -8742,8 +9606,9 @@ }, "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, - "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -8753,8 +9618,9 @@ }, "node_modules/pkg-fetch": { "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.3.0.tgz", + "integrity": "sha512-xJnIZ1KP+8rNN+VLafwu4tEeV4m8IkFBDdCFqmAJz9K1aiXEtbARmdbEe6HlXWGSVuShSHjFXpfkKRkDBQ5kiA==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.1.2", "fs-extra": "^9.1.0", @@ -8771,8 +9637,9 @@ }, "node_modules/pkg-fetch/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -8785,8 +9652,9 @@ }, "node_modules/pkg-fetch/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -8800,8 +9668,9 @@ }, "node_modules/pkg-fetch/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -8811,21 +9680,24 @@ }, "node_modules/pkg-fetch/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/pkg-fetch/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/pkg-fetch/node_modules/semver": { "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -8838,8 +9710,9 @@ }, "node_modules/pkg-fetch/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -8849,8 +9722,9 @@ }, "node_modules/pkg/node_modules/@babel/parser": { "version": "7.16.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", + "integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", "dev": true, - "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, @@ -8860,8 +9734,9 @@ }, "node_modules/pkg/node_modules/@babel/types": { "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", + "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.15.7", "to-fast-properties": "^2.0.0" @@ -8872,8 +9747,9 @@ }, "node_modules/pkg/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, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -8886,8 +9762,9 @@ }, "node_modules/pkg/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -8901,8 +9778,9 @@ }, "node_modules/pkg/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, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -8912,21 +9790,24 @@ }, "node_modules/pkg/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/pkg/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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/pkg/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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -8936,13 +9817,15 @@ }, "node_modules/pkg/node_modules/tslib": { "version": "2.3.1", - "dev": true, - "license": "0BSD" + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true }, "node_modules/prebuild-install": { "version": "6.1.4", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", + "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", "dev": true, - "license": "MIT", "dependencies": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", @@ -8967,8 +9850,9 @@ }, "node_modules/prebuild-install/node_modules/decompress-response": { "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "dev": true, - "license": "MIT", "dependencies": { "mimic-response": "^2.0.0" }, @@ -8978,8 +9862,9 @@ }, "node_modules/prebuild-install/node_modules/mimic-response": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -8989,8 +9874,9 @@ }, "node_modules/prebuild-install/node_modules/simple-get": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "dev": true, - "license": "MIT", "dependencies": { "decompress-response": "^4.2.0", "once": "^1.3.1", @@ -8999,16 +9885,18 @@ }, "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, - "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", "dev": true, - "license": "MIT", "bin": { "prettier": "bin-prettier.js" }, @@ -9021,8 +9909,9 @@ }, "node_modules/prettier-linter-helpers": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, - "license": "MIT", "dependencies": { "fast-diff": "^1.1.2" }, @@ -9032,8 +9921,9 @@ }, "node_modules/pretty-format": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -9045,8 +9935,9 @@ }, "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, - "license": "MIT", "engines": { "node": ">=10" }, @@ -9056,20 +9947,23 @@ }, "node_modules/process-nextick-args": { "version": "2.0.1", - "dev": true, - "license": "MIT" + "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, - "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/prompts": { "version": "2.4.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -9080,8 +9974,9 @@ }, "node_modules/protobufjs": { "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", "hasInstallScript": true, - "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -9104,17 +9999,20 @@ }, "node_modules/prr": { "version": "1.0.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==" }, "node_modules/psl": { "version": "1.8.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true }, "node_modules/pump": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, - "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -9122,13 +10020,16 @@ }, "node_modules/punycode": { "version": "2.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "engines": { "node": ">=6" } }, "node_modules/queue-microtask": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "funding": [ { "type": "github", @@ -9142,25 +10043,27 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/ramda": { "version": "0.27.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", + "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", + "dev": true }, "node_modules/randombytes": { "version": "2.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dependencies": { "safe-buffer": "^5.1.0" } }, "node_modules/rc": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -9173,20 +10076,23 @@ }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-is": { "version": "17.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true }, "node_modules/readable-stream": { "version": "3.6.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9210,13 +10116,15 @@ }, "node_modules/regenerate": { "version": "1.4.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true }, "node_modules/regenerate-unicode-properties": { "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "dev": true, - "license": "MIT", "dependencies": { "regenerate": "^1.4.2" }, @@ -9226,20 +10134,23 @@ }, "node_modules/regenerator-runtime": { "version": "0.13.9", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true }, "node_modules/regenerator-transform": { "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -9254,8 +10165,9 @@ }, "node_modules/regexpp": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -9265,8 +10177,9 @@ }, "node_modules/regexpu-core": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", "dev": true, - "license": "MIT", "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.0.1", @@ -9281,13 +10194,15 @@ }, "node_modules/regjsgen": { "version": "0.6.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", + "dev": true }, "node_modules/regjsparser": { "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "jsesc": "~0.5.0" }, @@ -9297,6 +10212,8 @@ }, "node_modules/regjsparser/node_modules/jsesc": { "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", "dev": true, "bin": { "jsesc": "bin/jsesc" @@ -9304,22 +10221,25 @@ }, "node_modules/require-directory": { "version": "2.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "engines": { "node": ">=0.10.0" } }, "node_modules/require-from-string": { "version": "2.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "engines": { "node": ">=0.10.0" } }, "node_modules/resolve": { "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, - "license": "MIT", "dependencies": { "is-core-module": "^2.8.1", "path-parse": "^1.0.7", @@ -9334,8 +10254,9 @@ }, "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, - "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -9345,23 +10266,26 @@ }, "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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/resolve.exports": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/resource-counter": { "version": "1.2.4", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/resource-counter/-/resource-counter-1.2.4.tgz", + "integrity": "sha512-DGJChvE5r4smqPE+xYNv9r1u/I9cCfRR5yfm7D6EQckdKqMyVpJ5z0s40yn0EM0puFxHg6mPORrQLQdEbJ/RnQ==", "dependencies": { "babel-runtime": "^6.26.0", "bitset": "^5.0.3" @@ -9372,8 +10296,9 @@ }, "node_modules/reusify": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, - "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -9381,8 +10306,9 @@ }, "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, - "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -9395,7 +10321,8 @@ }, "node_modules/ripemd160": { "version": "2.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -9403,6 +10330,8 @@ }, "node_modules/run-parallel": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -9418,13 +10347,14 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/run-parallel-limit": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", "funding": [ { "type": "github", @@ -9439,13 +10369,14 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "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==", "funding": [ { "type": "github", @@ -9459,18 +10390,19 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/safer-buffer": { "version": "2.1.2", - "dev": true, - "license": "MIT" + "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, - "license": "ISC", "dependencies": { "xmlchars": "^2.2.0" }, @@ -9480,20 +10412,23 @@ }, "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, - "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/set-blocking": { "version": "2.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true }, "node_modules/sha.js": { "version": "2.4.11", - "license": "(MIT AND BSD-3-Clause)", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -9504,7 +10439,8 @@ }, "node_modules/shebang-command": { "version": "2.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -9514,7 +10450,8 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "engines": { "node": ">=8" } @@ -9538,8 +10475,9 @@ }, "node_modules/shiki": { "version": "0.10.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", + "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", "dev": true, - "license": "MIT", "dependencies": { "jsonc-parser": "^3.0.0", "vscode-oniguruma": "^1.6.1", @@ -9564,7 +10502,8 @@ }, "node_modules/side-channel": { "version": "1.0.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -9576,11 +10515,14 @@ }, "node_modules/signal-exit": { "version": "3.0.7", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true }, "node_modules/simple-concat": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", "funding": [ { "type": "github", @@ -9594,11 +10536,12 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/simple-get": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", "funding": [ { "type": "github", @@ -9613,7 +10556,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -9622,28 +10564,32 @@ }, "node_modules/sisteransi": { "version": "1.0.5", - "license": "MIT" + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, "node_modules/slash": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "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, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-support": { "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, - "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -9651,13 +10597,15 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true }, "node_modules/stack-utils": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, - "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -9667,24 +10615,27 @@ }, "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, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/stream-meter": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", + "integrity": "sha512-4sOEtrbgFotXwnEuzzsQBYEV1elAeFSO8rSGeTwabuX1RRn/kEq9JVH7I0MRBhKVRR0sJkr0M0QCH7yOLf9fhQ==", "dev": true, - "license": "MIT", "dependencies": { "readable-stream": "^2.1.4" } }, "node_modules/stream-meter/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, - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -9697,28 +10648,32 @@ }, "node_modules/stream-meter/node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/stream-meter/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, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/string_decoder": { "version": "1.3.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dependencies": { "safe-buffer": "~5.2.0" } }, "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, - "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -9729,8 +10684,9 @@ }, "node_modules/string-width": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "dev": true, - "license": "MIT", "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -9742,16 +10698,18 @@ }, "node_modules/string-width/node_modules/ansi-regex": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/string-width/node_modules/strip-ansi": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -9761,7 +10719,8 @@ }, "node_modules/string.prototype.trimend": { "version": "1.0.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -9773,7 +10732,8 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -9785,7 +10745,8 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -9795,24 +10756,27 @@ }, "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, - "license": "MIT", "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, - "license": "MIT", "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, - "license": "MIT", "engines": { "node": ">=8" }, @@ -9822,8 +10786,9 @@ }, "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, - "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -9833,8 +10798,9 @@ }, "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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" @@ -9845,16 +10811,18 @@ }, "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, - "license": "MIT", "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, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -9864,8 +10832,9 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -9875,13 +10844,15 @@ }, "node_modules/symbol-tree": { "version": "3.2.4", - "dev": true, - "license": "MIT" + "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/tar-fs": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "dev": true, - "license": "MIT", "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -9891,8 +10862,9 @@ }, "node_modules/tar-stream": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, - "license": "MIT", "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -9906,8 +10878,9 @@ }, "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, - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" @@ -9921,8 +10894,9 @@ }, "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, - "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -9934,12 +10908,14 @@ }, "node_modules/text-table": { "version": "0.2.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true }, "node_modules/threads": { "version": "1.7.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/threads/-/threads-1.7.0.tgz", + "integrity": "sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ==", "dependencies": { "callsites": "^3.1.0", "debug": "^4.2.0", @@ -9955,20 +10931,24 @@ }, "node_modules/throat": { "version": "6.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true }, "node_modules/timeout-refresh": { "version": "1.0.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-1.0.3.tgz", + "integrity": "sha512-Mz0CX4vBGM5lj8ttbIFt7o4ZMxk/9rgudJRh76EvB7xXZMur7T/cjRiH2w4Fmkq0zxf2QpM8IFvOSRn8FEu3gA==" }, "node_modules/tiny-inflate": { "version": "1.0.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" }, "node_modules/tiny-worker": { "version": "2.3.0", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/tiny-worker/-/tiny-worker-2.3.0.tgz", + "integrity": "sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==", "optional": true, "dependencies": { "esm": "^3.2.25" @@ -9976,21 +10956,24 @@ }, "node_modules/tmpl": { "version": "1.0.5", - "dev": true, - "license": "BSD-3-Clause" + "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": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, - "license": "MIT", "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, - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -10000,8 +10983,9 @@ }, "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, - "license": "BSD-3-Clause", "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -10013,16 +10997,18 @@ }, "node_modules/tough-cookie/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, - "license": "MIT", "engines": { "node": ">= 4.0.0" } }, "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, - "license": "MIT", "dependencies": { "punycode": "^2.1.1" }, @@ -10032,15 +11018,17 @@ }, "node_modules/ts-custom-error": { "version": "3.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.2.0.tgz", + "integrity": "sha512-cBvC2QjtvJ9JfWLvstVnI45Y46Y5dMxIaG1TDMGAD/R87hpvqFL+7LhvUDhnRCfOnx/xitollFWWvUKKKhbN0A==", "engines": { "node": ">=8.0.0" } }, "node_modules/ts-jest": { - "version": "27.1.4", + "version": "27.1.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.5.tgz", + "integrity": "sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA==", "dev": true, - "license": "MIT", "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", @@ -10081,8 +11069,9 @@ }, "node_modules/ts-jest/node_modules/semver": { "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -10094,11 +11083,12 @@ } }, "node_modules/ts-node": { - "version": "10.7.0", + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz", + "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==", "dev": true, - "license": "MIT", "dependencies": { - "@cspotcode/source-map-support": "0.7.0", + "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", @@ -10109,7 +11099,7 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "bin": { @@ -10137,16 +11127,18 @@ }, "node_modules/ts-node/node_modules/acorn-walk": { "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/tsconfig-paths": { "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.1", @@ -10156,8 +11148,9 @@ }, "node_modules/tsconfig-paths/node_modules/json5": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "dev": true, - "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -10167,20 +11160,23 @@ }, "node_modules/tsconfig-paths/node_modules/strip-bom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/tslib": { "version": "2.4.0", - "license": "0BSD" + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/tsutils": { "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, - "license": "MIT", "dependencies": { "tslib": "^1.8.1" }, @@ -10193,13 +11189,15 @@ }, "node_modules/tsutils/node_modules/tslib": { "version": "1.14.1", - "dev": true, - "license": "0BSD" + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true }, "node_modules/tunnel-agent": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -10209,8 +11207,9 @@ }, "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, - "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -10220,16 +11219,18 @@ }, "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, - "license": "MIT", "engines": { "node": ">=4" } }, "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, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -10239,21 +11240,23 @@ }, "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, - "license": "MIT", "dependencies": { "is-typedarray": "^1.0.0" } }, "node_modules/typedoc": { - "version": "0.22.15", + "version": "0.22.17", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.17.tgz", + "integrity": "sha512-h6+uXHVVCPDaANzjwzdsj9aePBjZiBTpiMpBBeyh1zcN2odVsDCNajz8zyKnixF93HJeGpl34j/70yoEE5BfNg==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "glob": "^7.2.0", + "glob": "^8.0.3", "lunr": "^2.3.9", - "marked": "^4.0.12", - "minimatch": "^5.0.1", + "marked": "^4.0.16", + "minimatch": "^5.1.0", "shiki": "^0.10.1" }, "bin": { @@ -10263,21 +11266,42 @@ "node": ">= 12.10.0" }, "peerDependencies": { - "typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x" + "typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x || 4.7.x" } }, "node_modules/typedoc/node_modules/brace-expansion": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, + "node_modules/typedoc/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/typedoc/node_modules/minimatch": { - "version": "5.0.1", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -10286,9 +11310,10 @@ } }, "node_modules/typescript": { - "version": "4.6.4", + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", + "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10356,9 +11381,10 @@ } }, "node_modules/uglify-js": { - "version": "3.15.5", + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.0.tgz", + "integrity": "sha512-FEikl6bR30n0T3amyBh3LoiBdqHRy/f4H80+My34HOesOKyHfOsxAPAxOoqC0JUnC1amnO0IwkYC3sko51caSw==", "dev": true, - "license": "BSD-2-Clause", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -10369,7 +11395,8 @@ }, "node_modules/unbox-primitive": { "version": "1.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -10382,16 +11409,18 @@ }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, - "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -10402,23 +11431,26 @@ }, "node_modules/unicode-match-property-value-ecmascript": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-trie": { "version": "2.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", "dependencies": { "pako": "^0.2.5", "tiny-inflate": "^1.0.0" @@ -10426,42 +11458,49 @@ }, "node_modules/unicode-trie/node_modules/pako": { "version": "0.2.9", - "license": "MIT" + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" }, "node_modules/universalify": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10.0.0" } }, "node_modules/unordered-set": { "version": "2.0.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", + "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==" }, "node_modules/uri-js": { "version": "4.4.1", - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dependencies": { "punycode": "^2.1.0" } }, "node_modules/util-callbackify": { "version": "1.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/util-callbackify/-/util-callbackify-1.0.0.tgz", + "integrity": "sha512-5vEPPSM6DCHlCpq9FZryeIkY5FQMUqXLUz4yHtU369Z/abWUVdgInPVeINjWJV3Bk9DZhCr+JzGarEByPLsxBQ==", "dependencies": { "object.getownpropertydescriptors": "^2.0.3" } }, "node_modules/util-deprecate": { "version": "1.0.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/utp-native": { "version": "2.5.3", + "resolved": "https://registry.npmjs.org/utp-native/-/utp-native-2.5.3.tgz", + "integrity": "sha512-sWTrWYXPhhWJh+cS2baPzhaZc89zwlWCfwSthUjGhLkZztyPhcQllo+XVVCbNGi7dhyRlxkWxN4NKU6FbA9Y8w==", "hasInstallScript": true, - "license": "MIT", "dependencies": { "napi-macros": "^2.0.0", "node-gyp-build": "^4.2.0", @@ -10478,25 +11517,29 @@ }, "node_modules/uuid": { "version": "8.3.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/v8-compile-cache": { "version": "2.3.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", "dev": true, - "license": "ISC", "dependencies": { "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^1.6.0", @@ -10507,35 +11550,40 @@ } }, "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.3", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">= 8" } }, "node_modules/vscode-oniguruma": { "version": "1.6.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", + "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", + "dev": true }, "node_modules/vscode-textmate": { "version": "5.2.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", + "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", + "dev": true }, "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, - "license": "MIT", "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, - "license": "MIT", "dependencies": { "xml-name-validator": "^3.0.0" }, @@ -10545,37 +11593,42 @@ }, "node_modules/walker": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } }, "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, - "license": "BSD-2-Clause", "engines": { "node": ">=10.4" } }, "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, - "license": "MIT", "dependencies": { "iconv-lite": "0.4.24" } }, "node_modules/whatwg-mimetype": { "version": "2.3.0", - "dev": true, - "license": "MIT" + "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.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, - "license": "MIT", "dependencies": { "lodash": "^4.7.0", "tr46": "^2.1.0", @@ -10587,7 +11640,8 @@ }, "node_modules/which": { "version": "2.0.2", - "license": "ISC", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dependencies": { "isexe": "^2.0.0" }, @@ -10600,7 +11654,8 @@ }, "node_modules/which-boxed-primitive": { "version": "1.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -10614,28 +11669,32 @@ }, "node_modules/wide-align": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, - "license": "ISC", "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "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, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/wordwrap": { "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true }, "node_modules/wrap-ansi": { "version": "7.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -10650,7 +11709,8 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -10663,7 +11723,8 @@ }, "node_modules/wrap-ansi/node_modules/color-convert": { "version": "2.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -10673,18 +11734,21 @@ }, "node_modules/wrap-ansi/node_modules/color-name": { "version": "1.1.4", - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { "node": ">=8" } }, "node_modules/wrap-ansi/node_modules/string-width": { "version": "4.2.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10696,12 +11760,14 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "license": "ISC" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "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, - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", @@ -10710,9 +11776,10 @@ } }, "node_modules/ws": { - "version": "7.5.7", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.8.tgz", + "integrity": "sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8.3.0" }, @@ -10732,33 +11799,38 @@ "node_modules/xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==" }, "node_modules/xml-name-validator": { "version": "3.0.0", - "dev": true, - "license": "Apache-2.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", - "dev": true, - "license": "MIT" + "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", - "license": "ISC", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "engines": { "node": ">=10" } }, "node_modules/yallist": { "version": "4.0.0", - "dev": true, - "license": "ISC" + "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", - "license": "MIT", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -10774,21 +11846,24 @@ }, "node_modules/yargs-parser": { "version": "20.2.9", - "license": "ISC", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "engines": { "node": ">=10" } }, "node_modules/yargs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { "node": ">=8" } }, "node_modules/yargs/node_modules/string-width": { "version": "4.2.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10800,8 +11875,9 @@ }, "node_modules/yn": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -10810,6 +11886,8 @@ "dependencies": { "@ampproject/remapping": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dev": true, "requires": { "@jridgewell/gen-mapping": "^0.1.0", @@ -10818,29 +11896,35 @@ }, "@babel/code-frame": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "requires": { "@babel/highlight": "^7.16.7" } }, "@babel/compat-data": { - "version": "7.17.10", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.5.tgz", + "integrity": "sha512-BxhE40PVCBxVEJsSBhB6UWyAuqJRxGsAw8BdHMJ3AKGydcwuWW4kOO3HmqBQAdcq/OP+/DlTVxLvsCzRTnZuGg==", "dev": true }, "@babel/core": { - "version": "7.17.10", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.5.tgz", + "integrity": "sha512-MGY8vg3DxMnctw0LdvSEojOsumc70g0t18gNyUdAZqB1Rpd1Bqo/svHGvt+UJ6JcGX+DIekGFDxxIWofBxLCnQ==", "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.10", - "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helpers": "^7.17.9", - "@babel/parser": "^7.17.10", + "@babel/generator": "^7.18.2", + "@babel/helper-compilation-targets": "^7.18.2", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helpers": "^7.18.2", + "@babel/parser": "^7.18.5", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.10", - "@babel/types": "^7.17.10", + "@babel/traverse": "^7.18.5", + "@babel/types": "^7.18.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -10849,16 +11933,33 @@ } }, "@babel/generator": { - "version": "7.17.10", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", "dev": true, "requires": { - "@babel/types": "^7.17.10", - "@jridgewell/gen-mapping": "^0.1.0", + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", + "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } } }, "@babel/helper-annotate-as-pure": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "dev": true, "requires": { "@babel/types": "^7.16.7" @@ -10866,6 +11967,8 @@ }, "@babel/helper-builder-binary-assignment-operator-visitor": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "dev": true, "requires": { "@babel/helper-explode-assignable-expression": "^7.16.7", @@ -10873,7 +11976,9 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.17.10", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", + "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", "dev": true, "requires": { "@babel/compat-data": "^7.17.10", @@ -10883,7 +11988,9 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.17.9", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.0.tgz", + "integrity": "sha512-Kh8zTGR9de3J63e5nS0rQUdRs/kbtwoeQQ0sriS0lItjC96u8XXZN6lKpuyWd2coKSU13py/y+LTmThLuVX0Pg==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.16.7", @@ -10896,7 +12003,9 @@ } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz", + "integrity": "sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.16.7", @@ -10905,6 +12014,8 @@ }, "@babel/helper-define-polyfill-provider": { "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", "dev": true, "requires": { "@babel/helper-compilation-targets": "^7.13.0", @@ -10918,14 +12029,15 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.16.7", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", + "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", + "dev": true }, "@babel/helper-explode-assignable-expression": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", "dev": true, "requires": { "@babel/types": "^7.16.7" @@ -10933,6 +12045,8 @@ }, "@babel/helper-function-name": { "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", "dev": true, "requires": { "@babel/template": "^7.16.7", @@ -10941,6 +12055,8 @@ }, "@babel/helper-hoist-variables": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "dev": true, "requires": { "@babel/types": "^7.16.7" @@ -10948,6 +12064,8 @@ }, "@babel/helper-member-expression-to-functions": { "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "dev": true, "requires": { "@babel/types": "^7.17.0" @@ -10955,13 +12073,17 @@ }, "@babel/helper-module-imports": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dev": true, "requires": { "@babel/types": "^7.16.7" } }, "@babel/helper-module-transforms": { - "version": "7.17.7", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", + "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.16.7", @@ -10970,23 +12092,29 @@ "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0" + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" } }, "@babel/helper-optimise-call-expression": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "dev": true, "requires": { "@babel/types": "^7.16.7" } }, "@babel/helper-plugin-utils": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", + "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", "dev": true }, "@babel/helper-remap-async-to-generator": { "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.16.7", @@ -10995,25 +12123,31 @@ } }, "@babel/helper-replace-supers": { - "version": "7.16.7", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.2.tgz", + "integrity": "sha512-XzAIyxx+vFnrOxiQrToSUOzUOn0e1J2Li40ntddek1Y69AXUTXoDJ40/D5RdjFu7s7qHiaeoTiempZcbuVXh2Q==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-member-expression-to-functions": "^7.17.7", "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" } }, "@babel/helper-simple-access": { - "version": "7.17.7", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", + "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", "dev": true, "requires": { - "@babel/types": "^7.17.0" + "@babel/types": "^7.18.2" } }, "@babel/helper-skip-transparent-expression-wrappers": { "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", "dev": true, "requires": { "@babel/types": "^7.16.0" @@ -11021,6 +12155,8 @@ }, "@babel/helper-split-export-declaration": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "dev": true, "requires": { "@babel/types": "^7.16.7" @@ -11028,14 +12164,20 @@ }, "@babel/helper-validator-identifier": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true }, "@babel/helper-validator-option": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "dev": true }, "@babel/helper-wrap-function": { "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", "dev": true, "requires": { "@babel/helper-function-name": "^7.16.7", @@ -11045,16 +12187,20 @@ } }, "@babel/helpers": { - "version": "7.17.9", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", + "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", "dev": true, "requires": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.9", - "@babel/types": "^7.17.0" + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" } }, "@babel/highlight": { - "version": "7.17.9", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", + "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", @@ -11063,53 +12209,67 @@ } }, "@babel/parser": { - "version": "7.17.10", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.5.tgz", + "integrity": "sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw==", "dev": true }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.17.12.tgz", + "integrity": "sha512-xCJQXl4EeQ3J9C4yOmpTrtVGmzpm2iSzyxbkZHw7UCnZBftHpF/hpII80uWVyVrc40ytIClHjgWGTG1g/yB+aw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.17.12.tgz", + "integrity": "sha512-/vt0hpIw0x4b6BLKUkwlvEoiGZYYLNZ96CzyHYPbtG2jZGz6LBe7/V+drYrc/d+ovrF9NBi0pmtvmNb/FsWtRQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" + "@babel/plugin-proposal-optional-chaining": "^7.17.12" } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz", + "integrity": "sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-remap-async-to-generator": "^7.16.8", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz", + "integrity": "sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-proposal-class-static-block": { - "version": "7.17.6", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.0.tgz", + "integrity": "sha512-t+8LsRMMDE74c6sV7KShIw13sqbqd58tlqNrsWoWBTIMw7SVQ0cZ905wLNS/FBCy/3PyooRHLFFlfrUNyyz5lA==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.6", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-dynamic-import": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7", @@ -11117,39 +12277,49 @@ } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz", + "integrity": "sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.17.12.tgz", + "integrity": "sha512-rKJ+rKBoXwLnIn7n6o6fulViHMrOThz99ybH+hKHcOZbnN14VuMnH9fo2eHE69C8pO4uX1Q7t2HYYIDmv8VYkg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.17.12.tgz", + "integrity": "sha512-EqFo2s1Z5yy+JeJu7SFfbIUtToJTVlC61/C7WLKDntSw4Sz6JNAIfL7zQ74VvirxpjB5kz/kIx0gCcb+5OEo2Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz", + "integrity": "sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7", @@ -11157,18 +12327,22 @@ } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.0.tgz", + "integrity": "sha512-nbTv371eTrFabDfHLElkn9oyf9VG+VKK6WMzhY2o4eHKaG19BToD9947zzGMO6I/Irstx9d8CwX6njPNIAR/yw==", "dev": true, "requires": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" + "@babel/plugin-transform-parameters": "^7.17.12" } }, "@babel/plugin-proposal-optional-catch-binding": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7", @@ -11176,42 +12350,52 @@ } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz", + "integrity": "sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.16.11", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.17.12.tgz", + "integrity": "sha512-SllXoxo19HmxhDWm3luPz+cPhtoTSKLJE9PXshsfrOzBqs60QP0r8OaJItrPhAj0d7mZMnNF0Y1UUggCDgMz1A==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.17.12.tgz", + "integrity": "sha512-/6BtVi57CJfrtDNKfK5b66ydK2J5pXUKBKSPD2G1whamMuEnZWgoOIfO8Vf9F/DoD4izBLD/Au4NMQfruzzykg==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz", + "integrity": "sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" } }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -11219,6 +12403,8 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -11226,6 +12412,8 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.12.13" @@ -11233,6 +12421,8 @@ }, "@babel/plugin-syntax-class-static-block": { "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" @@ -11240,6 +12430,8 @@ }, "@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -11247,13 +12439,26 @@ }, "@babel/plugin-syntax-export-namespace-from": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.3" } }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.17.12.tgz", + "integrity": "sha512-n/loy2zkq9ZEM8tEOwON9wTQSTNDTDEz6NujPtJGLU7qObzT1N4c4YZZf8E6ATB2AjNQg/Ib2AIpO03EZaCehw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.10.4" @@ -11261,6 +12466,8 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -11268,6 +12475,8 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.10.4" @@ -11275,6 +12484,8 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -11282,6 +12493,8 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.10.4" @@ -11289,6 +12502,8 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -11296,6 +12511,8 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -11303,6 +12520,8 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -11310,6 +12529,8 @@ }, "@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" @@ -11317,78 +12538,98 @@ }, "@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, "requires": { "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-syntax-typescript": { - "version": "7.17.10", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz", + "integrity": "sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz", + "integrity": "sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.17.12.tgz", + "integrity": "sha512-J8dbrWIOO3orDzir57NRsjg4uxucvhby0L/KZuGsWDj0g7twWK3g7JhJhOrXtuXiw8MeiSdJ3E0OW9H8LYEzLQ==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-remap-async-to-generator": "^7.16.8" } }, "@babel/plugin-transform-block-scoped-functions": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.16.7", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.4.tgz", + "integrity": "sha512-+Hq10ye+jlvLEogSOtq4mKvtk7qwcUQ1f0Mrueai866C82f844Yom2cttfJdMdqRLTxWpsbfbkIkOIfovyUQXw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-classes": { - "version": "7.16.7", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.4.tgz", + "integrity": "sha512-e42NSG2mlKWgxKUAD9EJJSkZxR67+wZqzNxLSpc51T8tRU5SLFHsPmgYR5yr7sdgX4u+iHA1C5VafJ6AyImV3A==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-function-name": "^7.17.9", "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-replace-supers": "^7.18.2", "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz", + "integrity": "sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-destructuring": { - "version": "7.17.7", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.0.tgz", + "integrity": "sha512-Mo69klS79z6KEfrLg/1WkmVnB8javh75HX4pi2btjvlIoasuxilEyjtsQW6XPrubNd7AQy0MMaNIaQE4e7+PQw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-dotall-regex": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "dev": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.16.7", @@ -11396,14 +12637,18 @@ } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.17.12.tgz", + "integrity": "sha512-EA5eYFUG6xeerdabina/xIoB95jJ17mAkR8ivx6ZSu9frKShBjpOGZPn511MTDTkiCO+zXnzNczvUM69YSf3Zw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-exponentiation-operator": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "dev": true, "requires": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", @@ -11411,14 +12656,18 @@ } }, "@babel/plugin-transform-for-of": { - "version": "7.16.7", + "version": "7.18.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.1.tgz", + "integrity": "sha512-+TTB5XwvJ5hZbO8xvl2H4XaMDOAK57zF4miuC9qQJgysPNEAZZ9Z69rdF5LJkozGdZrjBIUAIyKUWRMmebI7vg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-function-name": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "dev": true, "requires": { "@babel/helper-compilation-targets": "^7.16.7", @@ -11427,73 +12676,92 @@ } }, "@babel/plugin-transform-literals": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz", + "integrity": "sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-member-expression-literals": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.16.7", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.0.tgz", + "integrity": "sha512-h8FjOlYmdZwl7Xm2Ug4iX2j7Qy63NANI+NQVWQzv6r25fqgg7k2dZl03p95kvqNclglHs4FZ+isv4p1uXMA+QA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.17.9", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.2.tgz", + "integrity": "sha512-f5A865gFPAJAEE0K7F/+nm5CmAE3y8AWlMBG9unu5j9+tk50UQVK0QS8RNxSp7MJf0wh97uYyLWt3Zvu71zyOQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-simple-access": "^7.18.2", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.17.8", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.5.tgz", + "integrity": "sha512-SEewrhPpcqMF1V7DhnEbhVJLrC+nnYfe1E0piZMZXBpxi9WvZqWGwpsk7JYP7wPWeqaBh4gyKlBhHJu3uz5g4Q==", "dev": true, "requires": { "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.16.7", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.0.tgz", + "integrity": "sha512-d/zZ8I3BWli1tmROLxXLc9A6YXvGK8egMxHp+E/rRwMh1Kip0AP77VwZae3snEJ33iiWwvNv2+UIIhfalqhzZA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.17.10", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz", + "integrity": "sha512-vWoWFM5CKaTeHrdUJ/3SIOTRV+MBVGybOC9mhJkaprGNt5demMymDW24yC74avb915/mIRe3TgNb/d8idvnCRA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.17.0" + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-new-target": { - "version": "7.16.7", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.5.tgz", + "integrity": "sha512-TuRL5uGW4KXU6OsRj+mLp9BM7pO8e7SGNTEokQRRxHFkXYMFiy2jlKSZPFtI/mKORDzciH+hneskcSOp0gU8hg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-object-super": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7", @@ -11501,71 +12769,92 @@ } }, "@babel/plugin-transform-parameters": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz", + "integrity": "sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-property-literals": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-regenerator": { - "version": "7.17.9", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.0.tgz", + "integrity": "sha512-C8YdRw9uzx25HSIzwA7EM7YP0FhCe5wNvJbZzjVNHHPGVcDJ3Aie+qGYYdS1oVQgn+B3eAIJbWFLrJ4Jipv7nw==", "dev": true, "requires": { + "@babel/helper-plugin-utils": "^7.17.12", "regenerator-transform": "^0.15.0" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.17.12.tgz", + "integrity": "sha512-1KYqwbJV3Co03NIi14uEHW8P50Md6KqFgt0FfpHdK6oyAHQVTosgPuPSiWud1HX0oYJ1hGRRlk0fP87jFpqXZA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-shorthand-properties": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-spread": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz", + "integrity": "sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" } }, "@babel/plugin-transform-sticky-regex": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-template-literals": { - "version": "7.16.7", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.2.tgz", + "integrity": "sha512-/cmuBVw9sZBGZVOMkpAEaVLwm4JmK2GZ1dFKOGGpMzEHWFmyZZ59lUU0PdRr8YNYeQdNzTDwuxP2X2gzydTc9g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.17.12.tgz", + "integrity": "sha512-Q8y+Jp7ZdtSPXCThB6zjQ74N3lj0f6TDh1Hnf5B+sYlzQ8i5Pjp8gW0My79iekSpT4WnI06blqP6DT0OmaXXmw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/plugin-transform-unicode-escapes": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7" @@ -11573,6 +12862,8 @@ }, "@babel/plugin-transform-unicode-regex": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "dev": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.16.7", @@ -11580,35 +12871,38 @@ } }, "@babel/preset-env": { - "version": "7.17.10", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.2.tgz", + "integrity": "sha512-PfpdxotV6afmXMU47S08F9ZKIm2bJIQ0YbAAtDfIENX7G1NUAXigLREh69CWDjtgUy7dYn7bsMzkgdtAlmS68Q==", "dev": true, "requires": { "@babel/compat-data": "^7.17.10", - "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-compilation-targets": "^7.18.2", + "@babel/helper-plugin-utils": "^7.17.12", "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.17.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.17.12", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-async-generator-functions": "^7.17.12", + "@babel/plugin-proposal-class-properties": "^7.17.12", + "@babel/plugin-proposal-class-static-block": "^7.18.0", "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.17.12", + "@babel/plugin-proposal-json-strings": "^7.17.12", + "@babel/plugin-proposal-logical-assignment-operators": "^7.17.12", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12", "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.17.3", + "@babel/plugin-proposal-object-rest-spread": "^7.18.0", "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-private-methods": "^7.17.12", + "@babel/plugin-proposal-private-property-in-object": "^7.17.12", + "@babel/plugin-proposal-unicode-property-regex": "^7.17.12", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.17.12", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -11618,40 +12912,40 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", + "@babel/plugin-transform-arrow-functions": "^7.17.12", + "@babel/plugin-transform-async-to-generator": "^7.17.12", "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.17.7", + "@babel/plugin-transform-block-scoping": "^7.17.12", + "@babel/plugin-transform-classes": "^7.17.12", + "@babel/plugin-transform-computed-properties": "^7.17.12", + "@babel/plugin-transform-destructuring": "^7.18.0", "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.17.12", "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.18.1", "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", + "@babel/plugin-transform-literals": "^7.17.12", "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.17.9", - "@babel/plugin-transform-modules-systemjs": "^7.17.8", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.10", - "@babel/plugin-transform-new-target": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.18.0", + "@babel/plugin-transform-modules-commonjs": "^7.18.2", + "@babel/plugin-transform-modules-systemjs": "^7.18.0", + "@babel/plugin-transform-modules-umd": "^7.18.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.12", + "@babel/plugin-transform-new-target": "^7.17.12", "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.17.12", "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.17.9", - "@babel/plugin-transform-reserved-words": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.18.0", + "@babel/plugin-transform-reserved-words": "^7.17.12", "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", + "@babel/plugin-transform-spread": "^7.17.12", "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.18.2", + "@babel/plugin-transform-typeof-symbol": "^7.17.12", "@babel/plugin-transform-unicode-escapes": "^7.16.7", "@babel/plugin-transform-unicode-regex": "^7.16.7", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.17.10", + "@babel/types": "^7.18.2", "babel-plugin-polyfill-corejs2": "^0.3.0", "babel-plugin-polyfill-corejs3": "^0.5.0", "babel-plugin-polyfill-regenerator": "^0.3.0", @@ -11661,6 +12955,8 @@ }, "@babel/preset-modules": { "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -11671,7 +12967,9 @@ } }, "@babel/runtime": { - "version": "7.17.9", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.3.tgz", + "integrity": "sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" @@ -11679,6 +12977,8 @@ }, "@babel/template": { "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "dev": true, "requires": { "@babel/code-frame": "^7.16.7", @@ -11687,23 +12987,27 @@ } }, "@babel/traverse": { - "version": "7.17.10", + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.5.tgz", + "integrity": "sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA==", "dev": true, "requires": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.10", - "@babel/helper-environment-visitor": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-environment-visitor": "^7.18.2", "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.10", - "@babel/types": "^7.17.10", + "@babel/parser": "^7.18.5", + "@babel/types": "^7.18.4", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.17.10", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", + "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", @@ -11712,27 +13016,41 @@ }, "@bcoe/v8-coverage": { "version": "0.2.3", - "dev": true - }, - "@cspotcode/source-map-consumer": { - "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, "@cspotcode/source-map-support": { - "version": "0.7.0", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "requires": { - "@cspotcode/source-map-consumer": "0.8.0" + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } } }, "@eslint/eslintrc": { - "version": "1.2.3", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.3.2", - "globals": "^13.9.0", + "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -11742,6 +13060,8 @@ "dependencies": { "ajv": { "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -11752,10 +13072,14 @@ }, "argparse": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, "globals": { "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -11763,6 +13087,8 @@ }, "js-yaml": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { "argparse": "^2.0.1" @@ -11770,33 +13096,43 @@ }, "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 }, "type-fest": { "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true } } }, "@grpc/grpc-js": { "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.6.7.tgz", + "integrity": "sha512-eBM03pu9hd3VqDQG+kHahiG1x80RGkkqqRb1Pchcwqej/KkAH95gAvKs6laqaHCycYaPK+TKuNQnOz9UXYA8qw==", "requires": { "@grpc/proto-loader": "^0.6.4", "@types/node": ">=12.12.47" } }, "@grpc/proto-loader": { - "version": "0.6.12", + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.13.tgz", + "integrity": "sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g==", "requires": { "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", "long": "^4.0.0", - "protobufjs": "^6.10.0", + "protobufjs": "^6.11.3", "yargs": "^16.2.0" } }, "@humanwhocodes/config-array": { "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -11806,10 +13142,14 @@ }, "@humanwhocodes/object-schema": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "@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, "requires": { "camelcase": "^5.3.1", @@ -11821,10 +13161,14 @@ }, "@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 }, "@jest/console": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", "dev": true, "requires": { "@jest/types": "^27.5.1", @@ -11837,6 +13181,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -11844,6 +13190,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -11852,6 +13200,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -11859,14 +13209,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -11876,6 +13232,8 @@ }, "@jest/core": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", "dev": true, "requires": { "@jest/console": "^27.5.1", @@ -11910,6 +13268,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -11917,6 +13277,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -11925,6 +13287,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -11932,14 +13296,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -11949,6 +13319,8 @@ }, "@jest/environment": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", "dev": true, "requires": { "@jest/fake-timers": "^27.5.1", @@ -11959,6 +13331,8 @@ }, "@jest/fake-timers": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", "dev": true, "requires": { "@jest/types": "^27.5.1", @@ -11971,6 +13345,8 @@ }, "@jest/globals": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", "dev": true, "requires": { "@jest/environment": "^27.5.1", @@ -11980,6 +13356,8 @@ }, "@jest/reporters": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", @@ -12011,6 +13389,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -12018,6 +13398,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -12026,6 +13408,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -12033,14 +13417,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -12050,6 +13440,8 @@ }, "@jest/source-map": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", "dev": true, "requires": { "callsites": "^3.0.0", @@ -12059,6 +13451,8 @@ }, "@jest/test-result": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", "dev": true, "requires": { "@jest/console": "^27.5.1", @@ -12069,6 +13463,8 @@ }, "@jest/test-sequencer": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", "dev": true, "requires": { "@jest/test-result": "^27.5.1", @@ -12079,6 +13475,8 @@ }, "@jest/transform": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "requires": { "@babel/core": "^7.1.0", @@ -12100,6 +13498,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -12107,6 +13507,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -12115,6 +13517,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -12122,14 +13526,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -12139,6 +13549,8 @@ }, "@jest/types": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -12150,6 +13562,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -12157,6 +13571,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -12165,6 +13581,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -12172,14 +13590,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -12189,6 +13613,8 @@ }, "@jridgewell/gen-mapping": { "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dev": true, "requires": { "@jridgewell/set-array": "^1.0.0", @@ -12197,18 +13623,26 @@ }, "@jridgewell/resolve-uri": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", "dev": true }, "@jridgewell/set-array": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", "dev": true }, "@jridgewell/sourcemap-codec": { "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", "dev": true }, "@jridgewell/trace-mapping": { "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", + "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.0.3", @@ -12217,6 +13651,8 @@ }, "@matrixai/async-init": { "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.7.3.tgz", + "integrity": "sha512-Sf3q5ODhVJqrYiAdGXmwj606956lgEMKGM9LMFU5scIOh13WokHo3GthjB1yh/umCV75NYvHJn60R9gnudVZ3Q==", "requires": { "@matrixai/async-locks": "^2.2.4", "@matrixai/errors": "^1.1.1" @@ -12248,26 +13684,36 @@ } }, "@matrixai/errors": { - "version": "1.1.1", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.1.2.tgz", + "integrity": "sha512-JSi2SIqdlqqDruANrTG8RMvLrJZAwduY19y26LZHx7DDkqhkqzF9fblbWaE9Fo1lhSTGk65oKRx2UjGn3v5gWw==", "requires": { "ts-custom-error": "^3.2.0" } }, "@matrixai/id": { "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@matrixai/id/-/id-3.3.3.tgz", + "integrity": "sha512-eXkxv68sCT17f6XQU8zMwgLLqwbdFm+8DoL3gXfBqfiDYxOCCQBS4L9kjUby8gRdlP7mIpkJ6oVAWCUnykGInA==", "requires": { "multiformats": "^9.4.8", "uuid": "^8.3.2" } }, "@matrixai/logger": { - "version": "2.1.1" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.1.1.tgz", + "integrity": "sha512-79KM0PyJTpfkALf9DK2xGniU+9gngsb5O8hcdUviWz+zR2W0hnTQq/g7tJW0YnIEhmDe/GkJf0Bnbs+gWfj3BA==" }, "@matrixai/resources": { - "version": "1.1.3" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@matrixai/resources/-/resources-1.1.3.tgz", + "integrity": "sha512-9zbA0NtgCtA+2hILpojshH6Pd679bIPtB8DcsPLVDzvGZP1TDwvtvZWCC3SG7oJUTzxqBI2Bfe+hypqwpvYPCw==" }, "@matrixai/workers": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@matrixai/workers/-/workers-1.3.3.tgz", + "integrity": "sha512-ID1sSJDXjM0hdWC10euWGcFofuys7+IDP+XTBh8Gq6jirn18xJs71wSy357qxLVSa7mL00qRJJfW6rljcFUK4A==", "requires": { "@matrixai/async-init": "^1.7.3", "@matrixai/errors": "^1.1.1", @@ -12277,6 +13723,8 @@ }, "@nodelib/fs.scandir": { "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "requires": { "@nodelib/fs.stat": "2.0.5", @@ -12285,10 +13733,14 @@ }, "@nodelib/fs.stat": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true }, "@nodelib/fs.walk": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.5", @@ -12296,41 +13748,63 @@ } }, "@protobufjs/aspromise": { - "version": "1.1.2" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" }, "@protobufjs/base64": { - "version": "1.1.2" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" }, "@protobufjs/codegen": { - "version": "2.0.4" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" }, "@protobufjs/eventemitter": { - "version": "1.1.0" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" }, "@protobufjs/fetch": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "requires": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "@protobufjs/float": { - "version": "1.0.2" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" }, "@protobufjs/inquire": { - "version": "1.1.0" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" }, "@protobufjs/path": { - "version": "1.1.2" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" }, "@protobufjs/pool": { - "version": "1.1.0" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" }, "@protobufjs/utf8": { - "version": "1.1.0" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "@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, "requires": { "type-detect": "4.0.8" @@ -12338,6 +13812,8 @@ }, "@sinonjs/fake-timers": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" @@ -12345,29 +13821,43 @@ }, "@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 }, "@tsconfig/node10": { - "version": "1.0.8", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", "dev": true }, "@tsconfig/node12": { - "version": "1.0.9", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.10.tgz", + "integrity": "sha512-N+srakvPaYMGkwjNDx3ASx65Zl3QG8dJgVtIB+YMOkucU+zctlv/hdP5250VKdDHSDoW9PFZoCqbqNcAPjCjXA==", "dev": true }, "@tsconfig/node14": { - "version": "1.0.1", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.2.tgz", + "integrity": "sha512-YwrUA5ysDXHFYfL0Xed9x3sNS4P+aKlCOnnbqUa2E5HdQshHFleCJVrj1PlGTb4GgFUCDyte1v3JWLy2sz8Oqg==", "dev": true }, "@tsconfig/node16": { - "version": "1.0.2", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, "@types/abstract-leveldown": { - "version": "7.2.0" + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-q5veSX6zjUy/DlDhR4Y4cU0k2Ar+DT2LUraP00T19WLmTO6Se1djepCCaqU6nQrwcJ5Hyo/CWqxTzrrFg8eqbQ==" }, "@types/babel__core": { "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -12379,6 +13869,8 @@ }, "@types/babel__generator": { "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, "requires": { "@babel/types": "^7.0.0" @@ -12386,6 +13878,8 @@ }, "@types/babel__template": { "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -12394,6 +13888,8 @@ }, "@types/babel__traverse": { "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", "dev": true, "requires": { "@babel/types": "^7.3.0" @@ -12401,6 +13897,8 @@ }, "@types/cross-spawn": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.2.tgz", + "integrity": "sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==", "dev": true, "requires": { "@types/node": "*" @@ -12408,10 +13906,14 @@ }, "@types/google-protobuf": { "version": "3.15.6", + "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.6.tgz", + "integrity": "sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw==", "dev": true }, "@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, "requires": { "@types/node": "*" @@ -12419,10 +13921,14 @@ }, "@types/istanbul-lib-coverage": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", "dev": true }, "@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, "requires": { "@types/istanbul-lib-coverage": "*" @@ -12430,13 +13936,17 @@ }, "@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, "requires": { "@types/istanbul-lib-report": "*" } }, "@types/jest": { - "version": "27.5.1", + "version": "27.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz", + "integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==", "dev": true, "requires": { "jest-matcher-utils": "^27.0.0", @@ -12445,24 +13955,34 @@ }, "@types/json-schema": { "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "@types/json5": { "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "@types/long": { - "version": "4.0.2" + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "@types/nexpect": { "version": "0.4.31", + "resolved": "https://registry.npmjs.org/@types/nexpect/-/nexpect-0.4.31.tgz", + "integrity": "sha512-Plh9Dlj2AKdsblgF1Pv7s2BjlojqW93d1zIUtK5xVVrUjkZQezyWIOAq0Xfwp0e0SDQ70YmaDqzhoJru2kqVPA==", "dev": true, "requires": { "@types/node": "*" } }, "@types/node": { - "version": "16.11.35" + "version": "16.11.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.39.tgz", + "integrity": "sha512-K0MsdV42vPwm9L6UwhIxMAOmcvH/1OoVkZyCgEtVu4Wx7sElGloy/W7kMBNe/oJ7V/jW9BVt1F6RahH6e7tPXw==" }, "@types/node-forge": { "version": "0.10.10", @@ -12475,14 +13995,20 @@ }, "@types/pako": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.4.tgz", + "integrity": "sha512-Z+5bJSm28EXBSUJEgx29ioWeEEHUh6TiMkZHDhLwjc9wVFH+ressbkmX6waUZc5R3Gobn4Qu5llGxaoflZ+yhA==", "dev": true }, "@types/prettier": { - "version": "2.6.1", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", + "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", "dev": true }, "@types/prompts": { "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.14.tgz", + "integrity": "sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA==", "dev": true, "requires": { "@types/node": "*" @@ -12490,6 +14016,8 @@ }, "@types/readable-stream": { "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.13.tgz", + "integrity": "sha512-4JSCx8EUzaW9Idevt+9lsRAt1lcSccoQfE+AouM1gk8sFxnnytKNIO3wTl9Dy+4m6jRJ1yXhboLHHT/LXBQiEw==", "dev": true, "requires": { "@types/node": "*", @@ -12498,14 +14026,20 @@ }, "@types/stack-utils": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, "@types/uuid": { "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", "dev": true }, "@types/yargs": { "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -12513,25 +14047,31 @@ }, "@types/yargs-parser": { "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.28.0.tgz", + "integrity": "sha512-DXVU6Cg29H2M6EybqSg2A+x8DgO9TCUBRp4QEXQHJceLS7ogVDP0g3Lkg/SZCqcvkAP/RruuQqK0gdlkgmhSUA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.23.0", - "@typescript-eslint/type-utils": "5.23.0", - "@typescript-eslint/utils": "5.23.0", - "debug": "^4.3.2", + "@typescript-eslint/scope-manager": "5.28.0", + "@typescript-eslint/type-utils": "5.28.0", + "@typescript-eslint/utils": "5.28.0", + "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", + "ignore": "^5.2.0", "regexpp": "^3.2.0", - "semver": "^7.3.5", + "semver": "^7.3.7", "tsutils": "^3.21.0" }, "dependencies": { "semver": { "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -12540,51 +14080,63 @@ } }, "@typescript-eslint/parser": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.28.0.tgz", + "integrity": "sha512-ekqoNRNK1lAcKhZESN/PdpVsWbP9jtiNqzFWkp/yAUdZvJalw2heCYuqRmM5eUJSIYEkgq5sGOjq+ZqsLMjtRA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.23.0", - "@typescript-eslint/types": "5.23.0", - "@typescript-eslint/typescript-estree": "5.23.0", - "debug": "^4.3.2" + "@typescript-eslint/scope-manager": "5.28.0", + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/typescript-estree": "5.28.0", + "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.28.0.tgz", + "integrity": "sha512-LeBLTqF/he1Z+boRhSqnso6YrzcKMTQ8bO/YKEe+6+O/JGof9M0g3IJlIsqfrK/6K03MlFIlycbf1uQR1IjE+w==", "dev": true, "requires": { - "@typescript-eslint/types": "5.23.0", - "@typescript-eslint/visitor-keys": "5.23.0" + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/visitor-keys": "5.28.0" } }, "@typescript-eslint/type-utils": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.28.0.tgz", + "integrity": "sha512-SyKjKh4CXPglueyC6ceAFytjYWMoPHMswPQae236zqe1YbhvCVQyIawesYywGiu98L9DwrxsBN69vGIVxJ4mQQ==", "dev": true, "requires": { - "@typescript-eslint/utils": "5.23.0", - "debug": "^4.3.2", + "@typescript-eslint/utils": "5.28.0", + "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.28.0.tgz", + "integrity": "sha512-2OOm8ZTOQxqkPbf+DAo8oc16sDlVR5owgJfKheBkxBKg1vAfw2JsSofH9+16VPlN9PWtv8Wzhklkqw3k/zCVxA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.28.0.tgz", + "integrity": "sha512-9GX+GfpV+F4hdTtYc6OV9ZkyYilGXPmQpm6AThInpBmKJEyRSIjORJd1G9+bknb7OTFYL+Vd4FBJAO6T78OVqA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.23.0", - "@typescript-eslint/visitor-keys": "5.23.0", - "debug": "^4.3.2", - "globby": "^11.0.4", + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/visitor-keys": "5.28.0", + "debug": "^4.3.4", + "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.5", + "semver": "^7.3.7", "tsutils": "^3.21.0" }, "dependencies": { "semver": { "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -12593,31 +14145,39 @@ } }, "@typescript-eslint/utils": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.28.0.tgz", + "integrity": "sha512-E60N5L0fjv7iPJV3UGc4EC+A3Lcj4jle9zzR0gW7vXhflO7/J29kwiTGITA2RlrmPokKiZbBy2DgaclCaEUs6g==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.23.0", - "@typescript-eslint/types": "5.23.0", - "@typescript-eslint/typescript-estree": "5.23.0", + "@typescript-eslint/scope-manager": "5.28.0", + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/typescript-estree": "5.28.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" } }, "@typescript-eslint/visitor-keys": { - "version": "5.23.0", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.28.0.tgz", + "integrity": "sha512-BtfP1vCor8cWacovzzPFOoeW4kBQxzmhxGoOpt0v1SFvG+nJ0cWaVdJk7cky1ArTcFHHKNIxyo2LLr3oNkSuXA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.23.0", - "eslint-visitor-keys": "^3.0.0" + "@typescript-eslint/types": "5.28.0", + "eslint-visitor-keys": "^3.3.0" } }, "abab": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "dev": true }, "abstract-leveldown": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", "requires": { "buffer": "^6.0.3", "catering": "^2.0.0", @@ -12629,10 +14189,14 @@ }, "acorn": { "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "dev": true }, "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, "requires": { "acorn": "^7.1.1", @@ -12641,21 +14205,29 @@ "dependencies": { "acorn": { "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true } } }, "acorn-jsx": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "requires": {} }, "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 }, "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, "requires": { "debug": "4" @@ -12663,6 +14235,8 @@ }, "ajv": { "version": "7.2.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.4.tgz", + "integrity": "sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -12672,16 +14246,22 @@ }, "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, "requires": { "type-fest": "^0.21.3" } }, "ansi-regex": { - "version": "5.0.1" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "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, "requires": { "color-convert": "^1.9.0" @@ -12689,6 +14269,8 @@ }, "anymatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -12697,10 +14279,14 @@ }, "aproba": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true }, "are-we-there-yet": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", "dev": true, "requires": { "delegates": "^1.0.0", @@ -12709,6 +14295,8 @@ "dependencies": { "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, "requires": { "core-util-is": "~1.0.0", @@ -12722,10 +14310,14 @@ }, "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 }, "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, "requires": { "safe-buffer": "~5.1.0" @@ -12735,10 +14327,14 @@ }, "arg": { "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, "argparse": { "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" @@ -12746,6 +14342,8 @@ }, "array-includes": { "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -12757,10 +14355,14 @@ }, "array-union": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, "array.prototype.flat": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -12769,25 +14371,47 @@ "es-shim-unscopables": "^1.0.0" } }, + "array.prototype.reduce": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz", + "integrity": "sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + } + }, "async-lock": { - "version": "1.3.1" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.3.1.tgz", + "integrity": "sha512-zK7xap9UnttfbE23JmcrNIyueAn6jWshihJqA33U/hEnKprF/lVGBDsBv/bqLm2YMMl1DnpHhUY044eA0t1TUw==" }, "async-mutex": { "version": "0.3.2", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", + "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", "requires": { "tslib": "^2.3.1" } }, "asynckit": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "at-least-node": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, "babel-jest": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", "dev": true, "requires": { "@jest/transform": "^27.5.1", @@ -12802,6 +14426,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -12809,6 +14435,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -12817,6 +14445,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -12824,14 +14454,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -12841,6 +14477,8 @@ }, "babel-plugin-dynamic-import-node": { "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", "dev": true, "requires": { "object.assign": "^4.1.0" @@ -12848,6 +14486,8 @@ }, "babel-plugin-istanbul": { "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -12859,6 +14499,8 @@ }, "babel-plugin-jest-hoist": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -12869,6 +14511,8 @@ }, "babel-plugin-polyfill-corejs2": { "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", "dev": true, "requires": { "@babel/compat-data": "^7.13.11", @@ -12878,6 +14522,8 @@ }, "babel-plugin-polyfill-corejs3": { "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", "dev": true, "requires": { "@babel/helper-define-polyfill-provider": "^0.3.1", @@ -12886,6 +14532,8 @@ }, "babel-plugin-polyfill-regenerator": { "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", "dev": true, "requires": { "@babel/helper-define-polyfill-provider": "^0.3.1" @@ -12893,6 +14541,8 @@ }, "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, "requires": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -12911,6 +14561,8 @@ }, "babel-preset-jest": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", "dev": true, "requires": { "babel-plugin-jest-hoist": "^27.5.1", @@ -12919,25 +14571,35 @@ }, "babel-runtime": { "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", "requires": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" }, "dependencies": { "regenerator-runtime": { - "version": "0.11.1" + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" } } }, "balanced-match": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "base64-js": { - "version": "1.5.1" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "bip39": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz", + "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==", "requires": { "@types/node": "11.11.6", "create-hash": "^1.1.0", @@ -12946,15 +14608,21 @@ }, "dependencies": { "@types/node": { - "version": "11.11.6" + "version": "11.11.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", + "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" } } }, "bitset": { - "version": "5.1.1" + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bitset/-/bitset-5.1.1.tgz", + "integrity": "sha512-oKaRp6mzXedJ1Npo86PKhWfDelI6HxxJo+it9nAcBB0HLVvYVp+5i6yj6DT5hfFgo+TS5T57MRWtw8zhwdTs3g==" }, "bl": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "requires": { "buffer": "^5.5.0", @@ -12964,6 +14632,8 @@ "dependencies": { "buffer": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "requires": { "base64-js": "^1.3.1", @@ -12973,10 +14643,14 @@ } }, "boolbase": { - "version": "1.0.0" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, "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, "requires": { "balanced-match": "^1.0.0", @@ -12985,6 +14659,8 @@ }, "braces": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -12992,21 +14668,27 @@ }, "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 }, "browserslist": { - "version": "4.20.3", + "version": "4.20.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.4.tgz", + "integrity": "sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", + "caniuse-lite": "^1.0.30001349", + "electron-to-chromium": "^1.4.147", "escalade": "^3.1.1", - "node-releases": "^2.0.3", + "node-releases": "^2.0.5", "picocolors": "^1.0.0" } }, "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, "requires": { "fast-json-stable-stringify": "2.x" @@ -13014,6 +14696,8 @@ }, "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, "requires": { "node-int64": "^0.4.0" @@ -13021,6 +14705,8 @@ }, "buffer": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "requires": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -13028,34 +14714,50 @@ }, "buffer-from": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, "call-bind": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" } }, "callsites": { - "version": "3.1.0" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "camelcase": { "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, "caniuse-lite": { - "version": "1.0.30001340", + "version": "1.0.30001352", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz", + "integrity": "sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA==", "dev": true }, "canonicalize": { - "version": "1.0.8" + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-1.0.8.tgz", + "integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==" }, "catering": { - "version": "2.1.1" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==" }, "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, "requires": { "ansi-styles": "^3.2.1", @@ -13065,44 +14767,60 @@ }, "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 }, "check-more-types": { "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", "dev": true }, "cheerio": { - "version": "1.0.0-rc.10", + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.11.tgz", + "integrity": "sha512-bQwNaDIBKID5ts/DsdhxrjqFXYfLw4ste+wMKqWA8DyKcS4qwsPP4Bk8ZNaTJjvpiX/qW3BT4sU7d6Bh5i+dag==", "requires": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "tslib": "^2.4.0" } }, "cheerio-select": { - "version": "1.6.0", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", "requires": { - "css-select": "^4.3.0", - "css-what": "^6.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.3.1", - "domutils": "^2.8.0" + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" } }, "chownr": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true }, "ci-info": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", + "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==", "dev": true }, "cipher-base": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -13110,13 +14828,19 @@ }, "cjs-module-lexer": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, "clean-git-ref": { - "version": "2.0.1" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", + "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==" }, "cliui": { "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -13124,10 +14848,14 @@ }, "dependencies": { "is-fullwidth-code-point": { - "version": "3.0.0" + "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==" }, "string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -13138,18 +14866,26 @@ }, "co": { "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true }, "code-point-at": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", "dev": true }, "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 }, "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, "requires": { "color-name": "1.1.3" @@ -13157,28 +14893,40 @@ }, "color-name": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "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, "requires": { "delayed-stream": "~1.0.0" } }, "commander": { - "version": "8.3.0" + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" }, "concat-map": { "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "console-control-strings": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", "dev": true }, "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, "requires": { "safe-buffer": "~5.1.1" @@ -13186,36 +14934,50 @@ "dependencies": { "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 } } }, "core-js": { - "version": "2.6.12" + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" }, "core-js-compat": { - "version": "3.22.5", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.0.tgz", + "integrity": "sha512-i4FgbtahOArZBEteiL+czI5N/bp17w16bXmLagGThdA2zuX1a5X4HbBmOVD7ERRtk3wMtPOFEmlXpVV4lsvwNw==", "dev": true, "requires": { - "browserslist": "^4.20.3", + "browserslist": "^4.20.4", "semver": "7.0.0" }, "dependencies": { "semver": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", "dev": true } } }, "core-util-is": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, "crc-32": { - "version": "1.2.2" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==" }, "create-hash": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -13226,6 +14988,8 @@ }, "create-hmac": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -13237,16 +15001,22 @@ }, "create-require": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, "cross-fetch": { "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", "requires": { "node-fetch": "2.6.7" } }, "cross-spawn": { "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -13254,24 +15024,32 @@ } }, "css-select": { - "version": "4.3.0", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "requires": { "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "css-what": { - "version": "6.1.0" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" }, "cssom": { "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", "dev": true }, "cssstyle": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, "requires": { "cssom": "~0.3.6" @@ -13279,12 +15057,16 @@ "dependencies": { "cssom": { "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true } } }, "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, "requires": { "abab": "^2.0.3", @@ -13294,38 +15076,54 @@ }, "debug": { "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } }, "decimal.js": { "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "dev": true }, "decompress-response": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "requires": { "mimic-response": "^3.1.0" } }, "dedent": { "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, "deep-extend": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true }, "deep-is": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, "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 }, "deferred-leveldown": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-7.0.0.tgz", + "integrity": "sha512-QKN8NtuS3BC6m0B8vAnBls44tX1WXAFATUsJlruyAYbZpysWV3siH6o/i3g9DCHauzodksO60bdj5NazNbjCmg==", "requires": { "abstract-leveldown": "^7.2.0", "inherits": "^2.0.3" @@ -13333,6 +15131,8 @@ }, "define-properties": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "requires": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -13340,33 +15140,49 @@ }, "delayed-stream": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true }, "delegates": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "dev": true }, "detect-libc": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true }, "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 }, "diff": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, "diff-sequences": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", "dev": true }, "diff3": { - "version": "0.0.3" + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==" }, "dir-glob": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "requires": { "path-type": "^4.0.0" @@ -13374,24 +15190,32 @@ }, "doctrine": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { "esutils": "^2.0.2" } }, "dom-serializer": { - "version": "1.4.1", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" } }, "domelementtype": { - "version": "2.3.0" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" }, "domexception": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", "dev": true, "requires": { "webidl-conversions": "^5.0.0" @@ -13399,37 +15223,51 @@ "dependencies": { "webidl-conversions": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", "dev": true } } }, "domhandler": { - "version": "4.3.1", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "requires": { - "domelementtype": "^2.2.0" + "domelementtype": "^2.3.0" } }, "domutils": { - "version": "2.8.0", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" } }, "electron-to-chromium": { - "version": "1.4.137", + "version": "1.4.154", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.154.tgz", + "integrity": "sha512-GbV9djOkrnj6xmW+YYVVEI3VCQnJ0pnSTu7TW2JyjKd5cakoiSaG5R4RbEtfaD92GsY10DzbU3GYRe+IOA9kqA==", "dev": true }, "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 }, "emoji-regex": { - "version": "8.0.0" + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "encoding-down": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-7.1.0.tgz", + "integrity": "sha512-ky47X5jP84ryk5EQmvedQzELwVJPjCgXDQZGeb9F6r4PdChByCGHTBrVcF3h8ynKVJ1wVbkxTsDC8zBROPypgQ==", "requires": { "abstract-leveldown": "^7.2.0", "inherits": "^2.0.3", @@ -13459,35 +15297,47 @@ }, "dependencies": { "node-forge": { - "version": "1.3.1" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" } } }, "end-of-stream": { "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { "once": "^1.4.0" } }, "entities": { - "version": "2.2.0" + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.0.tgz", + "integrity": "sha512-/iP1rZrSEJ0DTlPiX+jbzlA3eVkY/e8L8SozroF395fIqE3TYF/Nz7YOMAawta+vLmyJ/hkGNNPcSbMADCCXbg==" }, "errno": { "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "requires": { "prr": "~1.0.1" } }, "error-ex": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { "is-arrayish": "^0.2.1" } }, "es-abstract": { - "version": "1.20.0", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -13508,14 +15358,21 @@ "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.1", + "regexp.prototype.flags": "^1.4.3", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" } }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, "es-shim-unscopables": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", "dev": true, "requires": { "has": "^1.0.3" @@ -13523,6 +15380,8 @@ }, "es-to-primitive": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -13530,14 +15389,20 @@ } }, "escalade": { - "version": "3.1.1" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, "escape-string-regexp": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, "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, "requires": { "esprima": "^4.0.1", @@ -13549,10 +15414,14 @@ "dependencies": { "estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "levn": { "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "dev": true, "requires": { "prelude-ls": "~1.1.2", @@ -13561,6 +15430,8 @@ }, "optionator": { "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "requires": { "deep-is": "~0.1.3", @@ -13573,10 +15444,14 @@ }, "prelude-ls": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", "dev": true }, "type-check": { "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", "dev": true, "requires": { "prelude-ls": "~1.1.2" @@ -13585,10 +15460,12 @@ } }, "eslint": { - "version": "8.15.0", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.17.0.tgz", + "integrity": "sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.2.3", + "@eslint/eslintrc": "^1.3.0", "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", @@ -13606,7 +15483,7 @@ "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", - "globals": "^13.6.0", + "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -13627,6 +15504,8 @@ "dependencies": { "ajv": { "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -13637,6 +15516,8 @@ }, "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, "requires": { "color-convert": "^2.0.1" @@ -13644,10 +15525,14 @@ }, "argparse": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -13656,6 +15541,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -13663,14 +15550,20 @@ }, "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 }, "escape-string-regexp": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, "eslint-scope": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, "requires": { "esrecurse": "^4.3.0", @@ -13679,10 +15572,14 @@ }, "estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "globals": { "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -13690,10 +15587,14 @@ }, "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 }, "js-yaml": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { "argparse": "^2.0.1" @@ -13701,10 +15602,14 @@ }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -13712,17 +15617,23 @@ }, "type-fest": { "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true } } }, "eslint-config-prettier": { "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", "dev": true, "requires": {} }, "eslint-import-resolver-node": { "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dev": true, "requires": { "debug": "^3.2.7", @@ -13731,6 +15642,8 @@ "dependencies": { "debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -13740,6 +15653,8 @@ }, "eslint-module-utils": { "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", "dev": true, "requires": { "debug": "^3.2.7", @@ -13748,6 +15663,8 @@ "dependencies": { "debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -13755,6 +15672,8 @@ }, "find-up": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", "dev": true, "requires": { "locate-path": "^2.0.0" @@ -13762,6 +15681,8 @@ }, "locate-path": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", "dev": true, "requires": { "p-locate": "^2.0.0", @@ -13770,6 +15691,8 @@ }, "p-limit": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { "p-try": "^1.0.0" @@ -13777,6 +15700,8 @@ }, "p-locate": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", "dev": true, "requires": { "p-limit": "^1.1.0" @@ -13784,16 +15709,22 @@ }, "p-try": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", "dev": true }, "path-exists": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "dev": true } } }, "eslint-plugin-import": { "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, "requires": { "array-includes": "^3.1.4", @@ -13813,6 +15744,8 @@ "dependencies": { "debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -13820,6 +15753,8 @@ }, "doctrine": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -13827,12 +15762,16 @@ }, "ms": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } }, "eslint-plugin-prettier": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", + "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" @@ -13840,6 +15779,8 @@ }, "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, "requires": { "esrecurse": "^4.3.0", @@ -13848,6 +15789,8 @@ }, "eslint-utils": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { "eslint-visitor-keys": "^2.0.0" @@ -13855,20 +15798,28 @@ "dependencies": { "eslint-visitor-keys": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true } } }, "eslint-visitor-keys": { "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, "esm": { "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", "optional": true }, "espree": { "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", "dev": true, "requires": { "acorn": "^8.7.1", @@ -13878,10 +15829,14 @@ }, "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 }, "esquery": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -13889,12 +15844,16 @@ "dependencies": { "estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } }, "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, "requires": { "estraverse": "^5.2.0" @@ -13902,20 +15861,28 @@ "dependencies": { "estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } }, "estraverse": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "execa": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { "cross-spawn": "^7.0.3", @@ -13931,14 +15898,20 @@ }, "exit": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true }, "expand-template": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "dev": true }, "expect": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", "dev": true, "requires": { "@jest/types": "^27.5.1", @@ -13948,20 +15921,28 @@ } }, "fast-deep-equal": { - "version": "3.1.3" + "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==" }, "fast-diff": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, "fast-fuzzy": { - "version": "1.11.1", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/fast-fuzzy/-/fast-fuzzy-1.11.2.tgz", + "integrity": "sha512-H1ct10Pzx+pSO4h7F1uBXET91ay2hy67J1aQZFKL23EXsOoanpwjPNQQoc+NhClKJMmlGGN+0bXhIdFJX70BJw==", "requires": { "graphemesplit": "^2.4.1" } }, "fast-glob": { "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -13973,6 +15954,8 @@ "dependencies": { "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, "requires": { "is-glob": "^4.0.1" @@ -13982,14 +15965,20 @@ }, "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 }, "fast-levenshtein": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "fastq": { "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -13997,6 +15986,8 @@ }, "fb-watchman": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", "dev": true, "requires": { "bser": "2.1.1" @@ -14004,6 +15995,8 @@ }, "fd-lock": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fd-lock/-/fd-lock-1.2.0.tgz", + "integrity": "sha512-Lk/pKH2DldLpG4Yh/sOOY84k5VqNzxHPffGwf1+yYI+/qMXzTPp9KJMX+Wh6n4xqGSA1Mu7JPmaDArfJGw2O/A==", "requires": { "napi-macros": "^2.0.0", "node-gyp-build": "^4.2.2" @@ -14011,6 +16004,8 @@ }, "file-entry-cache": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { "flat-cache": "^3.0.4" @@ -14018,6 +16013,8 @@ }, "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, "requires": { "to-regex-range": "^5.0.1" @@ -14025,6 +16022,8 @@ }, "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, "requires": { "locate-path": "^5.0.0", @@ -14033,6 +16032,8 @@ }, "flat-cache": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { "flatted": "^3.1.0", @@ -14041,10 +16042,14 @@ }, "flatted": { "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, "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, "requires": { "asynckit": "^0.4.0", @@ -14054,6 +16059,8 @@ }, "from2": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", "dev": true, "requires": { "inherits": "^2.0.1", @@ -14062,6 +16069,8 @@ "dependencies": { "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, "requires": { "core-util-is": "~1.0.0", @@ -14075,10 +16084,14 @@ }, "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 }, "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, "requires": { "safe-buffer": "~5.1.0" @@ -14088,10 +16101,14 @@ }, "fs-constants": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, "fs-extra": { "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -14102,13 +16119,26 @@ }, "fs.realpath": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, "function-bind": { - "version": "1.1.1" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "function.prototype.name": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -14118,13 +16148,19 @@ }, "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": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "dev": true }, "functions-have-names": { - "version": "1.2.3" + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" }, "gauge": { "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", "dev": true, "requires": { "aproba": "^1.0.3", @@ -14139,10 +16175,14 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "strip-ansi": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -14152,29 +16192,41 @@ }, "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 }, "get-caller-file": { - "version": "2.0.5" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-intrinsic": { - "version": "1.1.1", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" } }, "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 }, "get-stream": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, "get-symbol-description": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -14182,22 +16234,28 @@ }, "github-from-package": { "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "dev": true }, "glob": { - "version": "7.2.0", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "glob-parent": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "requires": { "is-glob": "^4.0.3" @@ -14205,10 +16263,14 @@ }, "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 }, "globby": { "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "requires": { "array-union": "^2.1.0", @@ -14220,14 +16282,20 @@ } }, "google-protobuf": { - "version": "3.20.1" + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.20.1.tgz", + "integrity": "sha512-XMf1+O32FjYIV3CYu6Tuh5PNbfNEU5Xu22X+Xkdb/DUexFlCzhvv7d5Iirm4AOwn8lv4al1YvIhzGrg2j9Zfzw==" }, "graceful-fs": { "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "graphemesplit": { "version": "2.4.4", + "resolved": "https://registry.npmjs.org/graphemesplit/-/graphemesplit-2.4.4.tgz", + "integrity": "sha512-lKrpp1mk1NH26USxC/Asw4OHbhSQf5XfrWZ+CDv/dFVvd1j17kFgMotdJvOesmHkbFX9P9sBfpH8VogxOWLg8w==", "requires": { "js-base64": "^3.6.0", "unicode-trie": "^2.0.0" @@ -14235,6 +16303,8 @@ }, "grpc_tools_node_protoc_ts": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/grpc_tools_node_protoc_ts/-/grpc_tools_node_protoc_ts-5.3.2.tgz", + "integrity": "sha512-7xPSeu8bwjcird3i9R5+9O4BF2Lhv9fMBdeobfUc2Bys9tSVtm/VB3WjTpKV78WlLYJyD94+wL/8hJqaMZ53Hw==", "dev": true, "requires": { "google-protobuf": "3.15.8", @@ -14243,12 +16313,16 @@ "dependencies": { "google-protobuf": { "version": "3.15.8", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.15.8.tgz", + "integrity": "sha512-2jtfdqTaSxk0cuBJBtTTWsot4WtR9RVr2rXg7x7OoqiuOKopPrwXpM1G4dXIkLcUNRh3RKzz76C8IOkksZSeOw==", "dev": true } } }, "handlebars": { "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, "requires": { "minimist": "^1.2.5", @@ -14260,38 +16334,54 @@ }, "has": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "requires": { "function-bind": "^1.1.1" } }, "has-bigints": { - "version": "1.0.2" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" }, "has-flag": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, "has-property-descriptors": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", "requires": { "get-intrinsic": "^1.1.1" } }, "has-symbols": { - "version": "1.0.3" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, "has-tostringtag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "requires": { "has-symbols": "^1.0.2" } }, "has-unicode": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, "hash-base": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "requires": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", @@ -14300,6 +16390,8 @@ }, "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, "requires": { "whatwg-encoding": "^1.0.5" @@ -14307,19 +16399,25 @@ }, "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 }, "htmlparser2": { - "version": "6.1.0", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" } }, "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, "requires": { "@tootallnate/once": "1", @@ -14329,6 +16427,8 @@ }, "https-proxy-agent": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "requires": { "agent-base": "6", @@ -14337,23 +16437,33 @@ }, "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 }, "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, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "ieee754": { - "version": "1.2.1" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { - "version": "5.2.0" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" }, "import-fresh": { "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -14362,12 +16472,16 @@ "dependencies": { "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 } } }, "import-local": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "requires": { "pkg-dir": "^4.2.0", @@ -14376,10 +16490,14 @@ }, "imurmurhash": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true }, "inflight": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "requires": { "once": "^1.3.0", @@ -14387,14 +16505,20 @@ } }, "inherits": { - "version": "2.0.4" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, "internal-slot": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "requires": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", @@ -14409,6 +16533,8 @@ }, "into-stream": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", + "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", "dev": true, "requires": { "from2": "^2.3.0", @@ -14416,33 +16542,47 @@ } }, "ip-num": { - "version": "1.4.0" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ip-num/-/ip-num-1.4.0.tgz", + "integrity": "sha512-MP+gq4uBvrvm+G7EwP14GcJeFK49/p6sZrNOarMUoExLRodULJQM8mnkb/SbT1YKxRsZfh8rgwei2pUJIa35jA==" }, "is-arrayish": { "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, "is-bigint": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "requires": { "has-bigints": "^1.0.1" } }, "is-boolean-object": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" } }, "is-buffer": { - "version": "2.0.5" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" }, "is-callable": { - "version": "1.2.4" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, "is-core-module": { "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, "requires": { "has": "^1.0.3" @@ -14450,16 +16590,22 @@ }, "is-date-object": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "requires": { "has-tostringtag": "^1.0.0" } }, "is-extglob": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "dev": true, "requires": { "number-is-nan": "^1.0.0" @@ -14467,37 +16613,53 @@ }, "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 }, "is-glob": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, "is-negative-zero": { - "version": "2.0.2" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" }, "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 }, "is-number-object": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "requires": { "has-tostringtag": "^1.0.0" } }, "is-observable": { - "version": "2.1.0" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-2.1.0.tgz", + "integrity": "sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw==" }, "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 }, "is-regex": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -14505,45 +16667,63 @@ }, "is-shared-array-buffer": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "requires": { "call-bind": "^1.0.2" } }, "is-stream": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, "is-string": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "requires": { "has-tostringtag": "^1.0.0" } }, "is-symbol": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "requires": { "has-symbols": "^1.0.2" } }, "is-typedarray": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, "is-weakref": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "requires": { "call-bind": "^1.0.2" } }, "isarray": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, "isexe": { - "version": "2.0.0" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "isomorphic-git": { - "version": "1.17.2", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.18.1.tgz", + "integrity": "sha512-SNYmHxzDMwmB0N5jNaac9xmUOYv9VpWqBoPVQFvPEp47dfREOfsWy32IDEM00jzrDLGn+GsaPL2j6RYIDaKtJw==", "requires": { "async-lock": "^1.1.0", "clean-git-ref": "^2.0.1", @@ -14560,10 +16740,14 @@ }, "istanbul-lib-coverage": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true }, "istanbul-lib-instrument": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dev": true, "requires": { "@babel/core": "^7.12.3", @@ -14575,6 +16759,8 @@ }, "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, "requires": { "istanbul-lib-coverage": "^3.0.0", @@ -14584,10 +16770,14 @@ "dependencies": { "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -14597,6 +16787,8 @@ }, "istanbul-lib-source-maps": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "requires": { "debug": "^4.1.1", @@ -14606,6 +16798,8 @@ }, "istanbul-reports": { "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -14614,6 +16808,8 @@ }, "jest": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "dev": true, "requires": { "@jest/core": "^27.5.1", @@ -14623,6 +16819,8 @@ }, "jest-changed-files": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", "dev": true, "requires": { "@jest/types": "^27.5.1", @@ -14632,6 +16830,8 @@ }, "jest-circus": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", "dev": true, "requires": { "@jest/environment": "^27.5.1", @@ -14657,6 +16857,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -14664,6 +16866,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -14672,6 +16876,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -14679,14 +16885,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -14696,6 +16908,8 @@ }, "jest-cli": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", "dev": true, "requires": { "@jest/core": "^27.5.1", @@ -14714,6 +16928,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -14721,6 +16937,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -14729,6 +16947,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -14736,14 +16956,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -14753,6 +16979,8 @@ }, "jest-config": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", "dev": true, "requires": { "@babel/core": "^7.8.0", @@ -14783,6 +17011,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -14790,6 +17020,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -14798,6 +17030,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -14805,14 +17039,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -14822,6 +17062,8 @@ }, "jest-diff": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", "dev": true, "requires": { "chalk": "^4.0.0", @@ -14832,6 +17074,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -14839,6 +17083,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -14847,6 +17093,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -14854,14 +17102,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -14871,6 +17125,8 @@ }, "jest-docblock": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", "dev": true, "requires": { "detect-newline": "^3.0.0" @@ -14878,6 +17134,8 @@ }, "jest-each": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", "dev": true, "requires": { "@jest/types": "^27.5.1", @@ -14889,6 +17147,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -14896,6 +17156,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -14904,6 +17166,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -14911,14 +17175,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -14928,6 +17198,8 @@ }, "jest-environment-jsdom": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", "dev": true, "requires": { "@jest/environment": "^27.5.1", @@ -14941,6 +17213,8 @@ }, "jest-environment-node": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", "dev": true, "requires": { "@jest/environment": "^27.5.1", @@ -14953,10 +17227,14 @@ }, "jest-get-type": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", "dev": true }, "jest-haste-map": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "requires": { "@jest/types": "^27.5.1", @@ -14976,6 +17254,8 @@ }, "jest-jasmine2": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", "dev": true, "requires": { "@jest/environment": "^27.5.1", @@ -14999,6 +17279,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -15006,6 +17288,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -15014,6 +17298,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -15021,14 +17307,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -15049,6 +17341,8 @@ }, "jest-leak-detector": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", "dev": true, "requires": { "jest-get-type": "^27.5.1", @@ -15057,6 +17351,8 @@ }, "jest-matcher-utils": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", "dev": true, "requires": { "chalk": "^4.0.0", @@ -15067,6 +17363,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -15074,6 +17372,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -15082,6 +17382,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -15089,14 +17391,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -15106,6 +17414,8 @@ }, "jest-message-util": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", @@ -15121,6 +17431,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -15128,6 +17440,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -15136,6 +17450,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -15143,14 +17459,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -15160,6 +17482,8 @@ }, "jest-mock": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", "dev": true, "requires": { "@jest/types": "^27.5.1", @@ -15167,26 +17491,36 @@ } }, "jest-mock-process": { - "version": "1.4.1", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/jest-mock-process/-/jest-mock-process-1.5.1.tgz", + "integrity": "sha512-CPu46KyUiVSxE+LkqBuscqGmy1bvW2vJQuNstt83iLtFaFjgrgmp6LY04IKuOhhlGhcrdi86Gqq5/fTE2wG6lg==", "dev": true, "requires": {} }, "jest-mock-props": { "version": "1.9.1", + "resolved": "https://registry.npmjs.org/jest-mock-props/-/jest-mock-props-1.9.1.tgz", + "integrity": "sha512-PvTySOTw/K4dwL7XrVGq/VUZRm/qXPrV4+NuhgxuWkmE3h/Fd+g+qB0evK5vSBAkI8TaxvTXYv17IdxWdEze1g==", "dev": true, "requires": {} }, "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, "requires": {} }, "jest-regex-util": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "dev": true }, "jest-resolve": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", "dev": true, "requires": { "@jest/types": "^27.5.1", @@ -15203,6 +17537,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -15210,6 +17546,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -15218,6 +17556,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -15225,14 +17565,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -15242,6 +17588,8 @@ }, "jest-resolve-dependencies": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", "dev": true, "requires": { "@jest/types": "^27.5.1", @@ -15251,6 +17599,8 @@ }, "jest-runner": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", "dev": true, "requires": { "@jest/console": "^27.5.1", @@ -15278,6 +17628,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -15285,6 +17637,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -15293,6 +17647,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -15300,14 +17656,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -15317,6 +17679,8 @@ }, "jest-runtime": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", "dev": true, "requires": { "@jest/environment": "^27.5.1", @@ -15345,6 +17709,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -15352,6 +17718,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -15360,6 +17728,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -15367,14 +17737,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -15384,6 +17760,8 @@ }, "jest-serializer": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", "dev": true, "requires": { "@types/node": "*", @@ -15392,6 +17770,8 @@ }, "jest-snapshot": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", "dev": true, "requires": { "@babel/core": "^7.7.2", @@ -15420,6 +17800,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -15427,6 +17809,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -15435,6 +17819,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -15442,14 +17828,20 @@ }, "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 }, "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 }, "semver": { "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -15457,6 +17849,8 @@ }, "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, "requires": { "has-flag": "^4.0.0" @@ -15466,6 +17860,8 @@ }, "jest-util": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", "dev": true, "requires": { "@jest/types": "^27.5.1", @@ -15478,6 +17874,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -15485,6 +17883,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -15493,6 +17893,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -15500,14 +17902,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -15517,6 +17925,8 @@ }, "jest-validate": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", "dev": true, "requires": { "@jest/types": "^27.5.1", @@ -15529,6 +17939,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -15536,10 +17948,14 @@ }, "camelcase": { "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -15548,6 +17964,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -15555,14 +17973,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -15572,6 +17996,8 @@ }, "jest-watcher": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", "dev": true, "requires": { "@jest/test-result": "^27.5.1", @@ -15585,6 +18011,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -15592,6 +18020,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -15600,6 +18030,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -15607,14 +18039,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -15624,6 +18062,8 @@ }, "jest-worker": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "requires": { "@types/node": "*", @@ -15633,10 +18073,14 @@ "dependencies": { "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -15645,17 +18089,25 @@ } }, "jose": { - "version": "4.8.1" + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.8.1.tgz", + "integrity": "sha512-+/hpTbRcCw9YC0TOfN1W47pej4a9lRmltdOVdRLz5FP5UvUq3CenhXjQK7u/8NdMIIShMXYAh9VLPhc7TjhvFw==" }, "js-base64": { - "version": "3.7.2" + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.2.tgz", + "integrity": "sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==" }, "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 }, "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, "requires": { "argparse": "^1.0.7", @@ -15664,6 +18116,8 @@ }, "jsdom": { "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, "requires": { "abab": "^2.0.5", @@ -15693,33 +18147,55 @@ "whatwg-url": "^8.5.0", "ws": "^7.4.6", "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + } } }, "jsesc": { "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, "json-parse-even-better-errors": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, "json-schema-traverse": { - "version": "1.0.0" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, "json5": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "dev": true }, "jsonc-parser": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", "dev": true }, "jsonfile": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "requires": { "graceful-fs": "^4.1.6", @@ -15727,14 +18203,20 @@ } }, "kleur": { - "version": "3.0.3" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" }, "lazy-ass": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", "dev": true }, "level": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/level/-/level-7.0.1.tgz", + "integrity": "sha512-w3E64+ALx2eZf8RV5JL4kIcE0BFAvQscRYd1yU4YVqZN9RGTQxXSvH202xvK15yZwFFxRXe60f13LJjcJ//I4Q==", "requires": { "level-js": "^6.1.0", "level-packager": "^6.0.1", @@ -15743,21 +18225,29 @@ }, "level-codec": { "version": "10.0.0", + "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-10.0.0.tgz", + "integrity": "sha512-QW3VteVNAp6c/LuV6nDjg7XDXx9XHK4abmQarxZmlRSDyXYk20UdaJTSX6yzVvQ4i0JyWSB7jert0DsyD/kk6g==", "requires": { "buffer": "^6.0.3" } }, "level-concat-iterator": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", + "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", "requires": { "catering": "^2.1.0" } }, "level-errors": { - "version": "3.0.1" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-3.0.1.tgz", + "integrity": "sha512-tqTL2DxzPDzpwl0iV5+rBCv65HWbHp6eutluHNcVIftKZlQN//b6GEnZDM2CvGZvzGYMwyPtYppYnydBQd2SMQ==" }, "level-iterator-stream": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-5.0.0.tgz", + "integrity": "sha512-wnb1+o+CVFUDdiSMR/ZymE2prPs3cjVLlXuDeSq9Zb8o032XrabGEXcTCsBxprAtseO3qvFeGzh6406z9sOTRA==", "requires": { "inherits": "^2.0.4", "readable-stream": "^3.4.0" @@ -15765,6 +18255,8 @@ }, "level-js": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/level-js/-/level-js-6.1.0.tgz", + "integrity": "sha512-i7mPtkZm68aewfv0FnIUWvFUFfoyzIvVKnUmuQGrelEkP72vSPTaA1SGneWWoCV5KZJG4wlzbJLp1WxVNGuc6A==", "requires": { "abstract-leveldown": "^7.2.0", "buffer": "^6.0.3", @@ -15775,16 +18267,22 @@ }, "level-packager": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-6.0.1.tgz", + "integrity": "sha512-8Ezr0XM6hmAwqX9uu8IGzGNkWz/9doyPA8Oo9/D7qcMI6meJC+XhIbNYHukJhIn8OGdlzQs/JPcL9B8lA2F6EQ==", "requires": { "encoding-down": "^7.1.0", "levelup": "^5.1.1" } }, "level-supports": { - "version": "2.1.0" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", + "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==" }, "leveldown": { "version": "6.1.1", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.1.tgz", + "integrity": "sha512-88c+E+Eizn4CkQOBHwqlCJaTNEjGpaEIikn1S+cINc5E9HEvJ77bqY4JY/HxT5u0caWqsc3P3DcFIKBI1vHt+A==", "requires": { "abstract-leveldown": "^7.2.0", "napi-macros": "~2.0.0", @@ -15793,6 +18291,8 @@ }, "levelup": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-5.1.1.tgz", + "integrity": "sha512-0mFCcHcEebOwsQuk00WJwjLI6oCjbBuEYdh/RaRqhjnyVlzqf41T1NnDtCedumZ56qyIh8euLFDqV1KfzTAVhg==", "requires": { "catering": "^2.0.0", "deferred-leveldown": "^7.0.0", @@ -15804,10 +18304,14 @@ }, "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 }, "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, "requires": { "prelude-ls": "^1.2.1", @@ -15815,14 +18319,20 @@ } }, "lexicographic-integer": { - "version": "1.1.0" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/lexicographic-integer/-/lexicographic-integer-1.1.0.tgz", + "integrity": "sha512-MQCrf1gG31DJSNQDiIfgk7CQVlXkO6xC+DFGExs5WQWlxWSSAroH5k/UrKrS6LThHDHBoc3X1pNoYHDKOCPWRQ==" }, "lines-and-columns": { "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, "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, "requires": { "p-locate": "^4.1.0" @@ -15830,42 +18340,62 @@ }, "lodash": { "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "lodash.camelcase": { - "version": "4.3.0" + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" }, "lodash.debounce": { "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, "lodash.memoize": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "dev": true }, "lodash.merge": { "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "long": { - "version": "4.0.0" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "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, "requires": { "yallist": "^4.0.0" } }, "ltgt": { - "version": "2.2.1" + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", + "integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==" }, "lunr": { "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", "dev": true }, "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, "requires": { "semver": "^6.0.0" @@ -15873,21 +18403,29 @@ }, "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 }, "makeerror": { "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, "requires": { "tmpl": "1.0.5" } }, "marked": { - "version": "4.0.15", + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz", + "integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==", "dev": true }, "md5.js": { "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -15896,14 +18434,20 @@ }, "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 }, "merge2": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, "micromatch": { "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { "braces": "^3.0.2", @@ -15912,10 +18456,14 @@ }, "mime-db": { "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true }, "mime-types": { "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "requires": { "mime-db": "1.52.0" @@ -15923,23 +18471,33 @@ }, "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 }, "mimic-response": { - "version": "3.1.0" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" }, "minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.6" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "minimisted": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", + "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", "requires": { "minimist": "^1.2.5" } @@ -15951,10 +18509,14 @@ }, "mkdirp-classic": { "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, "mocked-env": { "version": "1.3.5", + "resolved": "https://registry.npmjs.org/mocked-env/-/mocked-env-1.3.5.tgz", + "integrity": "sha512-GyYY6ynVOdEoRlaGpaq8UYwdWkvrsU2xRme9B+WPSuJcNjh17+3QIxSYU6zwee0SbehhV6f06VZ4ahjG+9zdrA==", "dev": true, "requires": { "check-more-types": "2.24.0", @@ -15965,6 +18527,8 @@ "dependencies": { "debug": { "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -15973,13 +18537,19 @@ } }, "ms": { - "version": "2.1.2" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multiformats": { - "version": "9.6.5" + "version": "9.6.5", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.6.5.tgz", + "integrity": "sha512-vMwf/FUO+qAPvl3vlSZEgEVFY/AxeZq5yg761ScF3CZsXgmTi/HGkicUiNN0CI4PW8FiY2P0OLklOcmQjdQJhw==" }, "multistream": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", + "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", "dev": true, "requires": { "once": "^1.4.0", @@ -15988,21 +18558,31 @@ }, "napi-build-utils": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", "dev": true }, "napi-macros": { - "version": "2.0.0" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", + "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" }, "natural-compare": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "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 }, "nexpect": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/nexpect/-/nexpect-0.6.0.tgz", + "integrity": "sha512-gG4cO0zoNG+kaPesw516hPVEKLW3YizGU8UWMr5lpkHKOgoTWcu4sPQN7rWVAIL4Ck87zM4N8immPUhYPdDz3g==", "dev": true, "requires": { "cross-spawn": "^6.0.5" @@ -16010,6 +18590,8 @@ "dependencies": { "cross-spawn": { "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -16021,14 +18603,20 @@ }, "path-key": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true }, "semver": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "shebang-command": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, "requires": { "shebang-regex": "^1.0.0" @@ -16036,10 +18624,14 @@ }, "shebang-regex": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true }, "which": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -16049,10 +18641,14 @@ }, "nice-try": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "node-abi": { "version": "2.30.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", + "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", "dev": true, "requires": { "semver": "^5.4.1" @@ -16060,24 +18656,34 @@ "dependencies": { "semver": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } }, "node-fetch": { "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "requires": { "whatwg-url": "^5.0.0" }, "dependencies": { "tr46": { - "version": "0.0.3" + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "webidl-conversions": { - "version": "3.0.1" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "whatwg-url": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -16086,25 +18692,37 @@ } }, "node-forge": { - "version": "0.10.0" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" }, "node-gyp-build": { - "version": "4.4.0" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==" }, "node-int64": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true }, "node-releases": { - "version": "2.0.4", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", "dev": true }, "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 }, "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, "requires": { "path-key": "^3.0.0" @@ -16112,6 +18730,8 @@ }, "npmlog": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -16121,31 +18741,45 @@ } }, "nth-check": { - "version": "2.0.1", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "requires": { "boolbase": "^1.0.0" } }, "number-is-nan": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", "dev": true }, "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 }, "object-assign": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true }, "object-inspect": { - "version": "1.12.0" + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" }, "object-keys": { - "version": "1.1.1" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -16154,15 +18788,20 @@ } }, "object.getownpropertydescriptors": { - "version": "2.1.3", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz", + "integrity": "sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ==", "requires": { + "array.prototype.reduce": "^1.0.4", "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.1" } }, "object.values": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -16171,16 +18810,22 @@ } }, "observable-fns": { - "version": "0.6.1" + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/observable-fns/-/observable-fns-0.6.1.tgz", + "integrity": "sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==" }, "once": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "requires": { "wrappy": "1" } }, "onetime": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "requires": { "mimic-fn": "^2.1.0" @@ -16188,6 +18833,8 @@ }, "optionator": { "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "requires": { "deep-is": "^0.1.3", @@ -16200,10 +18847,14 @@ }, "p-is-promise": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", "dev": true }, "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, "requires": { "p-try": "^2.0.0" @@ -16211,6 +18862,8 @@ }, "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, "requires": { "p-limit": "^2.2.0" @@ -16218,13 +18871,19 @@ }, "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 }, "pako": { - "version": "1.0.11" + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "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, "requires": { "callsites": "^3.0.0" @@ -16232,6 +18891,8 @@ }, "parse-json": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -16241,35 +18902,55 @@ } }, "parse5": { - "version": "6.0.1" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", + "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", + "requires": { + "entities": "^4.3.0" + } }, "parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", "requires": { - "parse5": "^6.0.1" + "domhandler": "^5.0.2", + "parse5": "^7.0.0" } }, "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 }, "path-is-absolute": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, "path-key": { - "version": "3.1.1" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, "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 }, "path-type": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, "pbkdf2": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -16280,21 +18961,31 @@ }, "picocolors": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, "picomatch": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "pify": { - "version": "4.0.1" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" }, "pirates": { "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true }, "pkg": { "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.6.0.tgz", + "integrity": "sha512-mHrAVSQWmHA41RnUmRpC7pK9lNnMfdA16CF3cqOI22a8LZxOQzF7M8YWtA2nfs+d7I0MTDXOtkDsAsFXeCpYjg==", "dev": true, "requires": { "@babel/parser": "7.16.2", @@ -16316,10 +19007,14 @@ "dependencies": { "@babel/parser": { "version": "7.16.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", + "integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", "dev": true }, "@babel/types": { "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", + "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.15.7", @@ -16328,6 +19023,8 @@ }, "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, "requires": { "color-convert": "^2.0.1" @@ -16335,6 +19032,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -16343,6 +19042,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -16350,14 +19051,20 @@ }, "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 }, "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -16365,12 +19072,16 @@ }, "tslib": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", "dev": true } } }, "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, "requires": { "find-up": "^4.0.0" @@ -16378,6 +19089,8 @@ }, "pkg-fetch": { "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.3.0.tgz", + "integrity": "sha512-xJnIZ1KP+8rNN+VLafwu4tEeV4m8IkFBDdCFqmAJz9K1aiXEtbARmdbEe6HlXWGSVuShSHjFXpfkKRkDBQ5kiA==", "dev": true, "requires": { "chalk": "^4.1.2", @@ -16392,6 +19105,8 @@ "dependencies": { "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, "requires": { "color-convert": "^2.0.1" @@ -16399,6 +19114,8 @@ }, "chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -16407,6 +19124,8 @@ }, "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, "requires": { "color-name": "~1.1.4" @@ -16414,14 +19133,20 @@ }, "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 }, "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 }, "semver": { "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -16429,6 +19154,8 @@ }, "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, "requires": { "has-flag": "^4.0.0" @@ -16438,6 +19165,8 @@ }, "prebuild-install": { "version": "6.1.4", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", + "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", "dev": true, "requires": { "detect-libc": "^1.0.3", @@ -16457,6 +19186,8 @@ "dependencies": { "decompress-response": { "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "dev": true, "requires": { "mimic-response": "^2.0.0" @@ -16464,10 +19195,14 @@ }, "mimic-response": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", "dev": true }, "simple-get": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "dev": true, "requires": { "decompress-response": "^4.2.0", @@ -16479,14 +19214,20 @@ }, "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 }, "prettier": { "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", "dev": true }, "prettier-linter-helpers": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "requires": { "fast-diff": "^1.1.2" @@ -16494,6 +19235,8 @@ }, "pretty-format": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "requires": { "ansi-regex": "^5.0.1", @@ -16503,20 +19246,28 @@ "dependencies": { "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 } } }, "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 }, "progress": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "prompts": { "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "requires": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -16524,6 +19275,8 @@ }, "protobufjs": { "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -16541,14 +19294,20 @@ } }, "prr": { - "version": "1.0.1" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==" }, "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 }, "pump": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -16556,23 +19315,33 @@ } }, "punycode": { - "version": "2.1.1" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "queue-microtask": { - "version": "1.2.3" + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, "ramda": { "version": "0.27.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", + "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", "dev": true }, "randombytes": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "requires": { "safe-buffer": "^5.1.0" } }, "rc": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "requires": { "deep-extend": "^0.6.0", @@ -16583,16 +19352,22 @@ "dependencies": { "strip-json-comments": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true } } }, "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 }, "readable-stream": { "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -16610,10 +19385,14 @@ }, "regenerate": { "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true }, "regenerate-unicode-properties": { "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "dev": true, "requires": { "regenerate": "^1.4.2" @@ -16621,10 +19400,14 @@ }, "regenerator-runtime": { "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "dev": true }, "regenerator-transform": { "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "dev": true, "requires": { "@babel/runtime": "^7.8.4" @@ -16632,6 +19415,8 @@ }, "regexp.prototype.flags": { "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -16640,10 +19425,14 @@ }, "regexpp": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "regexpu-core": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", "dev": true, "requires": { "regenerate": "^1.4.2", @@ -16656,10 +19445,14 @@ }, "regjsgen": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", "dev": true }, "regjsparser": { "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -16667,18 +19460,26 @@ "dependencies": { "jsesc": { "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", "dev": true } } }, "require-directory": { - "version": "2.1.1" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" }, "require-from-string": { - "version": "2.0.2" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, "resolve": { "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { "is-core-module": "^2.8.1", @@ -16688,6 +19489,8 @@ }, "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, "requires": { "resolve-from": "^5.0.0" @@ -16695,14 +19498,20 @@ }, "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 }, "resolve.exports": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", "dev": true }, "resource-counter": { "version": "1.2.4", + "resolved": "https://registry.npmjs.org/resource-counter/-/resource-counter-1.2.4.tgz", + "integrity": "sha512-DGJChvE5r4smqPE+xYNv9r1u/I9cCfRR5yfm7D6EQckdKqMyVpJ5z0s40yn0EM0puFxHg6mPORrQLQdEbJ/RnQ==", "requires": { "babel-runtime": "^6.26.0", "bitset": "^5.0.3" @@ -16710,10 +19519,14 @@ }, "reusify": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, "rimraf": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" @@ -16721,6 +19534,8 @@ }, "ripemd160": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -16728,6 +19543,8 @@ }, "run-parallel": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "requires": { "queue-microtask": "^1.2.2" @@ -16735,19 +19552,27 @@ }, "run-parallel-limit": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", "requires": { "queue-microtask": "^1.2.2" } }, "safe-buffer": { - "version": "5.2.1" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safer-buffer": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "saxes": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", "dev": true, "requires": { "xmlchars": "^2.2.0" @@ -16755,14 +19580,20 @@ }, "semver": { "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "set-blocking": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, "sha.js": { "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -16770,12 +19601,16 @@ }, "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==", "requires": { "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "3.0.0" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, "shelljs": { "version": "0.8.5", @@ -16790,6 +19625,8 @@ }, "shiki": { "version": "0.10.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", + "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", "dev": true, "requires": { "jsonc-parser": "^3.0.0", @@ -16809,6 +19646,8 @@ }, "side-channel": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -16817,13 +19656,19 @@ }, "signal-exit": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, "simple-concat": { - "version": "1.0.1" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" }, "simple-get": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", "requires": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -16831,18 +19676,26 @@ } }, "sisteransi": { - "version": "1.0.5" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, "slash": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "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 }, "source-map-support": { "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -16851,10 +19704,14 @@ }, "sprintf-js": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "stack-utils": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "requires": { "escape-string-regexp": "^2.0.0" @@ -16862,12 +19719,16 @@ "dependencies": { "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 } } }, "stream-meter": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", + "integrity": "sha512-4sOEtrbgFotXwnEuzzsQBYEV1elAeFSO8rSGeTwabuX1RRn/kEq9JVH7I0MRBhKVRR0sJkr0M0QCH7yOLf9fhQ==", "dev": true, "requires": { "readable-stream": "^2.1.4" @@ -16875,6 +19736,8 @@ "dependencies": { "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, "requires": { "core-util-is": "~1.0.0", @@ -16888,10 +19751,14 @@ }, "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 }, "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, "requires": { "safe-buffer": "~5.1.0" @@ -16901,12 +19768,16 @@ }, "string_decoder": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "requires": { "safe-buffer": "~5.2.0" } }, "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, "requires": { "char-regex": "^1.0.2", @@ -16915,6 +19786,8 @@ }, "string-width": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -16924,10 +19797,14 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "strip-ansi": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -16937,6 +19814,8 @@ }, "string.prototype.trimend": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -16945,6 +19824,8 @@ }, "string.prototype.trimstart": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -16953,24 +19834,34 @@ }, "strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { "ansi-regex": "^5.0.1" } }, "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 }, "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 }, "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 }, "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, "requires": { "has-flag": "^3.0.0" @@ -16978,6 +19869,8 @@ }, "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, "requires": { "has-flag": "^4.0.0", @@ -16986,10 +19879,14 @@ "dependencies": { "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 }, "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, "requires": { "has-flag": "^4.0.0" @@ -16999,14 +19896,20 @@ }, "supports-preserve-symlinks-flag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, "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 }, "tar-fs": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "dev": true, "requires": { "chownr": "^1.1.1", @@ -17017,6 +19920,8 @@ }, "tar-stream": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "requires": { "bl": "^4.0.3", @@ -17028,6 +19933,8 @@ }, "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, "requires": { "ansi-escapes": "^4.2.1", @@ -17036,6 +19943,8 @@ }, "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, "requires": { "@istanbuljs/schema": "^0.1.2", @@ -17045,10 +19954,14 @@ }, "text-table": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "threads": { "version": "1.7.0", + "resolved": "https://registry.npmjs.org/threads/-/threads-1.7.0.tgz", + "integrity": "sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ==", "requires": { "callsites": "^3.1.0", "debug": "^4.2.0", @@ -17059,16 +19972,24 @@ }, "throat": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", "dev": true }, "timeout-refresh": { - "version": "1.0.3" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-1.0.3.tgz", + "integrity": "sha512-Mz0CX4vBGM5lj8ttbIFt7o4ZMxk/9rgudJRh76EvB7xXZMur7T/cjRiH2w4Fmkq0zxf2QpM8IFvOSRn8FEu3gA==" }, "tiny-inflate": { - "version": "1.0.3" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" }, "tiny-worker": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tiny-worker/-/tiny-worker-2.3.0.tgz", + "integrity": "sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==", "optional": true, "requires": { "esm": "^3.2.25" @@ -17076,14 +19997,20 @@ }, "tmpl": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, "to-fast-properties": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true }, "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, "requires": { "is-number": "^7.0.0" @@ -17091,6 +20018,8 @@ }, "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, "requires": { "psl": "^1.1.33", @@ -17100,22 +20029,30 @@ "dependencies": { "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 } } }, "tr46": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dev": true, "requires": { "punycode": "^2.1.1" } }, "ts-custom-error": { - "version": "3.2.0" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.2.0.tgz", + "integrity": "sha512-cBvC2QjtvJ9JfWLvstVnI45Y46Y5dMxIaG1TDMGAD/R87hpvqFL+7LhvUDhnRCfOnx/xitollFWWvUKKKhbN0A==" }, "ts-jest": { - "version": "27.1.4", + "version": "27.1.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.5.tgz", + "integrity": "sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA==", "dev": true, "requires": { "bs-logger": "0.x", @@ -17130,6 +20067,8 @@ "dependencies": { "semver": { "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -17138,10 +20077,12 @@ } }, "ts-node": { - "version": "10.7.0", + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz", + "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==", "dev": true, "requires": { - "@cspotcode/source-map-support": "0.7.0", + "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", @@ -17152,18 +20093,22 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "dependencies": { "acorn-walk": { "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true } } }, "tsconfig-paths": { "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, "requires": { "@types/json5": "^0.0.29", @@ -17174,6 +20119,8 @@ "dependencies": { "json5": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -17181,15 +20128,21 @@ }, "strip-bom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true } } }, "tslib": { - "version": "2.4.0" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "tsutils": { "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "requires": { "tslib": "^1.8.1" @@ -17197,12 +20150,16 @@ "dependencies": { "tslib": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true } } }, "tunnel-agent": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "requires": { "safe-buffer": "^5.0.1" @@ -17210,6 +20167,8 @@ }, "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, "requires": { "prelude-ls": "^1.2.1" @@ -17217,39 +20176,64 @@ }, "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 }, "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 }, "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, "requires": { "is-typedarray": "^1.0.0" } }, "typedoc": { - "version": "0.22.15", + "version": "0.22.17", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.17.tgz", + "integrity": "sha512-h6+uXHVVCPDaANzjwzdsj9aePBjZiBTpiMpBBeyh1zcN2odVsDCNajz8zyKnixF93HJeGpl34j/70yoEE5BfNg==", "dev": true, "requires": { - "glob": "^7.2.0", + "glob": "^8.0.3", "lunr": "^2.3.9", - "marked": "^4.0.12", - "minimatch": "^5.0.1", + "marked": "^4.0.16", + "minimatch": "^5.1.0", "shiki": "^0.10.1" }, "dependencies": { "brace-expansion": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { "balanced-match": "^1.0.0" } }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, "minimatch": { - "version": "5.0.1", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -17258,7 +20242,9 @@ } }, "typescript": { - "version": "4.6.4", + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", + "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", "dev": true }, "typescript-cached-transpile": { @@ -17313,12 +20299,16 @@ } }, "uglify-js": { - "version": "3.15.5", + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.0.tgz", + "integrity": "sha512-FEikl6bR30n0T3amyBh3LoiBdqHRy/f4H80+My34HOesOKyHfOsxAPAxOoqC0JUnC1amnO0IwkYC3sko51caSw==", "dev": true, "optional": true }, "unbox-primitive": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "requires": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -17328,10 +20318,14 @@ }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true }, "unicode-match-property-ecmascript": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "requires": { "unicode-canonical-property-names-ecmascript": "^2.0.0", @@ -17340,48 +20334,68 @@ }, "unicode-match-property-value-ecmascript": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", "dev": true }, "unicode-property-aliases-ecmascript": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true }, "unicode-trie": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", "requires": { "pako": "^0.2.5", "tiny-inflate": "^1.0.0" }, "dependencies": { "pako": { - "version": "0.2.9" + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" } } }, "universalify": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true }, "unordered-set": { - "version": "2.0.1" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", + "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==" }, "uri-js": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "requires": { "punycode": "^2.1.0" } }, "util-callbackify": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util-callbackify/-/util-callbackify-1.0.0.tgz", + "integrity": "sha512-5vEPPSM6DCHlCpq9FZryeIkY5FQMUqXLUz4yHtU369Z/abWUVdgInPVeINjWJV3Bk9DZhCr+JzGarEByPLsxBQ==", "requires": { "object.getownpropertydescriptors": "^2.0.3" } }, "util-deprecate": { - "version": "1.0.2" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "utp-native": { "version": "2.5.3", + "resolved": "https://registry.npmjs.org/utp-native/-/utp-native-2.5.3.tgz", + "integrity": "sha512-sWTrWYXPhhWJh+cS2baPzhaZc89zwlWCfwSthUjGhLkZztyPhcQllo+XVVCbNGi7dhyRlxkWxN4NKU6FbA9Y8w==", "requires": { "napi-macros": "^2.0.0", "node-gyp-build": "^4.2.0", @@ -17391,18 +20405,26 @@ } }, "uuid": { - "version": "8.3.2" + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-compile-cache": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, "v8-compile-cache-lib": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, "v8-to-istanbul": { "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -17411,21 +20433,29 @@ }, "dependencies": { "source-map": { - "version": "0.7.3", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true } } }, "vscode-oniguruma": { "version": "1.6.2", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", + "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", "dev": true }, "vscode-textmate": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", + "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", "dev": true }, "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, "requires": { "browser-process-hrtime": "^1.0.0" @@ -17433,6 +20463,8 @@ }, "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, "requires": { "xml-name-validator": "^3.0.0" @@ -17440,6 +20472,8 @@ }, "walker": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, "requires": { "makeerror": "1.0.12" @@ -17447,10 +20481,14 @@ }, "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 }, "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, "requires": { "iconv-lite": "0.4.24" @@ -17458,10 +20496,14 @@ }, "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 }, "whatwg-url": { "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, "requires": { "lodash": "^4.7.0", @@ -17471,12 +20513,16 @@ }, "which": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "requires": { "isexe": "^2.0.0" } }, "which-boxed-primitive": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "requires": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -17487,6 +20533,8 @@ }, "wide-align": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, "requires": { "string-width": "^1.0.2 || 2 || 3 || 4" @@ -17494,14 +20542,20 @@ }, "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 }, "wordwrap": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, "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==", "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -17510,24 +20564,34 @@ "dependencies": { "ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { "color-convert": "^2.0.1" } }, "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==", "requires": { "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.4" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "is-fullwidth-code-point": { - "version": "3.0.0" + "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==" }, "string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -17537,10 +20601,14 @@ } }, "wrappy": { - "version": "1.0.2" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "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, "requires": { "imurmurhash": "^0.1.4", @@ -17550,32 +20618,44 @@ } }, "ws": { - "version": "7.5.7", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.8.tgz", + "integrity": "sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==", "dev": true, "requires": {} }, "xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==" }, "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 }, "xmlchars": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, "y18n": { - "version": "5.0.8" + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, "yallist": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "yargs": { "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -17587,10 +20667,14 @@ }, "dependencies": { "is-fullwidth-code-point": { - "version": "3.0.0" + "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==" }, "string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -17600,10 +20684,14 @@ } }, "yargs-parser": { - "version": "20.2.9" + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" }, "yn": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true } } diff --git a/package.json b/package.json index 83a5806a2..da5c72593 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "jest-mock-props": "^1.9.0", "mocked-env": "^1.3.5", "nexpect": "^0.6.0", - "node-gyp-build": "4.4.0", + "node-gyp-build": "^4.4.0", "pkg": "5.6.0", "prettier": "^2.6.2", "shx": "^0.3.4", diff --git a/utils.nix b/utils.nix index 31f0b1055..811108c07 100644 --- a/utils.nix +++ b/utils.nix @@ -17,8 +17,8 @@ rec { node2nixSrc = fetchFromGitHub { owner = "svanderburg"; repo = "node2nix"; - rev = "68f5735f9a56737e3fedceb182705985e3ab8799"; - sha256 = "1f791vikig65ly5vcw6zjd0nv2qb8l5w5lr3xy343iq6746s1bil"; + rev = "9377fe4a45274fab0c7faba4f7c43ffae8421dd2"; + sha256 = "15zip9w9hivd1p6k82hh4zba02jj6q0g2f1i9b7rrn2hs70qdlai"; }; node2nix = (import "${node2nixSrc}/release.nix" {}).package.x86_64-linux; node2nixDrv = dev: runCommandNoCC "node2nix" {} '' From 60f536335439745153be6be15062564c60d9094e Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 15 Jun 2022 14:50:54 +1000 Subject: [PATCH 115/137] ci: using `--runInBand` for jest tests --- scripts/test-pipelines.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/test-pipelines.sh b/scripts/test-pipelines.sh index 4864af4fb..b82ab5746 100755 --- a/scripts/test-pipelines.sh +++ b/scripts/test-pipelines.sh @@ -60,7 +60,7 @@ check:test $test_dir: - > nix-shell --run ' npm run build --verbose; - npm test -- --ci ${test_files[@]}; + npm test -- --ci --runInBand ${test_files[@]}; ' artifacts: when: always @@ -81,7 +81,7 @@ check:test index: - > nix-shell --run ' npm run build --verbose; - npm test -- --ci ${test_files[@]}; + npm test -- --ci --runInBand ${test_files[@]}; ' artifacts: when: always From cb6be2af18d1d23ccb9c2a056b9cd60cbdd2e6d5 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 15 Jun 2022 16:08:02 +1000 Subject: [PATCH 116/137] tests: increasing timeouts for bin tests in CI/CD --- tests/bin/agent/start.test.ts | 12 ++++++------ tests/bin/agent/stop.test.ts | 4 ++-- tests/bin/bootstrap.test.ts | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/bin/agent/start.test.ts b/tests/bin/agent/start.test.ts index 6b419fde0..d4a546239 100644 --- a/tests/bin/agent/start.test.ts +++ b/tests/bin/agent/start.test.ts @@ -197,7 +197,7 @@ describe('start', () => { const statusInfo2 = await status.waitFor('DEAD'); expect(statusInfo2.status).toBe('DEAD'); }, - global.defaultTimeout * 2, + global.defaultTimeout * 3, ); test( 'concurrent starts results in 1 success', @@ -295,7 +295,7 @@ describe('start', () => { expect(signal).toBe('SIGQUIT'); } }, - global.defaultTimeout * 2, + global.defaultTimeout * 3, ); test( 'concurrent with bootstrap results in 1 success', @@ -387,7 +387,7 @@ describe('start', () => { expect(signal).toBe('SIGTERM'); } }, - global.defaultTimeout * 2, + global.defaultTimeout * 3, ); test( 'start with existing state', @@ -467,7 +467,7 @@ describe('start', () => { const statusInfo = (await status.readStatus())!; expect(statusInfo.status).toBe('DEAD'); }, - global.defaultTimeout * 2, + global.defaultTimeout * 3, ); test( 'start when interrupted, requires fresh on next start', @@ -577,7 +577,7 @@ describe('start', () => { const statusInfo = (await status.readStatus())!; expect(statusInfo.status).toBe('DEAD'); }, - global.defaultTimeout * 2, + global.defaultTimeout * 3, ); test( 'start from recovery code', @@ -711,7 +711,7 @@ describe('start', () => { agentProcess4.kill('SIGTERM'); await testBinUtils.processExit(agentProcess4); }, - global.defaultTimeout * 3, + global.defaultTimeout * 4, ); test( 'start with network configuration', diff --git a/tests/bin/agent/stop.test.ts b/tests/bin/agent/stop.test.ts index b56f9b42c..6719eee35 100644 --- a/tests/bin/agent/stop.test.ts +++ b/tests/bin/agent/stop.test.ts @@ -157,7 +157,7 @@ describe('stop', () => { expect(agentStop3.exitCode).toBe(0); expect(agentStop4.exitCode).toBe(0); }, - global.defaultTimeout * 2, + global.defaultTimeout * 3, ); test( 'stopping starting agent results in error', @@ -217,7 +217,7 @@ describe('stop', () => { ); await status.waitFor('DEAD'); }, - global.defaultTimeout * 2, + global.defaultTimeout * 3, ); test( 'stopping while unauthenticated does not stop', diff --git a/tests/bin/bootstrap.test.ts b/tests/bin/bootstrap.test.ts index 409afc4f7..d43e018a3 100644 --- a/tests/bin/bootstrap.test.ts +++ b/tests/bin/bootstrap.test.ts @@ -183,7 +183,7 @@ describe('bootstrap', () => { expect(exitCode2).toBe(0); } }, - global.defaultTimeout * 2, + global.defaultTimeout * 3, ); test( 'bootstrap when interrupted, requires fresh on next bootstrap', @@ -256,6 +256,6 @@ describe('bootstrap', () => { recoveryCode.split(' ').length === 24, ).toBe(true); }, - global.defaultTimeout * 2, + global.defaultTimeout * 3, ); }); From 6d43d477077a3612091b45606fcdcebdd71289e5 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 15 Jun 2022 16:24:15 +1000 Subject: [PATCH 117/137] tests: increasing timeouts for bin tests in CI/CD --- tests/bin/agent/start.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bin/agent/start.test.ts b/tests/bin/agent/start.test.ts index d4a546239..3be0e4694 100644 --- a/tests/bin/agent/start.test.ts +++ b/tests/bin/agent/start.test.ts @@ -711,7 +711,7 @@ describe('start', () => { agentProcess4.kill('SIGTERM'); await testBinUtils.processExit(agentProcess4); }, - global.defaultTimeout * 4, + global.defaultTimeout * 5, ); test( 'start with network configuration', From 8c191cac6ded40f4dfb14ed27771b0d019c1ea63 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 17 Jun 2022 10:13:38 +1000 Subject: [PATCH 118/137] fix: issue with ts-node causing increased test times in bin tests `ts-node` needs to be fixed to 10.7.0 for now, as 10.8.1 causes many bin tests (those using `pkSpawn`) to timeout. Also reduced test timeouts back to what they originally were now that the timeout problem is resolved. --- package-lock.json | 75 ++++++++++++++++------------------- package.json | 2 +- tests/bin/agent/start.test.ts | 12 +++--- tests/bin/agent/stop.test.ts | 4 +- tests/bin/bootstrap.test.ts | 4 +- 5 files changed, 45 insertions(+), 52 deletions(-) diff --git a/package-lock.json b/package-lock.json index f7dc2510e..acdf5c67a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -78,7 +78,7 @@ "prettier": "^2.6.2", "shx": "^0.3.4", "ts-jest": "^27.0.5", - "ts-node": "^10.4.0", + "ts-node": "10.7.0", "tsconfig-paths": "^3.9.0", "typedoc": "^0.22.15", "typescript": "^4.5.2", @@ -1715,26 +1715,25 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "node_modules/@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, "engines": { - "node": ">=12" + "node": ">= 12" } }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", + "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@cspotcode/source-map-consumer": "0.8.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/@eslint/eslintrc": { @@ -11083,12 +11082,12 @@ } }, "node_modules/ts-node": { - "version": "10.8.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz", - "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==", + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", + "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", "dev": true, "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", + "@cspotcode/source-map-support": "0.7.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", @@ -11099,7 +11098,7 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", + "v8-compile-cache-lib": "^3.0.0", "yn": "3.1.1" }, "bin": { @@ -13020,25 +13019,19 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true + }, "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", + "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", "dev": true, "requires": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } + "@cspotcode/source-map-consumer": "0.8.0" } }, "@eslint/eslintrc": { @@ -20077,12 +20070,12 @@ } }, "ts-node": { - "version": "10.8.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz", - "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==", + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", + "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", "dev": true, "requires": { - "@cspotcode/source-map-support": "^0.8.0", + "@cspotcode/source-map-support": "0.7.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", @@ -20093,7 +20086,7 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", + "v8-compile-cache-lib": "^3.0.0", "yn": "3.1.1" }, "dependencies": { diff --git a/package.json b/package.json index da5c72593..e5d730066 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "prettier": "^2.6.2", "shx": "^0.3.4", "ts-jest": "^27.0.5", - "ts-node": "^10.4.0", + "ts-node": "10.7.0", "tsconfig-paths": "^3.9.0", "typedoc": "^0.22.15", "typescript": "^4.5.2", diff --git a/tests/bin/agent/start.test.ts b/tests/bin/agent/start.test.ts index 3be0e4694..6b419fde0 100644 --- a/tests/bin/agent/start.test.ts +++ b/tests/bin/agent/start.test.ts @@ -197,7 +197,7 @@ describe('start', () => { const statusInfo2 = await status.waitFor('DEAD'); expect(statusInfo2.status).toBe('DEAD'); }, - global.defaultTimeout * 3, + global.defaultTimeout * 2, ); test( 'concurrent starts results in 1 success', @@ -295,7 +295,7 @@ describe('start', () => { expect(signal).toBe('SIGQUIT'); } }, - global.defaultTimeout * 3, + global.defaultTimeout * 2, ); test( 'concurrent with bootstrap results in 1 success', @@ -387,7 +387,7 @@ describe('start', () => { expect(signal).toBe('SIGTERM'); } }, - global.defaultTimeout * 3, + global.defaultTimeout * 2, ); test( 'start with existing state', @@ -467,7 +467,7 @@ describe('start', () => { const statusInfo = (await status.readStatus())!; expect(statusInfo.status).toBe('DEAD'); }, - global.defaultTimeout * 3, + global.defaultTimeout * 2, ); test( 'start when interrupted, requires fresh on next start', @@ -577,7 +577,7 @@ describe('start', () => { const statusInfo = (await status.readStatus())!; expect(statusInfo.status).toBe('DEAD'); }, - global.defaultTimeout * 3, + global.defaultTimeout * 2, ); test( 'start from recovery code', @@ -711,7 +711,7 @@ describe('start', () => { agentProcess4.kill('SIGTERM'); await testBinUtils.processExit(agentProcess4); }, - global.defaultTimeout * 5, + global.defaultTimeout * 3, ); test( 'start with network configuration', diff --git a/tests/bin/agent/stop.test.ts b/tests/bin/agent/stop.test.ts index 6719eee35..b56f9b42c 100644 --- a/tests/bin/agent/stop.test.ts +++ b/tests/bin/agent/stop.test.ts @@ -157,7 +157,7 @@ describe('stop', () => { expect(agentStop3.exitCode).toBe(0); expect(agentStop4.exitCode).toBe(0); }, - global.defaultTimeout * 3, + global.defaultTimeout * 2, ); test( 'stopping starting agent results in error', @@ -217,7 +217,7 @@ describe('stop', () => { ); await status.waitFor('DEAD'); }, - global.defaultTimeout * 3, + global.defaultTimeout * 2, ); test( 'stopping while unauthenticated does not stop', diff --git a/tests/bin/bootstrap.test.ts b/tests/bin/bootstrap.test.ts index d43e018a3..409afc4f7 100644 --- a/tests/bin/bootstrap.test.ts +++ b/tests/bin/bootstrap.test.ts @@ -183,7 +183,7 @@ describe('bootstrap', () => { expect(exitCode2).toBe(0); } }, - global.defaultTimeout * 3, + global.defaultTimeout * 2, ); test( 'bootstrap when interrupted, requires fresh on next bootstrap', @@ -256,6 +256,6 @@ describe('bootstrap', () => { recoveryCode.split(' ').length === 24, ).toBe(true); }, - global.defaultTimeout * 3, + global.defaultTimeout * 2, ); }); From b1eabebee8ea38e6bf13b6a95c7e3e83371c1094 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 22 Jun 2022 14:16:43 +1000 Subject: [PATCH 119/137] fix: expanded tests and small fix for `parseSeedNodes` Related #324 --- src/validation/utils.ts | 14 +++---- tests/validation/utils.nodes.test.ts | 55 +++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/validation/utils.ts b/src/validation/utils.ts index 020c1f51a..8197348a9 100644 --- a/src/validation/utils.ts +++ b/src/validation/utils.ts @@ -228,14 +228,14 @@ function parseSeedNodes(data: any): [SeedNodes, boolean] { } let seedNodeUrl: URL; try { - seedNodeUrl = new URL(`pk://${seedNodeString}`); + const seedNodeStringProtocol = /^pk:\/\//.test(seedNodeString) + ? seedNodeString + : `pk://${seedNodeString}`; + seedNodeUrl = new URL(seedNodeStringProtocol); } catch (e) { - if (e instanceof TypeError) { - throw new validationErrors.ErrorParse( - 'Seed nodes must be of format `nodeId@host:port;...`', - ); - } - throw e; + throw new validationErrors.ErrorParse( + 'Seed nodes must be of format `nodeId@host:port;...`', + ); } const nodeIdEncoded = seedNodeUrl.username; // Remove square braces for IPv6 diff --git a/tests/validation/utils.nodes.test.ts b/tests/validation/utils.nodes.test.ts index 8374312ef..9cb301d7b 100644 --- a/tests/validation/utils.nodes.test.ts +++ b/tests/validation/utils.nodes.test.ts @@ -35,6 +35,27 @@ describe('nodes validationUtils', () => { }); expect(parsed[1]).toBeFalsy(); }); + test('parseSeedNodes - valid nodes optionally have pk://', () => { + const rawSeedNodes = + `pk://${nodeIdEncoded1}@${hostname}:${port1};` + + `pk://${nodeIdEncoded2}@${hostIPv4}:${port2};` + + `pk://${nodeIdEncoded3}@${hostIPv6}:${port3};`; + const parsed = validationUtils.parseSeedNodes(rawSeedNodes); + const seeds = parsed[0]; + expect(seeds[nodeIdEncoded1]).toStrictEqual({ + host: hostname, + port: port1, + }); + expect(seeds[nodeIdEncoded2]).toStrictEqual({ + host: hostIPv4, + port: port2, + }); + expect(seeds[nodeIdEncoded3]).toStrictEqual({ + host: hostIPv6.replace(/\[|\]/g, ''), + port: port3, + }); + expect(parsed[1]).toBeFalsy(); + }); test('parseSeedNodes - invalid node ID', () => { const rawSeedNodes = `INVALIDNODEID@${hostname}:${port1}`; expect(() => validationUtils.parseSeedNodes(rawSeedNodes)).toThrow( @@ -47,6 +68,36 @@ describe('nodes validationUtils', () => { validationErrors.ErrorParse, ); }); - test.todo('parseSeedNodes - invalid port'); - test.todo('parseSeedNodes - invalid structure'); + test('parseSeedNodes - invalid URL', () => { + expect(() => + validationUtils.parseSeedNodes('thisisinvalid!@#$%^&*()'), + ).toThrow(validationErrors.ErrorParse); + }); + test('parseSeedNodes - invalid port', async () => { + expect(() => + validationUtils.parseSeedNodes(`${nodeIdEncoded1}@$invalidHost:-55555`), + ).toThrow(validationErrors.ErrorParse); + expect(() => + validationUtils.parseSeedNodes( + `${nodeIdEncoded1}@$invalidHost:999999999`, + ), + ).toThrow(validationErrors.ErrorParse); + }); + test('parseSeedNodes - invalid structure', async () => { + expect(() => + validationUtils.parseSeedNodes( + `${nodeIdEncoded1}!#$%^&*()@$invalidHost:${port1}`, + ), + ).toThrow(validationErrors.ErrorParse); + expect(() => + validationUtils.parseSeedNodes( + `pk:/${nodeIdEncoded1}@$invalidHost:${port1}`, + ), + ).toThrow(validationErrors.ErrorParse); + expect(() => + validationUtils.parseSeedNodes( + `asdpk://${nodeIdEncoded1}@$invalidHost:${port1}`, + ), + ).toThrow(validationErrors.ErrorParse); + }); }); From 7fd16a6983d88188311d558d53e36628d8aee010 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 23 Jun 2022 12:53:19 +1000 Subject: [PATCH 120/137] fix: added `tslib` to `pkg` assets This is to fix a problem where `tslib` was not getting included during the packaging process resulting in an error. --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index e5d730066..acffa9aa7 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,8 @@ "pkg": { "assets": [ "node_modules/jose/**/*", - "dist/**/*.json" + "dist/**/*.json", + "node_modules/tslib/**/*.js" ], "scripts": [ "dist/workers/polykeyWorker.js", From 89beb41426ee443f6b7cea27f36ba21a0b628186 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 23 Jun 2022 17:11:17 +1000 Subject: [PATCH 121/137] build: fix for `build:macos` job Related https://github.com/MatrixAI/js-async-locks/pull/10#issuecomment-1161934020 --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9742adbca..febe7602f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -196,6 +196,7 @@ build:macos: HOMEBREW_NO_INSTALL_UPGRADE: "true" HOMEBREW_NO_INSTALL_CLEANUP: "true" before_script: + - eval "$(brew shellenv)" - brew install node@16 - brew link --overwrite node@16 - hash -r From 18437cef25e7f62168925a204185757263eb7f60 Mon Sep 17 00:00:00 2001 From: Joshua Karp Date: Tue, 15 Feb 2022 13:20:47 +1100 Subject: [PATCH 122/137] test: NAT Traversal testing utils and tests --- shell.nix | 1 + tests/nat/endpointDependentNAT.test.ts | 268 +++++ tests/nat/endpointIndependentNAT.test.ts | 372 +++++++ tests/nat/noNAT.test.ts | 239 +++++ tests/nat/utils.ts | 1164 ++++++++++++++++++++++ 5 files changed, 2044 insertions(+) create mode 100644 tests/nat/endpointDependentNAT.test.ts create mode 100644 tests/nat/endpointIndependentNAT.test.ts create mode 100644 tests/nat/noNAT.test.ts create mode 100644 tests/nat/utils.ts diff --git a/shell.nix b/shell.nix index 961a13c8a..37475b20e 100644 --- a/shell.nix +++ b/shell.nix @@ -10,6 +10,7 @@ in utils.node2nix grpc-tools grpcurl + iptables-legacy ]; PKG_CACHE_PATH = utils.pkgCachePath; PKG_IGNORE_TAG = 1; diff --git a/tests/nat/endpointDependentNAT.test.ts b/tests/nat/endpointDependentNAT.test.ts new file mode 100644 index 000000000..113c0004a --- /dev/null +++ b/tests/nat/endpointDependentNAT.test.ts @@ -0,0 +1,268 @@ +import os from 'os'; +import path from 'path'; +import fs from 'fs'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import * as testNatUtils from './utils'; + +describe('endpoint dependent NAT traversal', () => { + const logger = new Logger('EDM NAT test', LogLevel.WARN, [ + new StreamHandler(), + ]); + let dataDir: string; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + }); + afterEach(async () => { + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test( + 'Node1 behind EDM NAT connects to Node2', + async () => { + const { + userPid, + agent1Pid, + password, + dataDir, + agent1NodePath, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('edm', 'dmz', logger); + // Since node2 is not behind a NAT can directly add its details + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + const { exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 connects to Node2 behind EDM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent1Host, + agent1ProxyPort, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('dmz', 'edmSimple', logger); + await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + // If we try to ping Agent 2 it will fail + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + // But Agent 2 can ping Agent 1 because Agent 1 is not behind a NAT + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + // Can now ping Agent 2 (it will be expecting a response) + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 behind EDM NAT cannot connect to Node2 behind EDM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent2NodeId, + tearDownNAT, + } = await testNatUtils.setupNATWithSeedNode( + 'edmSimple', + 'edmSimple', + logger, + ); + // Contact details are retrieved from the seed node, but cannot be used + // since port mapping changes between targets in EDM mapping + // Node 2 -> Node 1 ping should fail (Node 1 behind NAT) + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + // Node 1 -> Node 2 ping should also fail + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 behind EDM NAT cannot connect to Node2 behind EIM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent2NodeId, + tearDownNAT, + } = await testNatUtils.setupNATWithSeedNode('edmSimple', 'eim', logger); + // Since one of the nodes uses EDM NAT we cannot punch through + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json', '-vv'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json', '-vv'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); +}); diff --git a/tests/nat/endpointIndependentNAT.test.ts b/tests/nat/endpointIndependentNAT.test.ts new file mode 100644 index 000000000..357db3d17 --- /dev/null +++ b/tests/nat/endpointIndependentNAT.test.ts @@ -0,0 +1,372 @@ +import os from 'os'; +import path from 'path'; +import fs from 'fs'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import * as testNatUtils from './utils'; + +describe('endpoint independent NAT traversal', () => { + const logger = new Logger('EIM NAT test', LogLevel.WARN, [ + new StreamHandler(), + ]); + let dataDir: string; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + }); + afterEach(async () => { + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test( + 'Node1 behind EIM NAT connects to Node2', + async () => { + const { + userPid, + agent1Pid, + password, + dataDir, + agent1NodePath, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('eim', 'dmz', logger); + // Since node2 is not behind a NAT can directly add its details + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + const { exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 connects to Node2 behind EIM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent1Host, + agent1ProxyPort, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('dmz', 'eim', logger); + await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + // If we try to ping Agent 2 it will fail + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + // But Agent 2 can ping Agent 1 because Agent 1 is not behind a NAT + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + // Can now ping Agent 2 (it will be expecting a response) + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 behind EIM NAT connects to Node2 behind EIM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent1Host, + agent1ProxyPort, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('dmz', 'eim', logger); + await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + // If we try to ping Agent 2 it will fail + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + // But Agent 2 can ping Agent 1 because it's expecting a response now + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + // Can now ping Agent 2 (it will be expecting a response too) + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 behind EIM NAT connects to Node2 behind EIM NAT via seed node', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent2NodeId, + tearDownNAT, + } = await testNatUtils.setupNATWithSeedNode('eim', 'eim', logger); + // Contact details can be retrieved from the seed node so don't need to + // add manually + // If we try to ping Agent 2 it will fail + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + // But Agent 2 can ping Agent 1 now because it's expecting a response + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + // Can now ping Agent 2 (it will also be expecting a response) + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 behind EIM NAT cannot connect to Node2 behind EDM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent2NodeId, + tearDownNAT, + } = await testNatUtils.setupNATWithSeedNode('eim', 'edmSimple', logger); + // Since one of the nodes uses EDM NAT we cannot punch through + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json', '-vv'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json', '-vv'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); +}); diff --git a/tests/nat/noNAT.test.ts b/tests/nat/noNAT.test.ts new file mode 100644 index 000000000..bd8a85623 --- /dev/null +++ b/tests/nat/noNAT.test.ts @@ -0,0 +1,239 @@ +import os from 'os'; +import path from 'path'; +import fs from 'fs'; +import readline from 'readline'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import Status from '@/status/Status'; +import config from '@/config'; +import * as testNatUtils from './utils'; +import * as testBinUtils from '../bin/utils'; + +describe('no NAT', () => { + const logger = new Logger('no NAT test', LogLevel.WARN, [ + new StreamHandler(), + ]); + let dataDir: string; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + }); + afterEach(async () => { + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test( + 'can create an agent in a namespace', + async () => { + const password = 'abc123'; + const usrns = testNatUtils.createUserNamespace(); + const netns = testNatUtils.createNetworkNamespace(usrns.pid!); + const agentProcess = await testNatUtils.pkSpawnNs( + usrns.pid!, + netns.pid!, + [ + 'agent', + 'start', + '--node-path', + path.join(dataDir, 'polykey'), + '--root-key-pair-bits', + '1024', + '--client-host', + '127.0.0.1', + '--proxy-host', + '127.0.0.1', + '--workers', + '0', + '--verbose', + '--format', + 'json', + ], + { + PK_PASSWORD: password, + }, + dataDir, + logger.getChild('agentProcess'), + ); + const rlOut = readline.createInterface(agentProcess.stdout!); + const stdout = await new Promise((resolve, reject) => { + rlOut.once('line', resolve); + rlOut.once('close', reject); + }); + const statusLiveData = JSON.parse(stdout); + expect(statusLiveData).toMatchObject({ + pid: agentProcess.pid, + nodeId: expect.any(String), + clientHost: expect.any(String), + clientPort: expect.any(Number), + agentHost: expect.any(String), + agentPort: expect.any(Number), + forwardHost: expect.any(String), + forwardPort: expect.any(Number), + proxyHost: expect.any(String), + proxyPort: expect.any(Number), + recoveryCode: expect.any(String), + }); + expect( + statusLiveData.recoveryCode.split(' ').length === 12 || + statusLiveData.recoveryCode.split(' ').length === 24, + ).toBe(true); + agentProcess.kill('SIGTERM'); + let exitCode, signal; + [exitCode, signal] = await testBinUtils.processExit(agentProcess); + expect(exitCode).toBe(null); + expect(signal).toBe('SIGTERM'); + // Check for graceful exit + const status = new Status({ + statusPath: path.join(dataDir, 'polykey', config.defaults.statusBase), + statusLockPath: path.join( + dataDir, + 'polykey', + config.defaults.statusLockBase, + ), + fs, + logger, + }); + const statusInfo = (await status.readStatus())!; + expect(statusInfo.status).toBe('DEAD'); + netns.kill('SIGTERM'); + [exitCode, signal] = await testBinUtils.processExit(netns); + expect(exitCode).toBe(null); + expect(signal).toBe('SIGTERM'); + usrns.kill('SIGTERM'); + [exitCode, signal] = await testBinUtils.processExit(usrns); + expect(exitCode).toBe(null); + expect(signal).toBe('SIGTERM'); + }, + global.defaultTimeout * 2, + ); + test( + 'agents in different namespaces can ping each other', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent1Host, + agent1ProxyPort, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('dmz', 'dmz', logger); + // Since neither node is behind a NAT can directly add eachother's + // details using pk nodes add + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json', '--verbose'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json', '--verbose'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'agents in different namespaces can ping each other via seed node', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent2NodeId, + tearDownNAT, + } = await testNatUtils.setupNATWithSeedNode('dmz', 'dmz', logger); + // Should be able to ping straight away using the details from the + // seed node + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json', '--verbose'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json', '--verbose'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); +}); diff --git a/tests/nat/utils.ts b/tests/nat/utils.ts new file mode 100644 index 000000000..95125adf8 --- /dev/null +++ b/tests/nat/utils.ts @@ -0,0 +1,1164 @@ +import type { ChildProcess } from 'child_process'; +import os from 'os'; +import fs from 'fs'; +import path from 'path'; +import process from 'process'; +import child_process from 'child_process'; +import readline from 'readline'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import * as testBinUtils from '../bin/utils'; + +type NATType = 'eim' | 'edm' | 'dmz' | 'edmSimple'; + +// Constants for all util functions +// Veth pairs (ends) +const agent1Host = 'agent1'; +const agent2Host = 'agent2'; +const agent1RouterHostInt = 'router1-int'; +const agent1RouterHostExt = 'router1-ext'; +const agent2RouterHostInt = 'router2-int'; +const agent2RouterHostExt = 'router2-ext'; +const router1SeedHost = 'router1-seed'; +const router2SeedHost = 'router2-seed'; +const seedRouter1Host = 'seed-router1'; +const seedRouter2Host = 'seed-router2'; +// Subnets +const agent1HostIp = '10.0.0.2'; +const agent2HostIp = '10.0.0.2'; +const agent1RouterHostIntIp = '10.0.0.1'; +const agent2RouterHostIntIp = '10.0.0.1'; +const agent1RouterHostExtIp = '192.168.0.1'; +const agent2RouterHostExtIp = '192.168.0.2'; +const router1SeedHostIp = '192.168.0.1'; +const seedHostIp = '192.168.0.3'; +const router2SeedHostIp = '192.168.0.2'; +// Subnet mask +const subnetMask = '/24'; +// Ports +const agent1Port = '55551'; +const agent2Port = '55552'; +const mappedPort = '55555'; + +/** + * Formats the command to enter a namespace to run a process inside it + */ +const nsenter = (usrnsPid: number, netnsPid: number) => { + return `nsenter --target ${usrnsPid} --user --preserve-credentials `.concat( + `nsenter --target ${netnsPid} --net `, + ); +}; + +/** + * Create a user namespace from which network namespaces can be created without + * requiring sudo + */ +function createUserNamespace(): ChildProcess { + return child_process.spawn('unshare', ['--user', '--map-root-user'], { + shell: true, + }); +} + +/** + * Create a network namespace inside a user namespace + */ +function createNetworkNamespace(usrnsPid: number): ChildProcess { + return child_process.spawn( + 'nsenter', + [ + '--target', + usrnsPid.toString(), + '--user', + '--preserve-credentials', + 'unshare', + '--net', + ], + { shell: true }, + ); +} + +/** + * Set up four network namespaces to allow communication between two agents + * each behind a router + * Brings up loopback interfaces, creates and brings up a veth pair + * between each pair of adjacent namespaces, and adds default routing to allow + * cross-communication + */ +function setupNetworkNamespaceInterfaces( + usrnsPid: number, + agent1NetnsPid: number, + router1NetnsPid: number, + router2NetnsPid: number, + agent2NetnsPid: number, +) { + // Bring up loopback + child_process.exec(nsenter(usrnsPid, agent1NetnsPid) + `ip link set lo up`); + child_process.exec(nsenter(usrnsPid, router1NetnsPid) + `ip link set lo up`); + child_process.exec(nsenter(usrnsPid, router2NetnsPid) + `ip link set lo up`); + child_process.exec(nsenter(usrnsPid, agent2NetnsPid) + `ip link set lo up`); + // Create veth pair to link the namespaces + child_process.exec( + nsenter(usrnsPid, agent1NetnsPid) + + `ip link add ${agent1Host} type veth peer name ${agent1RouterHostInt}`, + ); + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + + `ip link add ${agent1RouterHostExt} type veth peer name ${agent2RouterHostExt}`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + + `ip link add ${agent2RouterHostInt} type veth peer name ${agent2Host}`, + ); + // Link up the ends to the correct namespaces + child_process.exec( + nsenter(usrnsPid, agent1NetnsPid) + + `ip link set dev ${agent1RouterHostInt} netns ${router1NetnsPid}`, + ); + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + + `ip link set dev ${agent2RouterHostExt} netns ${router2NetnsPid}`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + + `ip link set dev ${agent2Host} netns ${agent2NetnsPid}`, + ); + // Bring up each end + child_process.exec( + nsenter(usrnsPid, agent1NetnsPid) + `ip link set ${agent1Host} up`, + ); + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + + `ip link set ${agent1RouterHostInt} up`, + ); + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + + `ip link set ${agent1RouterHostExt} up`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + + `ip link set ${agent2RouterHostExt} up`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + + `ip link set ${agent2RouterHostInt} up`, + ); + child_process.exec( + nsenter(usrnsPid, agent2NetnsPid) + `ip link set ${agent2Host} up`, + ); + // Assign ip addresses to each end + child_process.exec( + nsenter(usrnsPid, agent1NetnsPid) + + `ip addr add ${agent1HostIp}${subnetMask} dev ${agent1Host}`, + ); + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + + `ip addr add ${agent1RouterHostIntIp}${subnetMask} dev ${agent1RouterHostInt}`, + ); + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + + `ip addr add ${agent1RouterHostExtIp}${subnetMask} dev ${agent1RouterHostExt}`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + + `ip addr add ${agent2RouterHostExtIp}${subnetMask} dev ${agent2RouterHostExt}`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + + `ip addr add ${agent2RouterHostIntIp}${subnetMask} dev ${agent2RouterHostInt}`, + ); + child_process.exec( + nsenter(usrnsPid, agent2NetnsPid) + + `ip addr add ${agent2HostIp}${subnetMask} dev ${agent2Host}`, + ); + // Add default routing + child_process.exec( + nsenter(usrnsPid, agent1NetnsPid) + + `ip route add default via ${agent1RouterHostIntIp}`, + ); + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + + `ip route add default via ${agent2RouterHostExtIp}`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + + `ip route add default via ${agent1RouterHostExtIp}`, + ); + child_process.exec( + nsenter(usrnsPid, agent2NetnsPid) + + `ip route add default via ${agent2RouterHostIntIp}`, + ); +} + +/** + * Set up four network namespaces to allow communication between two agents + * each behind a router + * Brings up loopback interfaces, creates and brings up a veth pair + * between each pair of adjacent namespaces, and adds default routing to allow + * cross-communication + */ +function setupSeedNamespaceInterfaces( + usrnsPid: number, + seedNetnsPid: number, + router1NetnsPid: number, + router2NetnsPid: number, +) { + // Bring up loopback + child_process.exec(nsenter(usrnsPid, seedNetnsPid) + `ip link set lo up`); + // Create veth pairs to link the namespaces + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + + `ip link add ${router1SeedHost} type veth peer name ${seedRouter1Host}`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + + `ip link add ${router2SeedHost} type veth peer name ${seedRouter2Host}`, + ); + // Move seed ends into seed network namespace + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + + `ip link set dev ${seedRouter1Host} netns ${seedNetnsPid}`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + + `ip link set dev ${seedRouter2Host} netns ${seedNetnsPid}`, + ); + // Bring up each end + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + `ip link set ${router1SeedHost} up`, + ); + child_process.exec( + nsenter(usrnsPid, seedNetnsPid) + `ip link set ${seedRouter1Host} up`, + ); + child_process.exec( + nsenter(usrnsPid, seedNetnsPid) + `ip link set ${seedRouter2Host} up`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + `ip link set ${router2SeedHost} up`, + ); + // Assign ip addresses to each end + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + + `ip addr add ${router1SeedHostIp}${subnetMask} dev ${router1SeedHost}`, + ); + child_process.exec( + nsenter(usrnsPid, seedNetnsPid) + + `ip addr add ${seedHostIp}${subnetMask} dev ${seedRouter1Host}`, + ); + child_process.exec( + nsenter(usrnsPid, seedNetnsPid) + + `ip addr add ${seedHostIp}${subnetMask} dev ${seedRouter2Host}`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + + `ip addr add ${router2SeedHostIp}${subnetMask} dev ${router2SeedHost}`, + ); + child_process.exec( + nsenter(usrnsPid, router1NetnsPid) + + `ip route add ${seedHostIp} dev ${router1SeedHost}`, + ); + child_process.exec( + nsenter(usrnsPid, router2NetnsPid) + + `ip route add ${seedHostIp} dev ${router2SeedHost}`, + ); + // Add default routing + child_process.exec( + nsenter(usrnsPid, seedNetnsPid) + + `ip route add ${router1SeedHostIp} dev ${seedRouter1Host}`, + ); + child_process.exec( + nsenter(usrnsPid, seedNetnsPid) + + `ip route add ${router2SeedHostIp} dev ${seedRouter2Host}`, + ); +} + +/** + * Runs pk command through subprocess inside a network namespace + * This is used when a subprocess functionality needs to be used + * This is intended for terminating subprocesses + * Both stdout and stderr are the entire output including newlines + * @param env Augments env for command execution + * @param cwd Defaults to temporary directory + */ +async function pkExecNs( + usrnsPid: number, + netnsPid: number, + args: Array = [], + env: Record = {}, + cwd?: string, +): Promise<{ + exitCode: number; + stdout: string; + stderr: string; +}> { + cwd = + cwd ?? (await fs.promises.mkdtemp(path.join(os.tmpdir(), 'polykey-test-'))); + env = { + ...process.env, + ...env, + }; + // Recall that we attempt to connect to all specified seed nodes on agent start. + // Therefore, for testing purposes only, we default the seed nodes as empty + // (if not defined in the env) to ensure no attempted connections. A regular + // PolykeyAgent is expected to initially connect to the mainnet seed nodes + env['PK_SEED_NODES'] = env['PK_SEED_NODES'] ?? ''; + const tsConfigPath = path.resolve( + path.join(global.projectDir, 'tsconfig.json'), + ); + const tsConfigPathsRegisterPath = path.resolve( + path.join(global.projectDir, 'node_modules/tsconfig-paths/register'), + ); + const polykeyPath = path.resolve( + path.join(global.projectDir, 'src/bin/polykey.ts'), + ); + return new Promise((resolve, reject) => { + child_process.execFile( + 'nsenter', + [ + '--target', + usrnsPid.toString(), + '--user', + '--preserve-credentials', + 'nsenter', + '--target', + netnsPid.toString(), + '--net', + 'ts-node', + '--project', + tsConfigPath, + '--require', + tsConfigPathsRegisterPath, + '--compiler', + 'typescript-cached-transpile', + '--transpile-only', + polykeyPath, + ...args, + ], + { + env, + cwd, + windowsHide: true, + }, + (error, stdout, stderr) => { + if (error != null && error.code === undefined) { + // This can only happen when the command is killed + return reject(error); + } else { + // Success and Unsuccessful exits are valid here + return resolve({ + exitCode: error && error.code != null ? error.code : 0, + stdout, + stderr, + }); + } + }, + ); + }); +} + +/** + * Launch pk command through subprocess inside a network namespace + * This is used when a subprocess functionality needs to be used + * This is intended for non-terminating subprocesses + * @param env Augments env for command execution + * @param cwd Defaults to temporary directory + */ +async function pkSpawnNs( + usrnsPid: number, + netnsPid: number, + args: Array = [], + env: Record = {}, + cwd?: string, + logger: Logger = new Logger(pkSpawnNs.name), +): Promise { + cwd = + cwd ?? (await fs.promises.mkdtemp(path.join(os.tmpdir(), 'polykey-test-'))); + env = { + ...process.env, + ...env, + }; + // Recall that we attempt to connect to all specified seed nodes on agent start. + // Therefore, for testing purposes only, we default the seed nodes as empty + // (if not defined in the env) to ensure no attempted connections. A regular + // PolykeyAgent is expected to initially connect to the mainnet seed nodes + env['PK_SEED_NODES'] = env['PK_SEED_NODES'] ?? ''; + const tsConfigPath = path.resolve( + path.join(global.projectDir, 'tsconfig.json'), + ); + const tsConfigPathsRegisterPath = path.resolve( + path.join(global.projectDir, 'node_modules/tsconfig-paths/register'), + ); + const polykeyPath = path.resolve( + path.join(global.projectDir, 'src/bin/polykey.ts'), + ); + const subprocess = child_process.spawn( + 'nsenter', + [ + '--target', + usrnsPid.toString(), + '--user', + '--preserve-credentials', + 'nsenter', + '--target', + netnsPid.toString(), + '--net', + 'ts-node', + '--project', + tsConfigPath, + '--require', + tsConfigPathsRegisterPath, + '--compiler', + 'typescript-cached-transpile', + '--transpile-only', + polykeyPath, + ...args, + ], + { + env, + cwd, + stdio: ['pipe', 'pipe', 'pipe'], + windowsHide: true, + shell: true, + }, + ); + const rlErr = readline.createInterface(subprocess.stderr!); + rlErr.on('line', (l) => { + // The readline library will trim newlines + logger.info(l); + }); + return subprocess; +} + +/** + * Setup routing between an agent and router with no NAT rules + */ +function setupDMZ( + usrnsPid: number, + routerNsPid: number, + agentIp: string, + agentPort: string, + routerExt: string, + routerExtIp: string, +) { + const postroutingCommand = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table nat ', + '--append POSTROUTING ', + '--protocol udp ', + `--source ${agentIp}${subnetMask} `, + `--out-interface ${routerExt} `, + '--jump SNAT ', + `--to-source ${routerExtIp}:${mappedPort}`, + ); + const preroutingCommand = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table nat ', + '--append PREROUTING ', + '--protocol udp ', + `--destination-port ${mappedPort} `, + `--in-interface ${routerExt} `, + '--jump DNAT ', + `--to-destination ${agentIp}:${agentPort}`, + ); + child_process.exec(postroutingCommand); + child_process.exec(preroutingCommand); +} + +/** + * Setup Port-Restricted Cone NAT for a namespace (on the router namespace) + */ +function setupNATEndpointIndependentMapping( + usrnsPid: number, + routerNsPid: number, + agentIp: string, + routerExt: string, + routerInt: string, +) { + const natCommand = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table nat ', + '--append POSTROUTING ', + '--protocol udp ', + `--source ${agentIp}${subnetMask} `, + `--out-interface ${routerExt} `, + '--jump MASQUERADE', + ); + const acceptLocalCommand = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table filter ', + '--append INPUT ', + `--in-interface ${routerInt} `, + '--jump ACCEPT', + ); + const acceptEstablishedCommand = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table filter ', + '--append INPUT ', + `--match conntrack `, + '--cstate RELATED,ESTABLISHED ', + '--jump ACCEPT', + ); + const dropCommand = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table filter ', + '--append INPUT ', + '--jump DROP', + ); + child_process.exec(acceptLocalCommand); + child_process.exec(acceptEstablishedCommand); + child_process.exec(dropCommand); + child_process.exec(natCommand); +} + +/** + * Setup Symmetric NAT for a namespace (on the router namespace) + */ +function setupNATEndpointDependentMapping( + usrnsPid: number, + routerNsPid: number, + routerExt: string, +) { + const command = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table nat ', + '--append POSTROUTING ', + '--protocol udp ', + `--out-interface ${routerExt} `, + '--jump MASQUERADE ', + `--random`, + ); + child_process.exec(command); +} + +/** + * Setup Port-Restricted Cone NAT for a namespace (on the router namespace) + */ +function setupNATSimplifiedEDMAgent( + usrnsPid: number, + routerNsPid: number, + agentIp: string, + routerExt: string, + routerInt: string, +) { + const natCommand = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table nat ', + '--append POSTROUTING ', + '--protocol udp ', + `--source ${agentIp}${subnetMask} `, + `--out-interface ${routerExt} `, + '--jump MASQUERADE ', + '--to-ports 44444', + ); + const acceptLocalCommand = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table filter ', + '--append INPUT ', + `--in-interface ${routerInt} `, + '--jump ACCEPT', + ); + const acceptEstablishedCommand = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table filter ', + '--append INPUT ', + `--match conntrack `, + '--cstate RELATED,ESTABLISHED ', + '--jump ACCEPT', + ); + const dropCommand = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table filter ', + '--append INPUT ', + '--jump DROP', + ); + child_process.exec(acceptLocalCommand); + child_process.exec(acceptEstablishedCommand); + child_process.exec(dropCommand); + child_process.exec(natCommand); +} + +/** + * Setup Port-Restricted Cone NAT for a namespace (on the router namespace) + */ +function setupNATSimplifiedEDMSeed( + usrnsPid: number, + routerNsPid: number, + agentIp: string, + routerExt: string, +) { + const natCommand = nsenter(usrnsPid, routerNsPid).concat( + 'iptables --table nat ', + '--append POSTROUTING ', + '--protocol udp ', + `--source ${agentIp}${subnetMask} `, + `--out-interface ${routerExt} `, + '--jump MASQUERADE ', + '--to-ports 55555', + ); + child_process.exec(natCommand); +} + +async function setupNATWithSeedNode( + agent1NAT: NATType, + agent2NAT: NATType, + logger: Logger = new Logger(setupNAT.name, LogLevel.WARN, [ + new StreamHandler(), + ]), +) { + const dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const password = 'password'; + // Create a user namespace containing five network namespaces + // Two agents, two routers, one seed node + const usrns = createUserNamespace(); + const seedNetns = createNetworkNamespace(usrns.pid!); + const agent1Netns = createNetworkNamespace(usrns.pid!); + const agent2Netns = createNetworkNamespace(usrns.pid!); + const router1Netns = createNetworkNamespace(usrns.pid!); + const router2Netns = createNetworkNamespace(usrns.pid!); + // Apply appropriate NAT rules + switch (agent1NAT) { + case 'dmz': { + setupDMZ( + usrns.pid!, + router1Netns.pid!, + agent1HostIp, + agent1Port, + agent1RouterHostExt, + agent1RouterHostExtIp, + ); + setupDMZ( + usrns.pid!, + router1Netns.pid!, + agent1HostIp, + agent1Port, + router1SeedHost, + router1SeedHostIp, + ); + break; + } + case 'eim': { + setupNATEndpointIndependentMapping( + usrns.pid!, + router1Netns.pid!, + agent1HostIp, + agent1RouterHostExt, + agent1RouterHostInt, + ); + setupNATEndpointIndependentMapping( + usrns.pid!, + router1Netns.pid!, + agent1HostIp, + router1SeedHost, + agent1RouterHostInt, + ); + break; + } + case 'edm': { + setupNATEndpointDependentMapping( + usrns.pid!, + router1Netns.pid!, + agent1RouterHostExt, + ); + setupNATEndpointDependentMapping( + usrns.pid!, + router1Netns.pid!, + router1SeedHost, + ); + break; + } + case 'edmSimple': { + setupNATSimplifiedEDMAgent( + usrns.pid!, + router1Netns.pid!, + agent1HostIp, + agent1RouterHostExt, + agent1RouterHostInt, + ); + setupNATSimplifiedEDMSeed( + usrns.pid!, + router1Netns.pid!, + agent1HostIp, + router1SeedHost, + ); + break; + } + } + switch (agent2NAT) { + case 'dmz': { + setupDMZ( + usrns.pid!, + router2Netns.pid!, + agent2HostIp, + agent2Port, + agent2RouterHostExt, + agent2RouterHostExtIp, + ); + setupDMZ( + usrns.pid!, + router2Netns.pid!, + agent2HostIp, + agent2Port, + router2SeedHost, + router2SeedHostIp, + ); + break; + } + case 'eim': { + setupNATEndpointIndependentMapping( + usrns.pid!, + router2Netns.pid!, + agent2HostIp, + agent2RouterHostExt, + agent2RouterHostInt, + ); + setupNATEndpointIndependentMapping( + usrns.pid!, + router2Netns.pid!, + agent2HostIp, + router2SeedHost, + agent2RouterHostInt, + ); + break; + } + case 'edm': { + setupNATEndpointDependentMapping( + usrns.pid!, + router2Netns.pid!, + agent2RouterHostExt, + ); + setupNATEndpointDependentMapping( + usrns.pid!, + router2Netns.pid!, + router2SeedHost, + ); + break; + } + case 'edmSimple': { + setupNATSimplifiedEDMAgent( + usrns.pid!, + router2Netns.pid!, + agent2HostIp, + agent2RouterHostExt, + agent2RouterHostInt, + ); + setupNATSimplifiedEDMSeed( + usrns.pid!, + router2Netns.pid!, + agent2HostIp, + router2SeedHost, + ); + break; + } + } + setupNetworkNamespaceInterfaces( + usrns.pid!, + agent1Netns.pid!, + router1Netns.pid!, + router2Netns.pid!, + agent2Netns.pid!, + ); + setupSeedNamespaceInterfaces( + usrns.pid!, + seedNetns.pid!, + router1Netns.pid!, + router2Netns.pid!, + ); + const seedNode = await pkSpawnNs( + usrns.pid!, + seedNetns.pid!, + [ + 'agent', + 'start', + '--node-path', + path.join(dataDir, 'seed'), + '--root-key-pair-bits', + '1024', + '--client-host', + '127.0.0.1', + '--proxy-host', + '0.0.0.0', + '--connection-timeout', + '1000', + '--workers', + '0', + '--verbose', + '--format', + 'json', + ], + { + PK_PASSWORD: password, + }, + dataDir, + logger.getChild('seed'), + ); + const rlOutSeed = readline.createInterface(seedNode.stdout!); + const stdoutSeed = await new Promise((resolve, reject) => { + rlOutSeed.once('line', resolve); + rlOutSeed.once('close', reject); + }); + const nodeIdSeed = JSON.parse(stdoutSeed).nodeId; + const proxyPortSeed = JSON.parse(stdoutSeed).proxyPort; + const agent1 = await pkSpawnNs( + usrns.pid!, + agent1Netns.pid!, + [ + 'agent', + 'start', + '--node-path', + path.join(dataDir, 'agent1'), + '--root-key-pair-bits', + '1024', + '--client-host', + '127.0.0.1', + '--proxy-host', + `${agent1HostIp}`, + '--proxy-port', + `${agent1Port}`, + '--workers', + '0', + '--connection-timeout', + '1000', + '--seed-nodes', + `${nodeIdSeed}@${seedHostIp}:${proxyPortSeed}`, + '--verbose', + '--format', + 'json', + ], + { + PK_PASSWORD: password, + }, + dataDir, + logger.getChild('agent1'), + ); + const rlOutNode1 = readline.createInterface(agent1.stdout!); + const stdoutNode1 = await new Promise((resolve, reject) => { + rlOutNode1.once('line', resolve); + rlOutNode1.once('close', reject); + }); + const nodeId1 = JSON.parse(stdoutNode1).nodeId; + const agent2 = await pkSpawnNs( + usrns.pid!, + agent2Netns.pid!, + [ + 'agent', + 'start', + '--node-path', + path.join(dataDir, 'agent2'), + '--root-key-pair-bits', + '1024', + '--client-host', + '127.0.0.1', + '--proxy-host', + `${agent2HostIp}`, + '--proxy-port', + `${agent2Port}`, + '--workers', + '0', + '--connection-timeout', + '1000', + '--seed-nodes', + `${nodeIdSeed}@${seedHostIp}:${proxyPortSeed}`, + '--verbose', + '--format', + 'json', + ], + { + PK_PASSWORD: password, + }, + dataDir, + logger.getChild('agent2'), + ); + const rlOutNode2 = readline.createInterface(agent2.stdout!); + const stdoutNode2 = await new Promise((resolve, reject) => { + rlOutNode2.once('line', resolve); + rlOutNode2.once('close', reject); + }); + const nodeId2 = JSON.parse(stdoutNode2).nodeId; + // Until nodes add the information of nodes that connect to them must + // do it manually + const agent1ProxyPort = + agent1NAT === 'dmz' || agent1NAT === 'edmSimple' ? mappedPort : agent1Port; + const agent2ProxyPort = + agent2NAT === 'dmz' || agent2NAT === 'edmSimple' ? mappedPort : agent2Port; + await pkExecNs( + usrns.pid!, + seedNode.pid!, + ['nodes', 'add', nodeId1, agent1RouterHostExtIp, agent1ProxyPort], + { + PK_NODE_PATH: path.join(dataDir, 'seed'), + PK_PASSWORD: password, + }, + dataDir, + ); + await pkExecNs( + usrns.pid!, + seedNode.pid!, + ['nodes', 'add', nodeId2, agent2RouterHostExtIp, agent2ProxyPort], + { + PK_NODE_PATH: path.join(dataDir, 'seed'), + PK_PASSWORD: password, + }, + dataDir, + ); + return { + userPid: usrns.pid, + agent1Pid: agent1Netns.pid, + agent2Pid: agent2Netns.pid, + password, + dataDir, + agent1NodePath: path.join(dataDir, 'agent1'), + agent2NodePath: path.join(dataDir, 'agent2'), + agent1NodeId: nodeId1, + agent2NodeId: nodeId2, + tearDownNAT: async () => { + agent2.kill('SIGTERM'); + await testBinUtils.processExit(agent2); + agent1.kill('SIGTERM'); + await testBinUtils.processExit(agent1); + seedNode.kill('SIGTERM'); + await testBinUtils.processExit(seedNode); + router2Netns.kill('SIGTERM'); + await testBinUtils.processExit(router2Netns); + router1Netns.kill('SIGTERM'); + await testBinUtils.processExit(router1Netns); + agent2Netns.kill('SIGTERM'); + await testBinUtils.processExit(agent2Netns); + agent1Netns.kill('SIGTERM'); + await testBinUtils.processExit(agent1Netns); + seedNetns.kill('SIGTERM'); + await testBinUtils.processExit(seedNetns); + usrns.kill('SIGTERM'); + await testBinUtils.processExit(usrns); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }, + }; +} + +async function setupNAT( + agent1NAT: NATType, + agent2NAT: NATType, + logger: Logger = new Logger(setupNAT.name, LogLevel.WARN, [ + new StreamHandler(), + ]), +) { + const dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + const password = 'password'; + // Create a user namespace containing four network namespaces + // Two agents and two routers + const usrns = createUserNamespace(); + const agent1Netns = createNetworkNamespace(usrns.pid!); + const agent2Netns = createNetworkNamespace(usrns.pid!); + const router1Netns = createNetworkNamespace(usrns.pid!); + const router2Netns = createNetworkNamespace(usrns.pid!); + // Apply appropriate NAT rules + switch (agent1NAT) { + case 'dmz': { + setupDMZ( + usrns.pid!, + router1Netns.pid!, + agent1HostIp, + agent1Port, + agent1RouterHostExt, + agent1RouterHostExtIp, + ); + break; + } + case 'eim': { + setupNATEndpointIndependentMapping( + usrns.pid!, + router1Netns.pid!, + agent1HostIp, + agent1RouterHostExt, + agent1RouterHostInt, + ); + break; + } + case 'edm': { + setupNATEndpointDependentMapping( + usrns.pid!, + router1Netns.pid!, + agent1RouterHostExt, + ); + break; + } + case 'edmSimple': { + setupNATSimplifiedEDMAgent( + usrns.pid!, + router1Netns.pid!, + agent1HostIp, + agent1RouterHostExt, + agent1RouterHostInt, + ); + break; + } + } + switch (agent2NAT) { + case 'dmz': { + setupDMZ( + usrns.pid!, + router2Netns.pid!, + agent2HostIp, + agent2Port, + agent2RouterHostExt, + agent2RouterHostExtIp, + ); + break; + } + case 'eim': { + setupNATEndpointIndependentMapping( + usrns.pid!, + router2Netns.pid!, + agent2HostIp, + agent2RouterHostExt, + agent2RouterHostInt, + ); + break; + } + case 'edm': { + setupNATEndpointDependentMapping( + usrns.pid!, + router2Netns.pid!, + agent2RouterHostExt, + ); + break; + } + case 'edmSimple': { + setupNATSimplifiedEDMAgent( + usrns.pid!, + router2Netns.pid!, + agent2HostIp, + agent2RouterHostExt, + agent2RouterHostInt, + ); + break; + } + } + setupNetworkNamespaceInterfaces( + usrns.pid!, + agent1Netns.pid!, + router1Netns.pid!, + router2Netns.pid!, + agent2Netns.pid!, + ); + const agent1 = await pkSpawnNs( + usrns.pid!, + agent1Netns.pid!, + [ + 'agent', + 'start', + '--node-path', + path.join(dataDir, 'agent1'), + '--root-key-pair-bits', + '1024', + '--client-host', + '127.0.0.1', + '--proxy-host', + `${agent1HostIp}`, + '--proxy-port', + `${agent1Port}`, + '--connection-timeout', + '1000', + '--workers', + '0', + '--verbose', + '--format', + 'json', + ], + { + PK_PASSWORD: password, + }, + dataDir, + logger.getChild('agent1'), + ); + const rlOutNode1 = readline.createInterface(agent1.stdout!); + const stdoutNode1 = await new Promise((resolve, reject) => { + rlOutNode1.once('line', resolve); + rlOutNode1.once('close', reject); + }); + const nodeId1 = JSON.parse(stdoutNode1).nodeId; + const agent2 = await pkSpawnNs( + usrns.pid!, + agent2Netns.pid!, + [ + 'agent', + 'start', + '--node-path', + path.join(dataDir, 'agent2'), + '--root-key-pair-bits', + '1024', + '--client-host', + '127.0.0.1', + '--proxy-host', + `${agent2HostIp}`, + '--proxy-port', + `${agent2Port}`, + '--connection-timeout', + '1000', + '--workers', + '0', + '--verbose', + '--format', + 'json', + ], + { + PK_PASSWORD: password, + }, + dataDir, + logger.getChild('agent2'), + ); + const rlOutNode2 = readline.createInterface(agent2.stdout!); + const stdoutNode2 = await new Promise((resolve, reject) => { + rlOutNode2.once('line', resolve); + rlOutNode2.once('close', reject); + }); + const nodeId2 = JSON.parse(stdoutNode2).nodeId; + return { + userPid: usrns.pid, + agent1Pid: agent1Netns.pid, + agent2Pid: agent2Netns.pid, + password, + dataDir, + agent1NodePath: path.join(dataDir, 'agent1'), + agent2NodePath: path.join(dataDir, 'agent2'), + agent1NodeId: nodeId1, + agent1Host: agent1RouterHostExtIp, + agent1ProxyPort: + agent1NAT === 'dmz' + ? mappedPort + : agent1NAT === 'edmSimple' + ? '44444' + : agent1Port, + agent2NodeId: nodeId2, + agent2Host: agent2RouterHostExtIp, + agent2ProxyPort: + agent2NAT === 'dmz' + ? mappedPort + : agent2NAT === 'edmSimple' + ? '44444' + : agent2Port, + tearDownNAT: async () => { + agent2.kill('SIGTERM'); + await testBinUtils.processExit(agent2); + agent1.kill('SIGTERM'); + await testBinUtils.processExit(agent1); + router2Netns.kill('SIGTERM'); + await testBinUtils.processExit(router2Netns); + router1Netns.kill('SIGTERM'); + await testBinUtils.processExit(router1Netns); + agent2Netns.kill('SIGTERM'); + await testBinUtils.processExit(agent2Netns); + agent1Netns.kill('SIGTERM'); + await testBinUtils.processExit(agent1Netns); + usrns.kill('SIGTERM'); + await testBinUtils.processExit(usrns); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }, + }; +} + +export { + createUserNamespace, + createNetworkNamespace, + setupNetworkNamespaceInterfaces, + pkExecNs, + pkSpawnNs, + setupNAT, + setupNATWithSeedNode, +}; From 2110634eb0a2a033c1766a93e46db55ad732036e Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Thu, 9 Jun 2022 15:17:58 +1000 Subject: [PATCH 123/137] test: `describeIf` and `testIf` utilities for conditional testing --- package-lock.json | 1 + package.json | 1 + shell.nix | 1 - tests/bin/utils.ts | 30 + tests/nat/endpointDependentNAT.test.ts | 531 +++++----- tests/nat/endpointIndependentNAT.test.ts | 739 +++++++------- tests/nat/noNAT.test.ts | 463 ++++----- tests/nat/utils.ts | 1170 ++++++++++++++++------ tests/utils.ts | 18 + 9 files changed, 1772 insertions(+), 1182 deletions(-) diff --git a/package-lock.json b/package-lock.json index acdf5c67a..56ae4cab3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -76,6 +76,7 @@ "node-gyp-build": "^4.4.0", "pkg": "5.6.0", "prettier": "^2.6.2", + "shelljs": "^0.8.5", "shx": "^0.3.4", "ts-jest": "^27.0.5", "ts-node": "10.7.0", diff --git a/package.json b/package.json index acffa9aa7..2fdc8cbff 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "node-gyp-build": "^4.4.0", "pkg": "5.6.0", "prettier": "^2.6.2", + "shelljs": "^0.8.5", "shx": "^0.3.4", "ts-jest": "^27.0.5", "ts-node": "10.7.0", diff --git a/shell.nix b/shell.nix index 37475b20e..961a13c8a 100644 --- a/shell.nix +++ b/shell.nix @@ -10,7 +10,6 @@ in utils.node2nix grpc-tools grpcurl - iptables-legacy ]; PKG_CACHE_PATH = utils.pkgCachePath; PKG_IGNORE_TAG = 1; diff --git a/tests/bin/utils.ts b/tests/bin/utils.ts index b0acefed2..c6cc42c54 100644 --- a/tests/bin/utils.ts +++ b/tests/bin/utils.ts @@ -12,6 +12,35 @@ import nexpect from 'nexpect'; import Logger from '@matrixai/logger'; import main from '@/bin/polykey'; +/** + * Wrapper for execFile to make it asynchronous and non-blocking + */ +async function exec( + command: string, + args: Array = [], +): Promise<{ + stdout: string; + stderr: string; +}> { + return new Promise((resolve, reject) => { + child_process.execFile( + command, + args, + { windowsHide: true }, + (error, stdout, stderr) => { + if (error) { + reject(error); + } else { + return resolve({ + stdout, + stderr, + }); + } + }, + ); + }); +} + /** * Runs pk command functionally */ @@ -361,6 +390,7 @@ function expectProcessError( } export { + exec, pk, pkStdio, pkExec, diff --git a/tests/nat/endpointDependentNAT.test.ts b/tests/nat/endpointDependentNAT.test.ts index 113c0004a..4d8cfcec7 100644 --- a/tests/nat/endpointDependentNAT.test.ts +++ b/tests/nat/endpointDependentNAT.test.ts @@ -1,268 +1,279 @@ import os from 'os'; import path from 'path'; import fs from 'fs'; +import process from 'process'; +import shell from 'shelljs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import * as testNatUtils from './utils'; +import { describeIf } from '../utils'; -describe('endpoint dependent NAT traversal', () => { - const logger = new Logger('EDM NAT test', LogLevel.WARN, [ - new StreamHandler(), - ]); - let dataDir: string; - beforeEach(async () => { - dataDir = await fs.promises.mkdtemp( - path.join(os.tmpdir(), 'polykey-test-'), - ); - }); - afterEach(async () => { - await fs.promises.rm(dataDir, { - force: true, - recursive: true, - }); - }); - test( - 'Node1 behind EDM NAT connects to Node2', - async () => { - const { - userPid, - agent1Pid, - password, - dataDir, - agent1NodePath, - agent2NodeId, - agent2Host, - agent2ProxyPort, - tearDownNAT, - } = await testNatUtils.setupNAT('edm', 'dmz', logger); - // Since node2 is not behind a NAT can directly add its details - await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - const { exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - await tearDownNAT(); - }, - global.defaultTimeout * 2, - ); - test( - 'Node1 connects to Node2 behind EDM NAT', - async () => { - const { - userPid, - agent1Pid, - agent2Pid, - password, - dataDir, - agent1NodePath, - agent2NodePath, - agent1NodeId, - agent1Host, - agent1ProxyPort, - agent2NodeId, - agent2Host, - agent2ProxyPort, - tearDownNAT, - } = await testNatUtils.setupNAT('dmz', 'edmSimple', logger); - await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - // If we try to ping Agent 2 it will fail - let exitCode, stdout; - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', - }); - // But Agent 2 can ping Agent 1 because Agent 1 is not behind a NAT - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - // Can now ping Agent 2 (it will be expecting a response) - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - await tearDownNAT(); - }, - global.defaultTimeout * 2, - ); - test( - 'Node1 behind EDM NAT cannot connect to Node2 behind EDM NAT', - async () => { - const { - userPid, - agent1Pid, - agent2Pid, - password, - dataDir, - agent1NodePath, - agent2NodePath, - agent1NodeId, - agent2NodeId, - tearDownNAT, - } = await testNatUtils.setupNATWithSeedNode( - 'edmSimple', - 'edmSimple', - logger, +describeIf( + process.platform === 'linux' && + shell.which('ip') && + shell.which('iptables') && + shell.which('nsenter') && + shell.which('unshare'), + 'endpoint dependent NAT traversal', + () => { + const logger = new Logger('EDM NAT test', LogLevel.WARN, [ + new StreamHandler(), + ]); + let dataDir: string; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), ); - // Contact details are retrieved from the seed node, but cannot be used - // since port mapping changes between targets in EDM mapping - // Node 2 -> Node 1 ping should fail (Node 1 behind NAT) - let exitCode, stdout; - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', - }); - // Node 1 -> Node 2 ping should also fail - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', - }); - await tearDownNAT(); - }, - global.defaultTimeout * 2, - ); - test( - 'Node1 behind EDM NAT cannot connect to Node2 behind EIM NAT', - async () => { - const { - userPid, - agent1Pid, - agent2Pid, - password, - dataDir, - agent1NodePath, - agent2NodePath, - agent1NodeId, - agent2NodeId, - tearDownNAT, - } = await testNatUtils.setupNATWithSeedNode('edmSimple', 'eim', logger); - // Since one of the nodes uses EDM NAT we cannot punch through - let exitCode, stdout; - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json', '-vv'], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', - }); - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json', '-vv'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', + }); + afterEach(async () => { + await fs.promises.rm(dataDir, { + force: true, + recursive: true, }); - await tearDownNAT(); - }, - global.defaultTimeout * 2, - ); -}); + }); + test( + 'Node1 behind EDM NAT connects to Node2', + async () => { + const { + userPid, + agent1Pid, + password, + dataDir, + agent1NodePath, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('edm', 'dmz', logger); + // Since node2 is not behind a NAT can directly add its details + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + const { exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 connects to Node2 behind EDM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent1Host, + agent1ProxyPort, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('dmz', 'edmSimple', logger); + await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + // If we try to ping Agent 2 it will fail + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + // But Agent 2 can ping Agent 1 because Agent 1 is not behind a NAT + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + // Can now ping Agent 2 (it will be expecting a response) + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 behind EDM NAT cannot connect to Node2 behind EDM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent2NodeId, + tearDownNAT, + } = await testNatUtils.setupNATWithSeedNode( + 'edmSimple', + 'edmSimple', + logger, + ); + // Contact details are retrieved from the seed node, but cannot be used + // since port mapping changes between targets in EDM mapping + // Node 2 -> Node 1 ping should fail (Node 1 behind NAT) + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + // Node 1 -> Node 2 ping should also fail + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 behind EDM NAT cannot connect to Node2 behind EIM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent2NodeId, + tearDownNAT, + } = await testNatUtils.setupNATWithSeedNode('edmSimple', 'eim', logger); + // Since one of the nodes uses EDM NAT we cannot punch through + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json', '-vv'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json', '-vv'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + }, +); diff --git a/tests/nat/endpointIndependentNAT.test.ts b/tests/nat/endpointIndependentNAT.test.ts index 357db3d17..ff44117ff 100644 --- a/tests/nat/endpointIndependentNAT.test.ts +++ b/tests/nat/endpointIndependentNAT.test.ts @@ -1,372 +1,383 @@ import os from 'os'; import path from 'path'; import fs from 'fs'; +import process from 'process'; +import shell from 'shelljs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import * as testNatUtils from './utils'; +import { describeIf } from '../utils'; -describe('endpoint independent NAT traversal', () => { - const logger = new Logger('EIM NAT test', LogLevel.WARN, [ - new StreamHandler(), - ]); - let dataDir: string; - beforeEach(async () => { - dataDir = await fs.promises.mkdtemp( - path.join(os.tmpdir(), 'polykey-test-'), - ); - }); - afterEach(async () => { - await fs.promises.rm(dataDir, { - force: true, - recursive: true, - }); - }); - test( - 'Node1 behind EIM NAT connects to Node2', - async () => { - const { - userPid, - agent1Pid, - password, - dataDir, - agent1NodePath, - agent2NodeId, - agent2Host, - agent2ProxyPort, - tearDownNAT, - } = await testNatUtils.setupNAT('eim', 'dmz', logger); - // Since node2 is not behind a NAT can directly add its details - await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, +describeIf( + process.platform === 'linux' && + shell.which('ip') && + shell.which('iptables') && + shell.which('nsenter') && + shell.which('unshare'), + 'endpoint independent NAT traversal', + () => { + const logger = new Logger('EIM NAT test', LogLevel.WARN, [ + new StreamHandler(), + ]); + let dataDir: string; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), ); - const { exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - await tearDownNAT(); - }, - global.defaultTimeout * 2, - ); - test( - 'Node1 connects to Node2 behind EIM NAT', - async () => { - const { - userPid, - agent1Pid, - agent2Pid, - password, - dataDir, - agent1NodePath, - agent2NodePath, - agent1NodeId, - agent1Host, - agent1ProxyPort, - agent2NodeId, - agent2Host, - agent2ProxyPort, - tearDownNAT, - } = await testNatUtils.setupNAT('dmz', 'eim', logger); - await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - // If we try to ping Agent 2 it will fail - let exitCode, stdout; - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', - }); - // But Agent 2 can ping Agent 1 because Agent 1 is not behind a NAT - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - // Can now ping Agent 2 (it will be expecting a response) - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - await tearDownNAT(); - }, - global.defaultTimeout * 2, - ); - test( - 'Node1 behind EIM NAT connects to Node2 behind EIM NAT', - async () => { - const { - userPid, - agent1Pid, - agent2Pid, - password, - dataDir, - agent1NodePath, - agent2NodePath, - agent1NodeId, - agent1Host, - agent1ProxyPort, - agent2NodeId, - agent2Host, - agent2ProxyPort, - tearDownNAT, - } = await testNatUtils.setupNAT('dmz', 'eim', logger); - await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - // If we try to ping Agent 2 it will fail - let exitCode, stdout; - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', - }); - // But Agent 2 can ping Agent 1 because it's expecting a response now - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - // Can now ping Agent 2 (it will be expecting a response too) - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - await tearDownNAT(); - }, - global.defaultTimeout * 2, - ); - test( - 'Node1 behind EIM NAT connects to Node2 behind EIM NAT via seed node', - async () => { - const { - userPid, - agent1Pid, - agent2Pid, - password, - dataDir, - agent1NodePath, - agent2NodePath, - agent1NodeId, - agent2NodeId, - tearDownNAT, - } = await testNatUtils.setupNATWithSeedNode('eim', 'eim', logger); - // Contact details can be retrieved from the seed node so don't need to - // add manually - // If we try to ping Agent 2 it will fail - let exitCode, stdout; - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', - }); - // But Agent 2 can ping Agent 1 now because it's expecting a response - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - // Can now ping Agent 2 (it will also be expecting a response) - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - await tearDownNAT(); - }, - global.defaultTimeout * 2, - ); - test( - 'Node1 behind EIM NAT cannot connect to Node2 behind EDM NAT', - async () => { - const { - userPid, - agent1Pid, - agent2Pid, - password, - dataDir, - agent1NodePath, - agent2NodePath, - agent1NodeId, - agent2NodeId, - tearDownNAT, - } = await testNatUtils.setupNATWithSeedNode('eim', 'edmSimple', logger); - // Since one of the nodes uses EDM NAT we cannot punch through - let exitCode, stdout; - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json', '-vv'], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', - }); - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json', '-vv'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', + }); + afterEach(async () => { + await fs.promises.rm(dataDir, { + force: true, + recursive: true, }); - await tearDownNAT(); - }, - global.defaultTimeout * 2, - ); -}); + }); + test( + 'Node1 behind EIM NAT connects to Node2', + async () => { + const { + userPid, + agent1Pid, + password, + dataDir, + agent1NodePath, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('eim', 'dmz', logger); + // Since node2 is not behind a NAT can directly add its details + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + const { exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 connects to Node2 behind EIM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent1Host, + agent1ProxyPort, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('dmz', 'eim', logger); + await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + // If we try to ping Agent 2 it will fail + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + // But Agent 2 can ping Agent 1 because Agent 1 is not behind a NAT + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + // Can now ping Agent 2 (it will be expecting a response) + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 behind EIM NAT connects to Node2 behind EIM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent1Host, + agent1ProxyPort, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('dmz', 'eim', logger); + await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + // If we try to ping Agent 2 it will fail + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + // But Agent 2 can ping Agent 1 because it's expecting a response now + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + // Can now ping Agent 2 (it will be expecting a response too) + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 behind EIM NAT connects to Node2 behind EIM NAT via seed node', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent2NodeId, + tearDownNAT, + } = await testNatUtils.setupNATWithSeedNode('eim', 'eim', logger); + // Contact details can be retrieved from the seed node so don't need to + // add manually + // If we try to ping Agent 2 it will fail + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + // But Agent 2 can ping Agent 1 now because it's expecting a response + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + // Can now ping Agent 2 (it will also be expecting a response) + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'Node1 behind EIM NAT cannot connect to Node2 behind EDM NAT', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent2NodeId, + tearDownNAT, + } = await testNatUtils.setupNATWithSeedNode('eim', 'edmSimple', logger); + // Since one of the nodes uses EDM NAT we cannot punch through + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json', '-vv'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json', '-vv'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(1); + expect(JSON.parse(stdout)).toEqual({ + success: false, + message: 'No response received', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + }, +); diff --git a/tests/nat/noNAT.test.ts b/tests/nat/noNAT.test.ts index bd8a85623..737f36c08 100644 --- a/tests/nat/noNAT.test.ts +++ b/tests/nat/noNAT.test.ts @@ -2,238 +2,249 @@ import os from 'os'; import path from 'path'; import fs from 'fs'; import readline from 'readline'; +import process from 'process'; +import shell from 'shelljs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import Status from '@/status/Status'; import config from '@/config'; import * as testNatUtils from './utils'; +import { describeIf } from '../utils'; import * as testBinUtils from '../bin/utils'; -describe('no NAT', () => { - const logger = new Logger('no NAT test', LogLevel.WARN, [ - new StreamHandler(), - ]); - let dataDir: string; - beforeEach(async () => { - dataDir = await fs.promises.mkdtemp( - path.join(os.tmpdir(), 'polykey-test-'), - ); - }); - afterEach(async () => { - await fs.promises.rm(dataDir, { - force: true, - recursive: true, - }); - }); - test( - 'can create an agent in a namespace', - async () => { - const password = 'abc123'; - const usrns = testNatUtils.createUserNamespace(); - const netns = testNatUtils.createNetworkNamespace(usrns.pid!); - const agentProcess = await testNatUtils.pkSpawnNs( - usrns.pid!, - netns.pid!, - [ - 'agent', - 'start', - '--node-path', - path.join(dataDir, 'polykey'), - '--root-key-pair-bits', - '1024', - '--client-host', - '127.0.0.1', - '--proxy-host', - '127.0.0.1', - '--workers', - '0', - '--verbose', - '--format', - 'json', - ], - { - PK_PASSWORD: password, - }, - dataDir, - logger.getChild('agentProcess'), +describeIf( + process.platform === 'linux' && + shell.which('ip') && + shell.which('iptables') && + shell.which('nsenter') && + shell.which('unshare'), + 'no NAT', + () => { + const logger = new Logger('no NAT test', LogLevel.WARN, [ + new StreamHandler(), + ]); + let dataDir: string; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), ); - const rlOut = readline.createInterface(agentProcess.stdout!); - const stdout = await new Promise((resolve, reject) => { - rlOut.once('line', resolve); - rlOut.once('close', reject); - }); - const statusLiveData = JSON.parse(stdout); - expect(statusLiveData).toMatchObject({ - pid: agentProcess.pid, - nodeId: expect.any(String), - clientHost: expect.any(String), - clientPort: expect.any(Number), - agentHost: expect.any(String), - agentPort: expect.any(Number), - forwardHost: expect.any(String), - forwardPort: expect.any(Number), - proxyHost: expect.any(String), - proxyPort: expect.any(Number), - recoveryCode: expect.any(String), + }); + afterEach(async () => { + await fs.promises.rm(dataDir, { + force: true, + recursive: true, }); - expect( - statusLiveData.recoveryCode.split(' ').length === 12 || - statusLiveData.recoveryCode.split(' ').length === 24, - ).toBe(true); - agentProcess.kill('SIGTERM'); - let exitCode, signal; - [exitCode, signal] = await testBinUtils.processExit(agentProcess); - expect(exitCode).toBe(null); - expect(signal).toBe('SIGTERM'); - // Check for graceful exit - const status = new Status({ - statusPath: path.join(dataDir, 'polykey', config.defaults.statusBase), - statusLockPath: path.join( + }); + test( + 'can create an agent in a namespace', + async () => { + const password = 'abc123'; + const usrns = testNatUtils.createUserNamespace(logger); + const netns = testNatUtils.createNetworkNamespace(usrns.pid!, logger); + const agentProcess = await testNatUtils.pkSpawnNs( + usrns.pid!, + netns.pid!, + [ + 'agent', + 'start', + '--node-path', + path.join(dataDir, 'polykey'), + '--root-key-pair-bits', + '1024', + '--client-host', + '127.0.0.1', + '--proxy-host', + '127.0.0.1', + '--workers', + '0', + '--verbose', + '--format', + 'json', + ], + { + PK_PASSWORD: password, + }, dataDir, - 'polykey', - config.defaults.statusLockBase, - ), - fs, - logger, - }); - const statusInfo = (await status.readStatus())!; - expect(statusInfo.status).toBe('DEAD'); - netns.kill('SIGTERM'); - [exitCode, signal] = await testBinUtils.processExit(netns); - expect(exitCode).toBe(null); - expect(signal).toBe('SIGTERM'); - usrns.kill('SIGTERM'); - [exitCode, signal] = await testBinUtils.processExit(usrns); - expect(exitCode).toBe(null); - expect(signal).toBe('SIGTERM'); - }, - global.defaultTimeout * 2, - ); - test( - 'agents in different namespaces can ping each other', - async () => { - const { - userPid, - agent1Pid, - agent2Pid, - password, - dataDir, - agent1NodePath, - agent2NodePath, - agent1NodeId, - agent1Host, - agent1ProxyPort, - agent2NodeId, - agent2Host, - agent2ProxyPort, - tearDownNAT, - } = await testNatUtils.setupNAT('dmz', 'dmz', logger); - // Since neither node is behind a NAT can directly add eachother's - // details using pk nodes add - await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - let exitCode, stdout; - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json', '--verbose'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json', '--verbose'], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - await tearDownNAT(); - }, - global.defaultTimeout * 2, - ); - test( - 'agents in different namespaces can ping each other via seed node', - async () => { - const { - userPid, - agent1Pid, - agent2Pid, - password, - dataDir, - agent1NodePath, - agent2NodePath, - agent1NodeId, - agent2NodeId, - tearDownNAT, - } = await testNatUtils.setupNATWithSeedNode('dmz', 'dmz', logger); - // Should be able to ping straight away using the details from the - // seed node - let exitCode, stdout; - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json', '--verbose'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json', '--verbose'], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toEqual({ - success: true, - message: 'Node is Active.', - }); - await tearDownNAT(); - }, - global.defaultTimeout * 2, - ); -}); + logger.getChild('agentProcess'), + ); + const rlOut = readline.createInterface(agentProcess.stdout!); + const stdout = await new Promise((resolve, reject) => { + rlOut.once('line', resolve); + rlOut.once('close', reject); + }); + const statusLiveData = JSON.parse(stdout); + expect(statusLiveData).toMatchObject({ + pid: agentProcess.pid, + nodeId: expect.any(String), + clientHost: expect.any(String), + clientPort: expect.any(Number), + agentHost: expect.any(String), + agentPort: expect.any(Number), + forwardHost: expect.any(String), + forwardPort: expect.any(Number), + proxyHost: expect.any(String), + proxyPort: expect.any(Number), + recoveryCode: expect.any(String), + }); + expect( + statusLiveData.recoveryCode.split(' ').length === 12 || + statusLiveData.recoveryCode.split(' ').length === 24, + ).toBe(true); + agentProcess.kill('SIGTERM'); + let exitCode, signal; + [exitCode, signal] = await testBinUtils.processExit(agentProcess); + expect(exitCode).toBe(null); + expect(signal).toBe('SIGTERM'); + // Check for graceful exit + const status = new Status({ + statusPath: path.join(dataDir, 'polykey', config.defaults.statusBase), + statusLockPath: path.join( + dataDir, + 'polykey', + config.defaults.statusLockBase, + ), + fs, + logger, + }); + const statusInfo = (await status.readStatus())!; + expect(statusInfo.status).toBe('DEAD'); + netns.kill('SIGTERM'); + [exitCode, signal] = await testBinUtils.processExit(netns); + expect(exitCode).toBe(null); + expect(signal).toBe('SIGTERM'); + usrns.kill('SIGTERM'); + [exitCode, signal] = await testBinUtils.processExit(usrns); + expect(exitCode).toBe(null); + expect(signal).toBe('SIGTERM'); + }, + global.defaultTimeout * 2, + ); + test( + 'agents in different namespaces can ping each other', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent1Host, + agent1ProxyPort, + agent2NodeId, + agent2Host, + agent2ProxyPort, + tearDownNAT, + } = await testNatUtils.setupNAT('dmz', 'dmz', logger); + // Since neither node is behind a NAT can directly add eachother's + // details using pk nodes add + await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + ); + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json', '--verbose'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json', '--verbose'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + test( + 'agents in different namespaces can ping each other via seed node', + async () => { + const { + userPid, + agent1Pid, + agent2Pid, + password, + dataDir, + agent1NodePath, + agent2NodePath, + agent1NodeId, + agent2NodeId, + tearDownNAT, + } = await testNatUtils.setupNATWithSeedNode('dmz', 'dmz', logger); + // Should be able to ping straight away using the details from the + // seed node + let exitCode, stdout; + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent1Pid!, + ['nodes', 'ping', agent2NodeId, '--format', 'json', '--verbose'], + { + PK_NODE_PATH: agent1NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + ({ exitCode, stdout } = await testNatUtils.pkExecNs( + userPid!, + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json', '--verbose'], + { + PK_NODE_PATH: agent2NodePath, + PK_PASSWORD: password, + }, + dataDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toEqual({ + success: true, + message: 'Node is Active.', + }); + await tearDownNAT(); + }, + global.defaultTimeout * 2, + ); + }, +); diff --git a/tests/nat/utils.ts b/tests/nat/utils.ts index 95125adf8..9b83fdab3 100644 --- a/tests/nat/utils.ts +++ b/tests/nat/utils.ts @@ -43,26 +43,52 @@ const mappedPort = '55555'; * Formats the command to enter a namespace to run a process inside it */ const nsenter = (usrnsPid: number, netnsPid: number) => { - return `nsenter --target ${usrnsPid} --user --preserve-credentials `.concat( - `nsenter --target ${netnsPid} --net `, - ); + return [ + '--target', + usrnsPid.toString(), + '--user', + '--preserve-credentials', + 'nsenter', + '--target', + netnsPid.toString(), + '--net', + ]; }; /** * Create a user namespace from which network namespaces can be created without * requiring sudo */ -function createUserNamespace(): ChildProcess { - return child_process.spawn('unshare', ['--user', '--map-root-user'], { - shell: true, +function createUserNamespace( + logger: Logger = new Logger(createUserNamespace.name), +): ChildProcess { + logger.info('unshare --user --map-root-user'); + const subprocess = child_process.spawn( + 'unshare', + ['--user', '--map-root-user'], + { + shell: true, + }, + ); + const rlErr = readline.createInterface(subprocess.stderr!); + rlErr.on('line', (l) => { + // The readline library will trim newlines + logger.info(l); }); + return subprocess; } /** * Create a network namespace inside a user namespace */ -function createNetworkNamespace(usrnsPid: number): ChildProcess { - return child_process.spawn( +function createNetworkNamespace( + usrnsPid: number, + logger: Logger = new Logger(createNetworkNamespace.name), +): ChildProcess { + logger.info( + `nsenter --target ${usrnsPid.toString()} --user --preserve-credentials unshare --net`, + ); + const subprocess = child_process.spawn( 'nsenter', [ '--target', @@ -74,6 +100,12 @@ function createNetworkNamespace(usrnsPid: number): ChildProcess { ], { shell: true }, ); + const rlErr = readline.createInterface(subprocess.stderr!); + rlErr.on('line', (l) => { + // The readline library will trim newlines + logger.info(l); + }); + return subprocess; } /** @@ -83,109 +115,313 @@ function createNetworkNamespace(usrnsPid: number): ChildProcess { * between each pair of adjacent namespaces, and adds default routing to allow * cross-communication */ -function setupNetworkNamespaceInterfaces( +async function setupNetworkNamespaceInterfaces( usrnsPid: number, agent1NetnsPid: number, router1NetnsPid: number, router2NetnsPid: number, agent2NetnsPid: number, + logger: Logger = new Logger(setupNetworkNamespaceInterfaces.name), ) { - // Bring up loopback - child_process.exec(nsenter(usrnsPid, agent1NetnsPid) + `ip link set lo up`); - child_process.exec(nsenter(usrnsPid, router1NetnsPid) + `ip link set lo up`); - child_process.exec(nsenter(usrnsPid, router2NetnsPid) + `ip link set lo up`); - child_process.exec(nsenter(usrnsPid, agent2NetnsPid) + `ip link set lo up`); - // Create veth pair to link the namespaces - child_process.exec( - nsenter(usrnsPid, agent1NetnsPid) + - `ip link add ${agent1Host} type veth peer name ${agent1RouterHostInt}`, - ); - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + - `ip link add ${agent1RouterHostExt} type veth peer name ${agent2RouterHostExt}`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + - `ip link add ${agent2RouterHostInt} type veth peer name ${agent2Host}`, - ); - // Link up the ends to the correct namespaces - child_process.exec( - nsenter(usrnsPid, agent1NetnsPid) + - `ip link set dev ${agent1RouterHostInt} netns ${router1NetnsPid}`, - ); - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + - `ip link set dev ${agent2RouterHostExt} netns ${router2NetnsPid}`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + - `ip link set dev ${agent2Host} netns ${agent2NetnsPid}`, - ); - // Bring up each end - child_process.exec( - nsenter(usrnsPid, agent1NetnsPid) + `ip link set ${agent1Host} up`, - ); - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + - `ip link set ${agent1RouterHostInt} up`, - ); - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + - `ip link set ${agent1RouterHostExt} up`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + - `ip link set ${agent2RouterHostExt} up`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + - `ip link set ${agent2RouterHostInt} up`, - ); - child_process.exec( - nsenter(usrnsPid, agent2NetnsPid) + `ip link set ${agent2Host} up`, - ); - // Assign ip addresses to each end - child_process.exec( - nsenter(usrnsPid, agent1NetnsPid) + - `ip addr add ${agent1HostIp}${subnetMask} dev ${agent1Host}`, - ); - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + - `ip addr add ${agent1RouterHostIntIp}${subnetMask} dev ${agent1RouterHostInt}`, - ); - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + - `ip addr add ${agent1RouterHostExtIp}${subnetMask} dev ${agent1RouterHostExt}`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + - `ip addr add ${agent2RouterHostExtIp}${subnetMask} dev ${agent2RouterHostExt}`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + - `ip addr add ${agent2RouterHostIntIp}${subnetMask} dev ${agent2RouterHostInt}`, - ); - child_process.exec( - nsenter(usrnsPid, agent2NetnsPid) + - `ip addr add ${agent2HostIp}${subnetMask} dev ${agent2Host}`, - ); - // Add default routing - child_process.exec( - nsenter(usrnsPid, agent1NetnsPid) + - `ip route add default via ${agent1RouterHostIntIp}`, - ); - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + - `ip route add default via ${agent2RouterHostExtIp}`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + - `ip route add default via ${agent1RouterHostExtIp}`, - ); - child_process.exec( - nsenter(usrnsPid, agent2NetnsPid) + - `ip route add default via ${agent2RouterHostIntIp}`, - ); + let args: Array = []; + try { + // Bring up loopback + args = [ + ...nsenter(usrnsPid, agent1NetnsPid), + 'ip', + 'link', + 'set', + 'lo', + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'link', + 'set', + 'lo', + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'link', + 'set', + 'lo', + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, agent2NetnsPid), + 'ip', + 'link', + 'set', + 'lo', + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + // Create veth pair to link the namespaces + args = [ + ...nsenter(usrnsPid, agent1NetnsPid), + 'ip', + 'link', + 'add', + agent1Host, + 'type', + 'veth', + 'peer', + 'name', + agent1RouterHostInt, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'link', + 'add', + agent1RouterHostExt, + 'type', + 'veth', + 'peer', + 'name', + agent2RouterHostExt, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'link', + 'add', + agent2RouterHostInt, + 'type', + 'veth', + 'peer', + 'name', + agent2Host, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + // Link up the ends to the correct namespaces + args = [ + ...nsenter(usrnsPid, agent1NetnsPid), + 'ip', + 'link', + 'set', + 'dev', + agent1RouterHostInt, + 'netns', + router1NetnsPid.toString(), + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'link', + 'set', + 'dev', + agent2RouterHostExt, + 'netns', + router2NetnsPid.toString(), + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'link', + 'set', + 'dev', + agent2Host, + 'netns', + agent2NetnsPid.toString(), + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + // Bring up each end + args = [ + ...nsenter(usrnsPid, agent1NetnsPid), + 'ip', + 'link', + 'set', + agent1Host, + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'link', + 'set', + agent1RouterHostInt, + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'link', + 'set', + agent1RouterHostExt, + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'link', + 'set', + agent2RouterHostExt, + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'link', + 'set', + agent2RouterHostInt, + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, agent2NetnsPid), + 'ip', + 'link', + 'set', + agent2Host, + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + // Assign ip addresses to each end + args = [ + ...nsenter(usrnsPid, agent1NetnsPid), + 'ip', + 'addr', + 'add', + `${agent1HostIp}${subnetMask}`, + 'dev', + agent1Host, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'addr', + 'add', + `${agent1RouterHostIntIp}${subnetMask}`, + 'dev', + agent1RouterHostInt, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'addr', + 'add', + `${agent1RouterHostExtIp}${subnetMask}`, + 'dev', + agent1RouterHostExt, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'addr', + 'add', + `${agent2RouterHostExtIp}${subnetMask}`, + 'dev', + agent2RouterHostExt, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'addr', + 'add', + `${agent2RouterHostIntIp}${subnetMask}`, + 'dev', + agent2RouterHostInt, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, agent2NetnsPid), + 'ip', + 'addr', + 'add', + `${agent2HostIp}${subnetMask}`, + 'dev', + agent2Host, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + // Add default routing + args = [ + ...nsenter(usrnsPid, agent1NetnsPid), + 'ip', + 'route', + 'add', + 'default', + 'via', + agent1RouterHostIntIp, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'route', + 'add', + 'default', + 'via', + agent2RouterHostExtIp, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'route', + 'add', + 'default', + 'via', + agent1RouterHostExtIp, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, agent2NetnsPid), + 'ip', + 'route', + 'add', + 'default', + 'via', + agent2RouterHostIntIp, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + } catch (e) { + logger.error(e.message); + } } /** @@ -195,79 +431,214 @@ function setupNetworkNamespaceInterfaces( * between each pair of adjacent namespaces, and adds default routing to allow * cross-communication */ -function setupSeedNamespaceInterfaces( +async function setupSeedNamespaceInterfaces( usrnsPid: number, seedNetnsPid: number, router1NetnsPid: number, router2NetnsPid: number, + logger: Logger = new Logger(setupSeedNamespaceInterfaces.name), ) { - // Bring up loopback - child_process.exec(nsenter(usrnsPid, seedNetnsPid) + `ip link set lo up`); - // Create veth pairs to link the namespaces - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + - `ip link add ${router1SeedHost} type veth peer name ${seedRouter1Host}`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + - `ip link add ${router2SeedHost} type veth peer name ${seedRouter2Host}`, - ); - // Move seed ends into seed network namespace - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + - `ip link set dev ${seedRouter1Host} netns ${seedNetnsPid}`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + - `ip link set dev ${seedRouter2Host} netns ${seedNetnsPid}`, - ); - // Bring up each end - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + `ip link set ${router1SeedHost} up`, - ); - child_process.exec( - nsenter(usrnsPid, seedNetnsPid) + `ip link set ${seedRouter1Host} up`, - ); - child_process.exec( - nsenter(usrnsPid, seedNetnsPid) + `ip link set ${seedRouter2Host} up`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + `ip link set ${router2SeedHost} up`, - ); - // Assign ip addresses to each end - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + - `ip addr add ${router1SeedHostIp}${subnetMask} dev ${router1SeedHost}`, - ); - child_process.exec( - nsenter(usrnsPid, seedNetnsPid) + - `ip addr add ${seedHostIp}${subnetMask} dev ${seedRouter1Host}`, - ); - child_process.exec( - nsenter(usrnsPid, seedNetnsPid) + - `ip addr add ${seedHostIp}${subnetMask} dev ${seedRouter2Host}`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + - `ip addr add ${router2SeedHostIp}${subnetMask} dev ${router2SeedHost}`, - ); - child_process.exec( - nsenter(usrnsPid, router1NetnsPid) + - `ip route add ${seedHostIp} dev ${router1SeedHost}`, - ); - child_process.exec( - nsenter(usrnsPid, router2NetnsPid) + - `ip route add ${seedHostIp} dev ${router2SeedHost}`, - ); - // Add default routing - child_process.exec( - nsenter(usrnsPid, seedNetnsPid) + - `ip route add ${router1SeedHostIp} dev ${seedRouter1Host}`, - ); - child_process.exec( - nsenter(usrnsPid, seedNetnsPid) + - `ip route add ${router2SeedHostIp} dev ${seedRouter2Host}`, - ); + let args: Array = []; + try { + // Bring up loopback + args = [ + ...nsenter(usrnsPid, seedNetnsPid), + 'ip', + 'link', + 'set', + 'lo', + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + // Create veth pairs to link the namespaces + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'link', + 'add', + router1SeedHost, + 'type', + 'veth', + 'peer', + 'name', + seedRouter1Host, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'link', + 'add', + router2SeedHost, + 'type', + 'veth', + 'peer', + 'name', + seedRouter2Host, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + // Move seed ends into seed network namespace + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'link', + 'set', + 'dev', + seedRouter1Host, + 'netns', + seedNetnsPid.toString(), + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'link', + 'set', + 'dev', + seedRouter2Host, + 'netns', + seedNetnsPid.toString(), + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + // Bring up each end + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'link', + 'set', + router1SeedHost, + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, seedNetnsPid), + 'ip', + 'link', + 'set', + seedRouter1Host, + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, seedNetnsPid), + 'ip', + 'link', + 'set', + seedRouter2Host, + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'link', + 'set', + router2SeedHost, + 'up', + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + // Assign ip addresses to each end + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'addr', + 'add', + `${router1SeedHostIp}${subnetMask}`, + 'dev', + router1SeedHost, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, seedNetnsPid), + 'ip', + 'addr', + 'add', + `${seedHostIp}${subnetMask}`, + 'dev', + seedRouter1Host, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, seedNetnsPid), + 'ip', + 'addr', + 'add', + `${seedHostIp}${subnetMask}`, + 'dev', + seedRouter2Host, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'addr', + 'add', + `${router2SeedHostIp}${subnetMask}`, + 'dev', + router2SeedHost, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + // Add default routing + args = [ + ...nsenter(usrnsPid, router1NetnsPid), + 'ip', + 'route', + 'add', + seedHostIp, + 'dev', + router1SeedHost, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, router2NetnsPid), + 'ip', + 'route', + 'add', + seedHostIp, + 'dev', + router2SeedHost, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, seedNetnsPid), + 'ip', + 'route', + 'add', + router1SeedHostIp, + 'dev', + seedRouter1Host, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + args = [ + ...nsenter(usrnsPid, seedNetnsPid), + 'ip', + 'route', + 'add', + router2SeedHostIp, + 'dev', + seedRouter2Host, + ]; + logger.info(['nsenter', ...args].join(' ')); + await testBinUtils.exec('nsenter', args); + } catch (e) { + logger.error(e.message); + } } /** @@ -313,14 +684,7 @@ async function pkExecNs( child_process.execFile( 'nsenter', [ - '--target', - usrnsPid.toString(), - '--user', - '--preserve-credentials', - 'nsenter', - '--target', - netnsPid.toString(), - '--net', + ...nsenter(usrnsPid, netnsPid), 'ts-node', '--project', tsConfigPath, @@ -392,14 +756,7 @@ async function pkSpawnNs( const subprocess = child_process.spawn( 'nsenter', [ - '--target', - usrnsPid.toString(), - '--user', - '--preserve-credentials', - 'nsenter', - '--target', - netnsPid.toString(), - '--net', + ...nsenter(usrnsPid, netnsPid), 'ts-node', '--project', tsConfigPath, @@ -430,159 +787,283 @@ async function pkSpawnNs( /** * Setup routing between an agent and router with no NAT rules */ -function setupDMZ( +async function setupDMZ( usrnsPid: number, routerNsPid: number, agentIp: string, agentPort: string, routerExt: string, routerExtIp: string, + logger: Logger = new Logger(setupDMZ.name), ) { - const postroutingCommand = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table nat ', - '--append POSTROUTING ', - '--protocol udp ', - `--source ${agentIp}${subnetMask} `, - `--out-interface ${routerExt} `, - '--jump SNAT ', - `--to-source ${routerExtIp}:${mappedPort}`, - ); - const preroutingCommand = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table nat ', - '--append PREROUTING ', - '--protocol udp ', - `--destination-port ${mappedPort} `, - `--in-interface ${routerExt} `, - '--jump DNAT ', - `--to-destination ${agentIp}:${agentPort}`, - ); - child_process.exec(postroutingCommand); - child_process.exec(preroutingCommand); + const postroutingCommand = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'nat', + '--append', + 'POSTROUTING', + '--protocol', + 'udp', + '--source', + `${agentIp}${subnetMask}`, + '--out-interface', + routerExt, + '--jump', + 'SNAT', + '--to-source', + `${routerExtIp}:${mappedPort}`, + ]; + const preroutingCommand = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'nat', + '--append', + 'PREROUTING', + '--protocol', + 'udp', + '--destination-port', + mappedPort, + '--in-interface', + routerExt, + '--jump', + 'DNAT', + '--to-destination', + `${agentIp}:${agentPort}`, + ]; + try { + logger.info(['nsenter', ...postroutingCommand].join(' ')); + await testBinUtils.exec('nsenter', postroutingCommand); + logger.info(['nsenter', ...preroutingCommand].join(' ')); + await testBinUtils.exec('nsenter', preroutingCommand); + } catch (e) { + logger.error(e.message); + } } /** * Setup Port-Restricted Cone NAT for a namespace (on the router namespace) */ -function setupNATEndpointIndependentMapping( +async function setupNATEndpointIndependentMapping( usrnsPid: number, routerNsPid: number, agentIp: string, routerExt: string, routerInt: string, + logger: Logger = new Logger(setupNATEndpointIndependentMapping.name), ) { - const natCommand = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table nat ', - '--append POSTROUTING ', - '--protocol udp ', - `--source ${agentIp}${subnetMask} `, - `--out-interface ${routerExt} `, - '--jump MASQUERADE', - ); - const acceptLocalCommand = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table filter ', - '--append INPUT ', - `--in-interface ${routerInt} `, - '--jump ACCEPT', - ); - const acceptEstablishedCommand = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table filter ', - '--append INPUT ', - `--match conntrack `, - '--cstate RELATED,ESTABLISHED ', - '--jump ACCEPT', - ); - const dropCommand = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table filter ', - '--append INPUT ', - '--jump DROP', - ); - child_process.exec(acceptLocalCommand); - child_process.exec(acceptEstablishedCommand); - child_process.exec(dropCommand); - child_process.exec(natCommand); + const natCommand = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'nat', + '--append', + 'POSTROUTING', + '--protocol', + 'udp', + '--source', + `${agentIp}${subnetMask}`, + '--out-interface', + routerExt, + '--jump', + 'MASQUERADE', + ]; + const acceptLocalCommand = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'filter', + '--append', + 'INPUT', + '--in-interface', + routerInt, + '--jump', + 'ACCEPT', + ]; + const acceptEstablishedCommand = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'filter', + '--append', + 'INPUT', + '--match', + 'conntrack', + '--ctstate', + 'RELATED,ESTABLISHED', + '--jump', + 'ACCEPT', + ]; + const dropCommand = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'filter', + '--append', + 'INPUT', + '--jump', + 'DROP', + ]; + try { + logger.info(['nsenter', ...acceptLocalCommand].join(' ')); + await testBinUtils.exec('nsenter', acceptLocalCommand); + logger.info(['nsenter', ...acceptEstablishedCommand].join(' ')); + await testBinUtils.exec('nsenter', acceptEstablishedCommand); + logger.info(['nsenter', ...dropCommand].join(' ')); + await testBinUtils.exec('nsenter', dropCommand); + logger.info(['nsenter', ...natCommand].join(' ')); + await testBinUtils.exec('nsenter', natCommand); + } catch (e) { + logger.error(e.message); + } } /** * Setup Symmetric NAT for a namespace (on the router namespace) */ -function setupNATEndpointDependentMapping( +async function setupNATEndpointDependentMapping( usrnsPid: number, routerNsPid: number, routerExt: string, + logger: Logger = new Logger(setupNATEndpointDependentMapping.name), ) { - const command = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table nat ', - '--append POSTROUTING ', - '--protocol udp ', - `--out-interface ${routerExt} `, - '--jump MASQUERADE ', + const command = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'nat', + '--append', + 'POSTROUTING', + '--protocol', + 'udp', + '--out-interface', + routerExt, + '--jump', + 'MASQUERADE', `--random`, - ); - child_process.exec(command); + ]; + try { + logger.info(['nsenter', ...command].join(' ')); + await testBinUtils.exec('nsenter', command); + } catch (e) { + logger.error(e.message); + } } /** * Setup Port-Restricted Cone NAT for a namespace (on the router namespace) */ -function setupNATSimplifiedEDMAgent( +async function setupNATSimplifiedEDMAgent( usrnsPid: number, routerNsPid: number, agentIp: string, routerExt: string, routerInt: string, + logger: Logger = new Logger(setupNATSimplifiedEDMAgent.name), ) { - const natCommand = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table nat ', - '--append POSTROUTING ', - '--protocol udp ', - `--source ${agentIp}${subnetMask} `, - `--out-interface ${routerExt} `, - '--jump MASQUERADE ', - '--to-ports 44444', - ); - const acceptLocalCommand = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table filter ', - '--append INPUT ', - `--in-interface ${routerInt} `, - '--jump ACCEPT', - ); - const acceptEstablishedCommand = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table filter ', - '--append INPUT ', - `--match conntrack `, - '--cstate RELATED,ESTABLISHED ', - '--jump ACCEPT', - ); - const dropCommand = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table filter ', - '--append INPUT ', - '--jump DROP', - ); - child_process.exec(acceptLocalCommand); - child_process.exec(acceptEstablishedCommand); - child_process.exec(dropCommand); - child_process.exec(natCommand); + const natCommand = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'nat', + '--append', + 'POSTROUTING', + '--protocol', + 'udp', + '--source', + `${agentIp}${subnetMask}`, + '--out-interface', + routerExt, + '--jump', + 'MASQUERADE', + '--to-ports', + '44444', + ]; + const acceptLocalCommand = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'filter', + '--append', + 'INPUT', + '--in-interface', + routerInt, + '--jump', + 'ACCEPT', + ]; + const acceptEstablishedCommand = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'filter', + '--append', + 'INPUT', + '--match', + 'conntrack', + '--ctstate', + 'RELATED,ESTABLISHED', + '--jump', + 'ACCEPT', + ]; + const dropCommand = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'filter', + '--append', + 'INPUT', + '--jump', + 'DROP', + ]; + try { + logger.info(['nsenter', ...acceptLocalCommand].join(' ')); + await testBinUtils.exec('nsenter', acceptLocalCommand); + logger.info(['nsenter', ...acceptEstablishedCommand].join(' ')); + await testBinUtils.exec('nsenter', acceptEstablishedCommand); + logger.info(['nsenter', ...dropCommand].join(' ')); + await testBinUtils.exec('nsenter', dropCommand); + logger.info(['nsenter', ...natCommand].join(' ')); + await testBinUtils.exec('nsenter', natCommand); + } catch (e) { + logger.error(e.message); + } } /** * Setup Port-Restricted Cone NAT for a namespace (on the router namespace) */ -function setupNATSimplifiedEDMSeed( +async function setupNATSimplifiedEDMSeed( usrnsPid: number, routerNsPid: number, agentIp: string, routerExt: string, + logger: Logger = new Logger(setupNATSimplifiedEDMSeed.name), ) { - const natCommand = nsenter(usrnsPid, routerNsPid).concat( - 'iptables --table nat ', - '--append POSTROUTING ', - '--protocol udp ', - `--source ${agentIp}${subnetMask} `, - `--out-interface ${routerExt} `, - '--jump MASQUERADE ', - '--to-ports 55555', - ); - child_process.exec(natCommand); + const natCommand = [ + ...nsenter(usrnsPid, routerNsPid), + 'iptables', + '--table', + 'nat', + '--append', + 'POSTROUTING', + '--protocol', + 'udp', + '--source', + `${agentIp}${subnetMask}`, + '--out-interface', + routerExt, + '--jump', + 'MASQUERADE', + '--to-ports', + '55555', + ]; + try { + logger.info(['nsenter', ...natCommand].join(' ')); + await testBinUtils.exec('nsenter', natCommand); + } catch (e) { + logger.error(e.message); + } } async function setupNATWithSeedNode( @@ -598,159 +1079,177 @@ async function setupNATWithSeedNode( const password = 'password'; // Create a user namespace containing five network namespaces // Two agents, two routers, one seed node - const usrns = createUserNamespace(); - const seedNetns = createNetworkNamespace(usrns.pid!); - const agent1Netns = createNetworkNamespace(usrns.pid!); - const agent2Netns = createNetworkNamespace(usrns.pid!); - const router1Netns = createNetworkNamespace(usrns.pid!); - const router2Netns = createNetworkNamespace(usrns.pid!); + const usrns = createUserNamespace(logger); + const seedNetns = createNetworkNamespace(usrns.pid!, logger); + const agent1Netns = createNetworkNamespace(usrns.pid!, logger); + const agent2Netns = createNetworkNamespace(usrns.pid!, logger); + const router1Netns = createNetworkNamespace(usrns.pid!, logger); + const router2Netns = createNetworkNamespace(usrns.pid!, logger); // Apply appropriate NAT rules switch (agent1NAT) { case 'dmz': { - setupDMZ( + await setupDMZ( usrns.pid!, router1Netns.pid!, agent1HostIp, agent1Port, agent1RouterHostExt, agent1RouterHostExtIp, + logger, ); - setupDMZ( + await setupDMZ( usrns.pid!, router1Netns.pid!, agent1HostIp, agent1Port, router1SeedHost, router1SeedHostIp, + logger, ); break; } case 'eim': { - setupNATEndpointIndependentMapping( + await setupNATEndpointIndependentMapping( usrns.pid!, router1Netns.pid!, agent1HostIp, agent1RouterHostExt, agent1RouterHostInt, + logger, ); - setupNATEndpointIndependentMapping( + await setupNATEndpointIndependentMapping( usrns.pid!, router1Netns.pid!, agent1HostIp, router1SeedHost, agent1RouterHostInt, + logger, ); break; } case 'edm': { - setupNATEndpointDependentMapping( + await setupNATEndpointDependentMapping( usrns.pid!, router1Netns.pid!, agent1RouterHostExt, + logger, ); - setupNATEndpointDependentMapping( + await setupNATEndpointDependentMapping( usrns.pid!, router1Netns.pid!, router1SeedHost, + logger, ); break; } case 'edmSimple': { - setupNATSimplifiedEDMAgent( + await setupNATSimplifiedEDMAgent( usrns.pid!, router1Netns.pid!, agent1HostIp, agent1RouterHostExt, agent1RouterHostInt, + logger, ); - setupNATSimplifiedEDMSeed( + await setupNATSimplifiedEDMSeed( usrns.pid!, router1Netns.pid!, agent1HostIp, router1SeedHost, + logger, ); break; } } switch (agent2NAT) { case 'dmz': { - setupDMZ( + await setupDMZ( usrns.pid!, router2Netns.pid!, agent2HostIp, agent2Port, agent2RouterHostExt, agent2RouterHostExtIp, + logger, ); - setupDMZ( + await setupDMZ( usrns.pid!, router2Netns.pid!, agent2HostIp, agent2Port, router2SeedHost, router2SeedHostIp, + logger, ); break; } case 'eim': { - setupNATEndpointIndependentMapping( + await setupNATEndpointIndependentMapping( usrns.pid!, router2Netns.pid!, agent2HostIp, agent2RouterHostExt, agent2RouterHostInt, + logger, ); - setupNATEndpointIndependentMapping( + await setupNATEndpointIndependentMapping( usrns.pid!, router2Netns.pid!, agent2HostIp, router2SeedHost, agent2RouterHostInt, + logger, ); break; } case 'edm': { - setupNATEndpointDependentMapping( + await setupNATEndpointDependentMapping( usrns.pid!, router2Netns.pid!, agent2RouterHostExt, + logger, ); - setupNATEndpointDependentMapping( + await setupNATEndpointDependentMapping( usrns.pid!, router2Netns.pid!, router2SeedHost, + logger, ); break; } case 'edmSimple': { - setupNATSimplifiedEDMAgent( + await setupNATSimplifiedEDMAgent( usrns.pid!, router2Netns.pid!, agent2HostIp, agent2RouterHostExt, agent2RouterHostInt, + logger, ); - setupNATSimplifiedEDMSeed( + await setupNATSimplifiedEDMSeed( usrns.pid!, router2Netns.pid!, agent2HostIp, router2SeedHost, + logger, ); break; } } - setupNetworkNamespaceInterfaces( + await setupNetworkNamespaceInterfaces( usrns.pid!, agent1Netns.pid!, router1Netns.pid!, router2Netns.pid!, agent2Netns.pid!, + logger, ); - setupSeedNamespaceInterfaces( + await setupSeedNamespaceInterfaces( usrns.pid!, seedNetns.pid!, router1Netns.pid!, router2Netns.pid!, + logger, ); const seedNode = await pkSpawnNs( usrns.pid!, @@ -939,100 +1438,109 @@ async function setupNAT( const password = 'password'; // Create a user namespace containing four network namespaces // Two agents and two routers - const usrns = createUserNamespace(); - const agent1Netns = createNetworkNamespace(usrns.pid!); - const agent2Netns = createNetworkNamespace(usrns.pid!); - const router1Netns = createNetworkNamespace(usrns.pid!); - const router2Netns = createNetworkNamespace(usrns.pid!); + const usrns = createUserNamespace(logger); + const agent1Netns = createNetworkNamespace(usrns.pid!, logger); + const agent2Netns = createNetworkNamespace(usrns.pid!, logger); + const router1Netns = createNetworkNamespace(usrns.pid!, logger); + const router2Netns = createNetworkNamespace(usrns.pid!, logger); // Apply appropriate NAT rules switch (agent1NAT) { case 'dmz': { - setupDMZ( + await setupDMZ( usrns.pid!, router1Netns.pid!, agent1HostIp, agent1Port, agent1RouterHostExt, agent1RouterHostExtIp, + logger, ); break; } case 'eim': { - setupNATEndpointIndependentMapping( + await setupNATEndpointIndependentMapping( usrns.pid!, router1Netns.pid!, agent1HostIp, agent1RouterHostExt, agent1RouterHostInt, + logger, ); break; } case 'edm': { - setupNATEndpointDependentMapping( + await setupNATEndpointDependentMapping( usrns.pid!, router1Netns.pid!, agent1RouterHostExt, + logger, ); break; } case 'edmSimple': { - setupNATSimplifiedEDMAgent( + await setupNATSimplifiedEDMAgent( usrns.pid!, router1Netns.pid!, agent1HostIp, agent1RouterHostExt, agent1RouterHostInt, + logger, ); break; } } switch (agent2NAT) { case 'dmz': { - setupDMZ( + await setupDMZ( usrns.pid!, router2Netns.pid!, agent2HostIp, agent2Port, agent2RouterHostExt, agent2RouterHostExtIp, + logger, ); break; } case 'eim': { - setupNATEndpointIndependentMapping( + await setupNATEndpointIndependentMapping( usrns.pid!, router2Netns.pid!, agent2HostIp, agent2RouterHostExt, agent2RouterHostInt, + logger, ); break; } case 'edm': { - setupNATEndpointDependentMapping( + await setupNATEndpointDependentMapping( usrns.pid!, router2Netns.pid!, agent2RouterHostExt, + logger, ); break; } case 'edmSimple': { - setupNATSimplifiedEDMAgent( + await setupNATSimplifiedEDMAgent( usrns.pid!, router2Netns.pid!, agent2HostIp, agent2RouterHostExt, agent2RouterHostInt, + logger, ); break; } } - setupNetworkNamespaceInterfaces( + await setupNetworkNamespaceInterfaces( usrns.pid!, agent1Netns.pid!, router1Netns.pid!, router2Netns.pid!, agent2Netns.pid!, + logger, ); const agent1 = await pkSpawnNs( usrns.pid!, diff --git a/tests/utils.ts b/tests/utils.ts index 3ac9a7499..e607faff1 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -198,9 +198,27 @@ const expectRemoteError = async ( } }; +function describeIf(condition, name, f) { + if (condition) { + describe(name, f); + } else { + describe.skip(name, f); + } +} + +function testIf(condition, name, f, timeout?) { + if (condition) { + test(name, f, timeout); + } else { + test.skip(name, f, timeout); + } +} + export { setupGlobalKeypair, generateRandomNodeId, expectRemoteError, setupGlobalAgent, + describeIf, + testIf, }; From 8cf52a4fd348e42dec5ed1bddc9cbf18ac165d23 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 21 Jun 2022 15:07:37 +1000 Subject: [PATCH 124/137] feat: better logging for service handler errors If an error was logged out by a service handler it would previously appear as `createClientService:`, which was too vague. The logger will now state the name of the handler. --- src/PolykeyAgent.ts | 2 +- src/agent/service/index.ts | 2 +- src/agent/service/nodesChainDataGet.ts | 2 +- src/agent/service/nodesClosestLocalNodesGet.ts | 2 +- src/agent/service/nodesCrossSignClaim.ts | 2 +- src/agent/service/nodesHolePunchMessageSend.ts | 3 ++- src/agent/service/notificationsSend.ts | 2 +- src/agent/service/vaultsGitInfoGet.ts | 2 +- src/agent/service/vaultsGitPackGet.ts | 2 +- src/agent/service/vaultsScan.ts | 2 +- src/client/GRPCClientClient.ts | 2 +- src/client/service/agentLockAll.ts | 2 +- src/client/service/agentStatus.ts | 2 +- src/client/service/agentStop.ts | 2 +- src/client/service/agentUnlock.ts | 2 +- .../service/gestaltsActionsGetByIdentity.ts | 2 +- src/client/service/gestaltsActionsGetByNode.ts | 2 +- .../service/gestaltsActionsSetByIdentity.ts | 2 +- src/client/service/gestaltsActionsSetByNode.ts | 2 +- .../service/gestaltsActionsUnsetByIdentity.ts | 2 +- src/client/service/gestaltsActionsUnsetByNode.ts | 2 +- .../service/gestaltsDiscoveryByIdentity.ts | 2 +- src/client/service/gestaltsDiscoveryByNode.ts | 2 +- .../service/gestaltsGestaltGetByIdentity.ts | 2 +- src/client/service/gestaltsGestaltGetByNode.ts | 2 +- src/client/service/gestaltsGestaltList.ts | 2 +- .../service/gestaltsGestaltTrustByIdentity.ts | 2 +- src/client/service/gestaltsGestaltTrustByNode.ts | 2 +- src/client/service/identitiesAuthenticate.ts | 2 +- src/client/service/identitiesAuthenticatedGet.ts | 2 +- src/client/service/identitiesClaim.ts | 2 +- src/client/service/identitiesInfoConnectedGet.ts | 2 +- src/client/service/identitiesInfoGet.ts | 2 +- src/client/service/identitiesProvidersList.ts | 2 +- src/client/service/identitiesTokenDelete.ts | 2 +- src/client/service/identitiesTokenGet.ts | 2 +- src/client/service/identitiesTokenPut.ts | 2 +- src/client/service/index.ts | 2 +- src/client/service/keysCertsChainGet.ts | 2 +- src/client/service/keysCertsGet.ts | 2 +- src/client/service/keysDecrypt.ts | 2 +- src/client/service/keysEncrypt.ts | 2 +- src/client/service/keysKeyPairRenew.ts | 2 +- src/client/service/keysKeyPairReset.ts | 2 +- src/client/service/keysKeyPairRoot.ts | 2 +- src/client/service/keysPasswordChange.ts | 2 +- src/client/service/keysSign.ts | 2 +- src/client/service/keysVerify.ts | 2 +- src/client/service/nodesAdd.ts | 2 +- src/client/service/nodesClaim.ts | 2 +- src/client/service/nodesFind.ts | 2 +- src/client/service/nodesGetAll.ts | 16 ++++++++++++---- src/client/service/nodesPing.ts | 2 +- src/client/service/notificationsClear.ts | 2 +- src/client/service/notificationsRead.ts | 2 +- src/client/service/notificationsSend.ts | 2 +- src/client/service/vaultsClone.ts | 2 +- src/client/service/vaultsCreate.ts | 2 +- src/client/service/vaultsDelete.ts | 2 +- src/client/service/vaultsList.ts | 2 +- src/client/service/vaultsLog.ts | 2 +- src/client/service/vaultsPermissionGet.ts | 2 +- src/client/service/vaultsPermissionSet.ts | 2 +- src/client/service/vaultsPermissionUnset.ts | 2 +- src/client/service/vaultsPull.ts | 2 +- src/client/service/vaultsRename.ts | 2 +- src/client/service/vaultsScan.ts | 2 +- src/client/service/vaultsSecretsDelete.ts | 2 +- src/client/service/vaultsSecretsEdit.ts | 2 +- src/client/service/vaultsSecretsGet.ts | 2 +- src/client/service/vaultsSecretsList.ts | 2 +- src/client/service/vaultsSecretsMkdir.ts | 2 +- src/client/service/vaultsSecretsNew.ts | 2 +- src/client/service/vaultsSecretsNewDir.ts | 2 +- src/client/service/vaultsSecretsRename.ts | 2 +- src/client/service/vaultsSecretsStat.ts | 2 +- src/client/service/vaultsVersion.ts | 2 +- 77 files changed, 89 insertions(+), 80 deletions(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index e3f033c71..1e905fa9e 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -627,7 +627,7 @@ class PolykeyAgent { grpcServerAgent: this.grpcServerAgent, proxy: this.proxy, fs: this.fs, - logger: this.logger.getChild(createClientService.name), + logger: this.logger.getChild('GRPCClientClientService'), }); // Starting modules await this.keyManager.start({ diff --git a/src/agent/service/index.ts b/src/agent/service/index.ts index 6342c2ba5..2e51b699e 100644 --- a/src/agent/service/index.ts +++ b/src/agent/service/index.ts @@ -27,7 +27,7 @@ import * as agentUtils from '../utils'; function createService({ proxy, db, - logger = new Logger(createService.name), + logger = new Logger('GRPCClientAgentService'), ...containerRest }: { db: DB; diff --git a/src/agent/service/nodesChainDataGet.ts b/src/agent/service/nodesChainDataGet.ts index e0f838b33..5d0f263ed 100644 --- a/src/agent/service/nodesChainDataGet.ts +++ b/src/agent/service/nodesChainDataGet.ts @@ -51,7 +51,7 @@ function nodesChainDataGet({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - !agentUtils.isAgentClientError(e) && logger.error(e); + !agentUtils.isAgentClientError(e) && logger.error(`${nodesChainDataGet.name}:${e}`); return; } }; diff --git a/src/agent/service/nodesClosestLocalNodesGet.ts b/src/agent/service/nodesClosestLocalNodesGet.ts index 36a172b12..9cb9f45f6 100644 --- a/src/agent/service/nodesClosestLocalNodesGet.ts +++ b/src/agent/service/nodesClosestLocalNodesGet.ts @@ -63,7 +63,7 @@ function nodesClosestLocalNodesGet({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - !agentUtils.isAgentClientError(e) && logger.error(e); + !agentUtils.isAgentClientError(e) && logger.error(`${nodesClosestLocalNodesGet.name}:${e}`); return; } }; diff --git a/src/agent/service/nodesCrossSignClaim.ts b/src/agent/service/nodesCrossSignClaim.ts index 20d5ac575..2c9793ba0 100644 --- a/src/agent/service/nodesCrossSignClaim.ts +++ b/src/agent/service/nodesCrossSignClaim.ts @@ -179,7 +179,7 @@ function nodesCrossSignClaim({ claimsErrors.ErrorUndefinedSignature, claimsErrors.ErrorNodesClaimType, claimsErrors.ErrorUndefinedDoublySignedClaim, - ]) && logger.error(e); + ]) && logger.error(`${nodesCrossSignClaim.name}:${e}`); return; } }; diff --git a/src/agent/service/nodesHolePunchMessageSend.ts b/src/agent/service/nodesHolePunchMessageSend.ts index 088787264..5e388809b 100644 --- a/src/agent/service/nodesHolePunchMessageSend.ts +++ b/src/agent/service/nodesHolePunchMessageSend.ts @@ -55,6 +55,7 @@ function nodesHolePunchMessageSend({ sourceId: call.request.getSrcId(), }, ); + logger.info('IN AGENT CLIENT'); // Firstly, check if this node is the desired node // If so, then we want to make this node start sending hole punching packets // back to the source node. @@ -74,7 +75,7 @@ function nodesHolePunchMessageSend({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - !agentUtils.isAgentClientError(e) && logger.error(e); + !agentUtils.isAgentClientError(e) && logger.error(`${nodesHolePunchMessageSend.name}:${e}`); return; } }; diff --git a/src/agent/service/notificationsSend.ts b/src/agent/service/notificationsSend.ts index eb336243c..cd1b43c76 100644 --- a/src/agent/service/notificationsSend.ts +++ b/src/agent/service/notificationsSend.ts @@ -41,7 +41,7 @@ function notificationsSend({ notificationsErrors.ErrorNotificationsValidationFailed, notificationsErrors.ErrorNotificationsParse, notificationsErrors.ErrorNotificationsPermissionsNotFound, - ]) && logger.error(e); + ]) && logger.error(`${notificationsSend.name}:${e}`); return; } }; diff --git a/src/agent/service/vaultsGitInfoGet.ts b/src/agent/service/vaultsGitInfoGet.ts index 7fe9831ff..0fb18c96a 100644 --- a/src/agent/service/vaultsGitInfoGet.ts +++ b/src/agent/service/vaultsGitInfoGet.ts @@ -111,7 +111,7 @@ function vaultsGitInfoGet({ vaultsErrors.ErrorVaultsVaultUndefined, agentErrors.ErrorConnectionInfoMissing, vaultsErrors.ErrorVaultsPermissionDenied, - ]) && logger.error(e); + ]) && logger.error(`${vaultsGitInfoGet.name}:${e}`); return; } }; diff --git a/src/agent/service/vaultsGitPackGet.ts b/src/agent/service/vaultsGitPackGet.ts index 50db9da28..f8aa5dc3d 100644 --- a/src/agent/service/vaultsGitPackGet.ts +++ b/src/agent/service/vaultsGitPackGet.ts @@ -124,7 +124,7 @@ function vaultsGitPackGet({ agentErrors.ErrorConnectionInfoMissing, vaultsErrors.ErrorVaultsPermissionDenied, vaultsErrors.ErrorVaultsVaultUndefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsGitPackGet.name}:${e}`); return; } }; diff --git a/src/agent/service/vaultsScan.ts b/src/agent/service/vaultsScan.ts index f1a94c2a9..f82719108 100644 --- a/src/agent/service/vaultsScan.ts +++ b/src/agent/service/vaultsScan.ts @@ -56,7 +56,7 @@ function vaultsScan({ !agentUtils.isAgentClientError(e, [ agentErrors.ErrorConnectionInfoMissing, vaultsErrors.ErrorVaultsPermissionDenied, - ]) && logger.error(e); + ]) && logger.error(`${vaultsScan.name}:${e}`); return; } }; diff --git a/src/client/GRPCClientClient.ts b/src/client/GRPCClientClient.ts index 8b9816536..2a0a4626f 100644 --- a/src/client/GRPCClientClient.ts +++ b/src/client/GRPCClientClient.ts @@ -909,7 +909,7 @@ class GRPCClientClient extends GRPCClient { nodeId: this.nodeId, host: this.host, port: this.port, - command: this.identitiesAuthenticate.name, + command: this.nodesGetAll.name, }, this.client.nodesGetAll, )(...args); diff --git a/src/client/service/agentLockAll.ts b/src/client/service/agentLockAll.ts index 29e64bcad..9bb315c8f 100644 --- a/src/client/service/agentLockAll.ts +++ b/src/client/service/agentLockAll.ts @@ -33,7 +33,7 @@ function agentLockAll({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${agentLockAll.name}:${e}`); return; } }; diff --git a/src/client/service/agentStatus.ts b/src/client/service/agentStatus.ts index 110555cf8..4ddb3b316 100644 --- a/src/client/service/agentStatus.ts +++ b/src/client/service/agentStatus.ts @@ -50,7 +50,7 @@ function agentStatus({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${agentStatus.name}:${e}`); return; } }; diff --git a/src/client/service/agentStop.ts b/src/client/service/agentStop.ts index f88885f09..e6a640d43 100644 --- a/src/client/service/agentStop.ts +++ b/src/client/service/agentStop.ts @@ -33,7 +33,7 @@ function agentStop({ callback(null, response); } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${agentStop.name}:${e}`); return; } // Stop is called after GRPC resources are cleared diff --git a/src/client/service/agentUnlock.ts b/src/client/service/agentUnlock.ts index 5147e2718..0480ab097 100644 --- a/src/client/service/agentUnlock.ts +++ b/src/client/service/agentUnlock.ts @@ -24,7 +24,7 @@ function agentUnlock({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${agentUnlock.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsActionsGetByIdentity.ts b/src/client/service/gestaltsActionsGetByIdentity.ts index ef45d57e7..ec8e8e316 100644 --- a/src/client/service/gestaltsActionsGetByIdentity.ts +++ b/src/client/service/gestaltsActionsGetByIdentity.ts @@ -63,7 +63,7 @@ function gestaltsActionsGetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${gestaltsActionsGetByIdentity.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsActionsGetByNode.ts b/src/client/service/gestaltsActionsGetByNode.ts index b5652d3bb..ba572d818 100644 --- a/src/client/service/gestaltsActionsGetByNode.ts +++ b/src/client/service/gestaltsActionsGetByNode.ts @@ -57,7 +57,7 @@ function gestaltsActionsGetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${gestaltsActionsGetByNode.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsActionsSetByIdentity.ts b/src/client/service/gestaltsActionsSetByIdentity.ts index 0628b2a98..b60d3aa84 100644 --- a/src/client/service/gestaltsActionsSetByIdentity.ts +++ b/src/client/service/gestaltsActionsSetByIdentity.ts @@ -71,7 +71,7 @@ function gestaltsActionsSetByIdentity({ !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, - ]) && logger.error(e); + ]) && logger.error(`${gestaltsActionsSetByIdentity.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsActionsSetByNode.ts b/src/client/service/gestaltsActionsSetByNode.ts index 2aa9a7050..187c634a7 100644 --- a/src/client/service/gestaltsActionsSetByNode.ts +++ b/src/client/service/gestaltsActionsSetByNode.ts @@ -56,7 +56,7 @@ function gestaltsActionsSetByNode({ callback(grpcUtils.fromError(e)); !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, - ]) && logger.error(e); + ]) && logger.error(`${gestaltsActionsSetByNode.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsActionsUnsetByIdentity.ts b/src/client/service/gestaltsActionsUnsetByIdentity.ts index 88745bc64..b2467bee5 100644 --- a/src/client/service/gestaltsActionsUnsetByIdentity.ts +++ b/src/client/service/gestaltsActionsUnsetByIdentity.ts @@ -71,7 +71,7 @@ function gestaltsActionsUnsetByIdentity({ !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, - ]) && logger.error(e); + ]) && logger.error(`${gestaltsActionsUnsetByIdentity.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsActionsUnsetByNode.ts b/src/client/service/gestaltsActionsUnsetByNode.ts index d7a62d68a..bc39dc569 100644 --- a/src/client/service/gestaltsActionsUnsetByNode.ts +++ b/src/client/service/gestaltsActionsUnsetByNode.ts @@ -56,7 +56,7 @@ function gestaltsActionsUnsetByNode({ callback(grpcUtils.fromError(e)); !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, - ]) && logger.error(e); + ]) && logger.error(`${gestaltsActionsUnsetByNode.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsDiscoveryByIdentity.ts b/src/client/service/gestaltsDiscoveryByIdentity.ts index 37efbf7d3..18bcb2ee8 100644 --- a/src/client/service/gestaltsDiscoveryByIdentity.ts +++ b/src/client/service/gestaltsDiscoveryByIdentity.ts @@ -52,7 +52,7 @@ function gestaltsDiscoveryByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${gestaltsDiscoveryByIdentity.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsDiscoveryByNode.ts b/src/client/service/gestaltsDiscoveryByNode.ts index 0c8d1ea4c..0584e55c3 100644 --- a/src/client/service/gestaltsDiscoveryByNode.ts +++ b/src/client/service/gestaltsDiscoveryByNode.ts @@ -48,7 +48,7 @@ function gestaltsDiscoveryByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${gestaltsDiscoveryByNode.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsGestaltGetByIdentity.ts b/src/client/service/gestaltsGestaltGetByIdentity.ts index 81e3ffc54..b81df554d 100644 --- a/src/client/service/gestaltsGestaltGetByIdentity.ts +++ b/src/client/service/gestaltsGestaltGetByIdentity.ts @@ -60,7 +60,7 @@ function gestaltsGestaltGetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${gestaltsGestaltGetByIdentity.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsGestaltGetByNode.ts b/src/client/service/gestaltsGestaltGetByNode.ts index fb3e63f56..48aff4729 100644 --- a/src/client/service/gestaltsGestaltGetByNode.ts +++ b/src/client/service/gestaltsGestaltGetByNode.ts @@ -56,7 +56,7 @@ function gestaltsGestaltGetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${gestaltsGestaltGetByNode.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsGestaltList.ts b/src/client/service/gestaltsGestaltList.ts index 7b4725892..c5d49123c 100644 --- a/src/client/service/gestaltsGestaltList.ts +++ b/src/client/service/gestaltsGestaltList.ts @@ -40,7 +40,7 @@ function gestaltsGestaltList({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${gestaltsGestaltList.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsGestaltTrustByIdentity.ts b/src/client/service/gestaltsGestaltTrustByIdentity.ts index 36a0aa982..06a9eb6c4 100644 --- a/src/client/service/gestaltsGestaltTrustByIdentity.ts +++ b/src/client/service/gestaltsGestaltTrustByIdentity.ts @@ -87,7 +87,7 @@ function gestaltsGestaltTrustByIdentity({ !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphIdentityIdMissing, gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, - ]) && logger.error(e); + ]) && logger.error(`${gestaltsGestaltTrustByIdentity.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsGestaltTrustByNode.ts b/src/client/service/gestaltsGestaltTrustByNode.ts index 8fa7299a0..4e01de903 100644 --- a/src/client/service/gestaltsGestaltTrustByNode.ts +++ b/src/client/service/gestaltsGestaltTrustByNode.ts @@ -73,7 +73,7 @@ function gestaltsGestaltTrustByNode({ callback(grpcUtils.fromError(e)); !clientUtils.isClientClientError(e, [ gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, - ]) && logger.error(e); + ]) && logger.error(`${gestaltsGestaltTrustByNode.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesAuthenticate.ts b/src/client/service/identitiesAuthenticate.ts index d9c216c6c..0950abddd 100644 --- a/src/client/service/identitiesAuthenticate.ts +++ b/src/client/service/identitiesAuthenticate.ts @@ -77,7 +77,7 @@ function identitiesAuthenticate({ await genWritable.throw(e); !clientUtils.isClientClientError(e, [ identitiesErrors.ErrorProviderMissing, - ]) && logger.error(e); + ]) && logger.error(`${identitiesAuthenticate.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesAuthenticatedGet.ts b/src/client/service/identitiesAuthenticatedGet.ts index 3ab4cc941..cae567830 100644 --- a/src/client/service/identitiesAuthenticatedGet.ts +++ b/src/client/service/identitiesAuthenticatedGet.ts @@ -64,7 +64,7 @@ function identitiesAuthenticatedGet({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${identitiesAuthenticatedGet.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesClaim.ts b/src/client/service/identitiesClaim.ts index de5e1df57..6677c77d4 100644 --- a/src/client/service/identitiesClaim.ts +++ b/src/client/service/identitiesClaim.ts @@ -96,7 +96,7 @@ function identitiesClaim({ !clientUtils.isClientClientError(e, [ identitiesErrors.ErrorProviderMissing, identitiesErrors.ErrorProviderUnauthenticated, - ]) && logger.error(e); + ]) && logger.error(`${identitiesClaim.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesInfoConnectedGet.ts b/src/client/service/identitiesInfoConnectedGet.ts index 63d681700..f8f906807 100644 --- a/src/client/service/identitiesInfoConnectedGet.ts +++ b/src/client/service/identitiesInfoConnectedGet.ts @@ -124,7 +124,7 @@ function identitiesInfoConnectedGet({ identitiesErrors.ErrorProviderMissing, identitiesErrors.ErrorProviderUnauthenticated, identitiesErrors.ErrorProviderUnimplemented, - ]) && logger.error(e); + ]) && logger.error(`${identitiesInfoConnectedGet.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesInfoGet.ts b/src/client/service/identitiesInfoGet.ts index e8df1153b..3fa2bdbc1 100644 --- a/src/client/service/identitiesInfoGet.ts +++ b/src/client/service/identitiesInfoGet.ts @@ -116,7 +116,7 @@ function identitiesInfoGet({ !clientUtils.isClientClientError(e, [ identitiesErrors.ErrorProviderMissing, identitiesErrors.ErrorProviderUnauthenticated, - ]) && logger.error(e); + ]) && logger.error(`${identitiesInfoGet.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesProvidersList.ts b/src/client/service/identitiesProvidersList.ts index 70cbc9ccd..752d9eea5 100644 --- a/src/client/service/identitiesProvidersList.ts +++ b/src/client/service/identitiesProvidersList.ts @@ -30,7 +30,7 @@ function identitiesProvidersList({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${identitiesProvidersList.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesTokenDelete.ts b/src/client/service/identitiesTokenDelete.ts index 779ffea47..3bf584d8d 100644 --- a/src/client/service/identitiesTokenDelete.ts +++ b/src/client/service/identitiesTokenDelete.ts @@ -57,7 +57,7 @@ function identitiesTokenDelete({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${identitiesTokenDelete.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesTokenGet.ts b/src/client/service/identitiesTokenGet.ts index 5ca76f585..41872941e 100644 --- a/src/client/service/identitiesTokenGet.ts +++ b/src/client/service/identitiesTokenGet.ts @@ -57,7 +57,7 @@ function identitiesTokenGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${identitiesTokenGet.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesTokenPut.ts b/src/client/service/identitiesTokenPut.ts index 261b88a12..d8a19ed9e 100644 --- a/src/client/service/identitiesTokenPut.ts +++ b/src/client/service/identitiesTokenPut.ts @@ -67,7 +67,7 @@ function identitiesTokenPut({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${identitiesTokenPut.name}:${e}`); return; } }; diff --git a/src/client/service/index.ts b/src/client/service/index.ts index d6b1dff6f..68f98ac8c 100644 --- a/src/client/service/index.ts +++ b/src/client/service/index.ts @@ -91,7 +91,7 @@ function createService({ keyManager, sessionManager, db, - logger = new Logger(createService.name), + logger = new Logger('GRPCClientClientService'), fs = require('fs'), ...containerRest }: { diff --git a/src/client/service/keysCertsChainGet.ts b/src/client/service/keysCertsChainGet.ts index fed99bf2a..fabb933d4 100644 --- a/src/client/service/keysCertsChainGet.ts +++ b/src/client/service/keysCertsChainGet.ts @@ -34,7 +34,7 @@ function keysCertsChainGet({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${keysCertsChainGet.name}:${e}`); return; } }; diff --git a/src/client/service/keysCertsGet.ts b/src/client/service/keysCertsGet.ts index 1b8222612..2b89ddb34 100644 --- a/src/client/service/keysCertsGet.ts +++ b/src/client/service/keysCertsGet.ts @@ -30,7 +30,7 @@ function keysCertsGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${keysCertsGet.name}:${e}`); return; } }; diff --git a/src/client/service/keysDecrypt.ts b/src/client/service/keysDecrypt.ts index b1a0f6bad..fcd95f2ae 100644 --- a/src/client/service/keysDecrypt.ts +++ b/src/client/service/keysDecrypt.ts @@ -31,7 +31,7 @@ function keysDecrypt({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${keysDecrypt.name}:${e}`); return; } }; diff --git a/src/client/service/keysEncrypt.ts b/src/client/service/keysEncrypt.ts index b8c5c60bb..9c9264dc6 100644 --- a/src/client/service/keysEncrypt.ts +++ b/src/client/service/keysEncrypt.ts @@ -31,7 +31,7 @@ function keysEncrypt({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${keysEncrypt.name}:${e}`); return; } }; diff --git a/src/client/service/keysKeyPairRenew.ts b/src/client/service/keysKeyPairRenew.ts index ada854cad..89d03fd51 100644 --- a/src/client/service/keysKeyPairRenew.ts +++ b/src/client/service/keysKeyPairRenew.ts @@ -31,7 +31,7 @@ function keysKeyPairRenew({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${keysKeyPairRenew.name}:${e}`); return; } }; diff --git a/src/client/service/keysKeyPairReset.ts b/src/client/service/keysKeyPairReset.ts index af3b25426..3f0b7bf33 100644 --- a/src/client/service/keysKeyPairReset.ts +++ b/src/client/service/keysKeyPairReset.ts @@ -31,7 +31,7 @@ function keysKeyPairReset({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${keysKeyPairReset.name}:${e}`); return; } }; diff --git a/src/client/service/keysKeyPairRoot.ts b/src/client/service/keysKeyPairRoot.ts index 14f543d9f..8da9aa3b8 100644 --- a/src/client/service/keysKeyPairRoot.ts +++ b/src/client/service/keysKeyPairRoot.ts @@ -31,7 +31,7 @@ function keysKeyPairRoot({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${keysKeyPairRoot.name}:${e}`); return; } }; diff --git a/src/client/service/keysPasswordChange.ts b/src/client/service/keysPasswordChange.ts index b1d116db5..d94a650ed 100644 --- a/src/client/service/keysPasswordChange.ts +++ b/src/client/service/keysPasswordChange.ts @@ -29,7 +29,7 @@ function keysPasswordChange({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${keysPasswordChange.name}:${e}`); return; } }; diff --git a/src/client/service/keysSign.ts b/src/client/service/keysSign.ts index 9c3aa2ab3..77d2d4d34 100644 --- a/src/client/service/keysSign.ts +++ b/src/client/service/keysSign.ts @@ -32,7 +32,7 @@ function keysSign({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${keysSign.name}:${e}`); return; } }; diff --git a/src/client/service/keysVerify.ts b/src/client/service/keysVerify.ts index 1c53fff74..6e7cee48e 100644 --- a/src/client/service/keysVerify.ts +++ b/src/client/service/keysVerify.ts @@ -33,7 +33,7 @@ function keysVerify({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${keysVerify.name}:${e}`); return; } }; diff --git a/src/client/service/nodesAdd.ts b/src/client/service/nodesAdd.ts index 3b6043219..c5c1b8949 100644 --- a/src/client/service/nodesAdd.ts +++ b/src/client/service/nodesAdd.ts @@ -89,7 +89,7 @@ function nodesAdd({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${nodesAdd.name}:${e}`); return; } }; diff --git a/src/client/service/nodesClaim.ts b/src/client/service/nodesClaim.ts index c9e1d6db9..991ed9548 100644 --- a/src/client/service/nodesClaim.ts +++ b/src/client/service/nodesClaim.ts @@ -79,7 +79,7 @@ function nodesClaim({ callback(grpcUtils.fromError(e)); !clientUtils.isClientClientError(e, [ nodesErrors.ErrorNodeGraphNodeIdNotFound, - ]) && logger.error(e); + ]) && logger.error(`${nodesClaim.name}:${e}`); return; } }; diff --git a/src/client/service/nodesFind.ts b/src/client/service/nodesFind.ts index 324e1c0e9..7b02f9347 100644 --- a/src/client/service/nodesFind.ts +++ b/src/client/service/nodesFind.ts @@ -62,7 +62,7 @@ function nodesFind({ callback(grpcUtils.fromError(e)); !clientUtils.isClientClientError(e, [ nodesErrors.ErrorNodeGraphNodeIdNotFound, - ]) && logger.error(e); + ]) && logger.error(`${nodesFind.name}:${e}`); return; } }; diff --git a/src/client/service/nodesGetAll.ts b/src/client/service/nodesGetAll.ts index 8c021a248..ad6ab9b6e 100644 --- a/src/client/service/nodesGetAll.ts +++ b/src/client/service/nodesGetAll.ts @@ -1,25 +1,30 @@ import type * as grpc from '@grpc/grpc-js'; +import type Logger from '@matrixai/logger'; import type { Authenticate } from '../types'; import type KeyManager from '../../keys/KeyManager'; import type { NodeId } from '../../nodes/types'; import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; import type NodeGraph from '../../nodes/NodeGraph'; import { IdInternal } from '@matrixai/id'; -import { utils as nodesUtils } from '../../nodes'; -import { utils as grpcUtils } from '../../grpc'; import * as nodesPB from '../../proto/js/polykey/v1/nodes/nodes_pb'; +import * as nodesUtils from '../../nodes/utils'; +import * as nodesErrors from '../../nodes/errors'; +import * as grpcUtils from '../../grpc/utils'; +import * as clientUtils from '../utils'; /** * Retrieves all nodes from all buckets in the NodeGraph. */ function nodesGetAll({ + authenticate, nodeGraph, keyManager, - authenticate, + logger, }: { + authenticate: Authenticate; nodeGraph: NodeGraph; keyManager: KeyManager; - authenticate: Authenticate; + logger: Logger; }) { return async ( call: grpc.ServerUnaryCall, @@ -62,6 +67,9 @@ function nodesGetAll({ return; } catch (e) { callback(grpcUtils.fromError(e)); + !clientUtils.isClientClientError(e, [ + nodesErrors.ErrorNodeGraphNodeIdNotFound, + ]) && logger.error(`${nodesGetAll.name}:${e}`); return; } }; diff --git a/src/client/service/nodesPing.ts b/src/client/service/nodesPing.ts index 5adc83f54..eaf69983c 100644 --- a/src/client/service/nodesPing.ts +++ b/src/client/service/nodesPing.ts @@ -55,7 +55,7 @@ function nodesPing({ callback(grpcUtils.fromError(e)); !clientUtils.isClientClientError(e, [ nodesErrors.ErrorNodeGraphNodeIdNotFound, - ]) && logger.error(e); + ]) && logger.error(`${nodesPing.name}:${e}`); return; } }; diff --git a/src/client/service/notificationsClear.ts b/src/client/service/notificationsClear.ts index acc05724e..dbbfc761a 100644 --- a/src/client/service/notificationsClear.ts +++ b/src/client/service/notificationsClear.ts @@ -33,7 +33,7 @@ function notificationsClear({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${notificationsClear.name}:${e}`); return; } }; diff --git a/src/client/service/notificationsRead.ts b/src/client/service/notificationsRead.ts index 4e6cbb92d..051f517c8 100644 --- a/src/client/service/notificationsRead.ts +++ b/src/client/service/notificationsRead.ts @@ -75,7 +75,7 @@ function notificationsRead({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${notificationsRead.name}:${e}`); return; } }; diff --git a/src/client/service/notificationsSend.ts b/src/client/service/notificationsSend.ts index fcdb72606..118d5edbf 100644 --- a/src/client/service/notificationsSend.ts +++ b/src/client/service/notificationsSend.ts @@ -58,7 +58,7 @@ function notificationsSend({ callback(grpcUtils.fromError(e)); !clientUtils.isClientClientError(e, [ nodesErrors.ErrorNodeGraphNodeIdNotFound, - ]) && logger.error(e); + ]) && logger.error(`${notificationsSend.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsClone.ts b/src/client/service/vaultsClone.ts index ec60df21a..14b799837 100644 --- a/src/client/service/vaultsClone.ts +++ b/src/client/service/vaultsClone.ts @@ -68,7 +68,7 @@ function vaultsClone({ nodesErrors.ErrorNodeGraphNodeIdNotFound, vaultsErrors.ErrorVaultsNameConflict, [grpcErrors.ErrorPolykeyRemote, vaultsErrors.ErrorVaultsVaultUndefined], - ]) && logger.error(e); + ]) && logger.error(`${vaultsClone.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsCreate.ts b/src/client/service/vaultsCreate.ts index c181b4b76..df7c6cfac 100644 --- a/src/client/service/vaultsCreate.ts +++ b/src/client/service/vaultsCreate.ts @@ -41,7 +41,7 @@ function vaultsCreate({ callback(grpcUtils.fromError(e)); !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultDefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsCreate.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsDelete.ts b/src/client/service/vaultsDelete.ts index 61fbfbc27..8e04bf0ab 100644 --- a/src/client/service/vaultsDelete.ts +++ b/src/client/service/vaultsDelete.ts @@ -50,7 +50,7 @@ function vaultsDelete({ callback(grpcUtils.fromError(e)); !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsDelete.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsList.ts b/src/client/service/vaultsList.ts index 2e9f1a79a..f8c6a92fb 100644 --- a/src/client/service/vaultsList.ts +++ b/src/client/service/vaultsList.ts @@ -40,7 +40,7 @@ function vaultsList({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientClientError(e) && logger.error(e); + !clientUtils.isClientClientError(e) && logger.error(`${vaultsList.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsLog.ts b/src/client/service/vaultsLog.ts index 32d014b05..c028006dc 100644 --- a/src/client/service/vaultsLog.ts +++ b/src/client/service/vaultsLog.ts @@ -69,7 +69,7 @@ function vaultsLog({ !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorVaultReferenceInvalid, - ]) && logger.error(e); + ]) && logger.error(`${vaultsLog.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsPermissionGet.ts b/src/client/service/vaultsPermissionGet.ts index 86377f531..e89d9b500 100644 --- a/src/client/service/vaultsPermissionGet.ts +++ b/src/client/service/vaultsPermissionGet.ts @@ -75,7 +75,7 @@ function vaultsPermissionGet({ await genWritable.throw(e); !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsPermissionGet.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsPermissionSet.ts b/src/client/service/vaultsPermissionSet.ts index 9bc2a3b8d..37b30c29a 100644 --- a/src/client/service/vaultsPermissionSet.ts +++ b/src/client/service/vaultsPermissionSet.ts @@ -103,7 +103,7 @@ function vaultsPermissionSet({ vaultsErrors.ErrorVaultsVaultUndefined, aclErrors.ErrorACLNodeIdMissing, nodesErrors.ErrorNodeGraphNodeIdNotFound, - ]) && logger.error(e); + ]) && logger.error(`${vaultsPermissionSet.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsPermissionUnset.ts b/src/client/service/vaultsPermissionUnset.ts index 7906207a3..5aa386d6b 100644 --- a/src/client/service/vaultsPermissionUnset.ts +++ b/src/client/service/vaultsPermissionUnset.ts @@ -102,7 +102,7 @@ function vaultsPermissionUnset({ !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, gestaltsErrors.ErrorGestaltsGraphNodeIdMissing, - ]) && logger.error(e); + ]) && logger.error(`${vaultsPermissionUnset.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsPull.ts b/src/client/service/vaultsPull.ts index 00fa44880..ea83519a4 100644 --- a/src/client/service/vaultsPull.ts +++ b/src/client/service/vaultsPull.ts @@ -90,7 +90,7 @@ function vaultsPull({ vaultsErrors.ErrorVaultsVaultUndefined, nodesErrors.ErrorNodeGraphNodeIdNotFound, [grpcErrors.ErrorPolykeyRemote, vaultsErrors.ErrorVaultsVaultUndefined], - ]) && logger.error(e); + ]) && logger.error(`${vaultsPull.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsRename.ts b/src/client/service/vaultsRename.ts index 29d2bb04b..21bcd7626 100644 --- a/src/client/service/vaultsRename.ts +++ b/src/client/service/vaultsRename.ts @@ -51,7 +51,7 @@ function vaultsRename({ !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorVaultsVaultDefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsRename.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsScan.ts b/src/client/service/vaultsScan.ts index c7a0def19..248a3c5d8 100644 --- a/src/client/service/vaultsScan.ts +++ b/src/client/service/vaultsScan.ts @@ -60,7 +60,7 @@ function vaultsScan({ await genWritable.throw(e); !clientUtils.isClientClientError(e, [ nodesErrors.ErrorNodeGraphNodeIdNotFound, - ]) && logger.error(e); + ]) && logger.error(`${vaultsScan.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsSecretsDelete.ts b/src/client/service/vaultsSecretsDelete.ts index 625c03cab..c35ba8ce8 100644 --- a/src/client/service/vaultsSecretsDelete.ts +++ b/src/client/service/vaultsSecretsDelete.ts @@ -59,7 +59,7 @@ function vaultsSecretsDelete({ !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsSecretsDelete.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsSecretsEdit.ts b/src/client/service/vaultsSecretsEdit.ts index a40ea71e9..d114e56d2 100644 --- a/src/client/service/vaultsSecretsEdit.ts +++ b/src/client/service/vaultsSecretsEdit.ts @@ -61,7 +61,7 @@ function vaultsSecretsEdit({ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, vaultsErrors.ErrorVaultRemoteDefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsSecretsEdit.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsSecretsGet.ts b/src/client/service/vaultsSecretsGet.ts index 4f826551f..61eafbf16 100644 --- a/src/client/service/vaultsSecretsGet.ts +++ b/src/client/service/vaultsSecretsGet.ts @@ -59,7 +59,7 @@ function vaultsSecretsGet({ !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsSecretsGet.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsSecretsList.ts b/src/client/service/vaultsSecretsList.ts index a0774565f..c55aa59d0 100644 --- a/src/client/service/vaultsSecretsList.ts +++ b/src/client/service/vaultsSecretsList.ts @@ -61,7 +61,7 @@ function vaultsSecretsList({ await genWritable.throw(e); !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsSecretsList.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsSecretsMkdir.ts b/src/client/service/vaultsSecretsMkdir.ts index 623a28ec9..a9a545704 100644 --- a/src/client/service/vaultsSecretsMkdir.ts +++ b/src/client/service/vaultsSecretsMkdir.ts @@ -60,7 +60,7 @@ function vaultsSecretsMkdir({ !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorVaultsRecursive, - ]) && logger.error(e); + ]) && logger.error(`${vaultsSecretsMkdir.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsSecretsNew.ts b/src/client/service/vaultsSecretsNew.ts index c481a4cda..2414e6bf6 100644 --- a/src/client/service/vaultsSecretsNew.ts +++ b/src/client/service/vaultsSecretsNew.ts @@ -60,7 +60,7 @@ function vaultsSecretsNew({ !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsSecretsNew.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsSecretsNewDir.ts b/src/client/service/vaultsSecretsNewDir.ts index e9a0d0878..3ed67ce68 100644 --- a/src/client/service/vaultsSecretsNewDir.ts +++ b/src/client/service/vaultsSecretsNewDir.ts @@ -61,7 +61,7 @@ function vaultsSecretsNewDir({ callback(grpcUtils.fromError(e)); !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsSecretsNewDir.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsSecretsRename.ts b/src/client/service/vaultsSecretsRename.ts index 9362c2b08..d65a87f02 100644 --- a/src/client/service/vaultsSecretsRename.ts +++ b/src/client/service/vaultsSecretsRename.ts @@ -65,7 +65,7 @@ function vaultsSecretsRename({ !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsSecretsRename.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsSecretsStat.ts b/src/client/service/vaultsSecretsStat.ts index 78a7d2800..9d4477443 100644 --- a/src/client/service/vaultsSecretsStat.ts +++ b/src/client/service/vaultsSecretsStat.ts @@ -58,7 +58,7 @@ function vaultsSecretsStat({ !clientUtils.isClientClientError(e, [ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorSecretsSecretUndefined, - ]) && logger.error(e); + ]) && logger.error(`${vaultsSecretsStat.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsVersion.ts b/src/client/service/vaultsVersion.ts index a3871b526..df1dc3300 100644 --- a/src/client/service/vaultsVersion.ts +++ b/src/client/service/vaultsVersion.ts @@ -68,7 +68,7 @@ function vaultsVersion({ vaultsErrors.ErrorVaultsVaultUndefined, vaultsErrors.ErrorVaultReferenceInvalid, vaultsErrors.ErrorVaultReferenceMissing, - ]) && logger.error(e); + ]) && logger.error(`${vaultsVersion.name}:${e}`); return; } }; From fc365b41c50effae67c09b5575cb5d83ce251066 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 21 Jun 2022 15:09:12 +1000 Subject: [PATCH 125/137] fix: PolykeyAgent now stops nodes domains when startup fails --- src/PolykeyAgent.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index 1e905fa9e..3cd247700 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -606,7 +606,7 @@ class PolykeyAgent { acl: this.acl, gestaltGraph: this.gestaltGraph, proxy: this.proxy, - logger: this.logger.getChild(createAgentService.name), + logger: this.logger.getChild('GRPCClientAgentService'), }); const clientService = createClientService({ pkAgent: this, @@ -696,6 +696,10 @@ class PolykeyAgent { await this.notificationsManager?.stop(); await this.vaultManager?.stop(); await this.discovery?.stop(); + await this.queue?.stop(); + await this.nodeGraph?.stop(); + await this.nodeConnectionManager?.stop(); + await this.nodeManager?.stop(); await this.proxy?.stop(); await this.grpcServerAgent?.stop(); await this.grpcServerClient?.stop(); From eebeee34381c96dddea26f431bc1f5bbb786c6ca Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 21 Jun 2022 15:09:42 +1000 Subject: [PATCH 126/137] fix: ICE protocol uses `Promise.any` instead of `Promise.all` --- src/nodes/NodeConnectionManager.ts | 32 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index f39f333d8..ffa54acaa 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -610,21 +610,23 @@ class NodeConnectionManager { timer, ); for (const [nodeId, nodeData] of nodes) { - const pingAndAddNode = async () => { - const port = nodeData.address.port; - const host = await networkUtils.resolveHost(nodeData.address.host); - if (await this.pingNode(nodeId, host, port)) { - await this.nodeManager!.setNode(nodeId, nodeData.address, true); - } - }; + if (!nodeId.equals(this.keyManager.getNodeId())) { + const pingAndAddNode = async () => { + const port = nodeData.address.port; + const host = await networkUtils.resolveHost(nodeData.address.host); + if (await this.pingNode(nodeId, host, port)) { + await this.nodeManager!.setNode(nodeId, nodeData.address, true); + } + }; - if (!block) { - this.queue.push(pingAndAddNode); - } else { - try { - await pingAndAddNode(); - } catch (e) { - if (!(e instanceof nodesErrors.ErrorNodeGraphSameNodeId)) throw e; + if (!block) { + this.queue.push(pingAndAddNode); + } else { + try { + await pingAndAddNode(); + } catch (e) { + if (!(e instanceof nodesErrors.ErrorNodeGraphSameNodeId)) throw e; + } } } } @@ -759,7 +761,7 @@ class NodeConnectionManager { ); try { - await Promise.all([forwardPunchPromise, ...holePunchPromises]); + await Promise.any([forwardPunchPromise, ...holePunchPromises]); } catch (e) { return false; } From ed2973e1ea5bf9fb1ef6512c6b72f81a79a617d4 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Tue, 21 Jun 2022 15:13:22 +1000 Subject: [PATCH 127/137] tests: fixes from testnet changes The testnet PR brought in some changes that affect the NAT tests, so they needed to be modified slightly. - Adding a node to the node graph pings the node by default. We want to disable this in the NAT tests so we have more control over the pings. - Nodes add the details of any node that pings them. We can now remove some additional `nodes add` calls that were required to imitate this previously missing functionality. --- tests/nat/endpointIndependentNAT.test.ts | 14 ++++++------- tests/nat/noNAT.test.ts | 4 ++-- tests/nat/utils.ts | 26 ------------------------ 3 files changed, 9 insertions(+), 35 deletions(-) diff --git a/tests/nat/endpointIndependentNAT.test.ts b/tests/nat/endpointIndependentNAT.test.ts index ff44117ff..23d46e84d 100644 --- a/tests/nat/endpointIndependentNAT.test.ts +++ b/tests/nat/endpointIndependentNAT.test.ts @@ -48,7 +48,7 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort, '--no-ping'], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -96,7 +96,7 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort, '--no-ping'], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, @@ -106,7 +106,7 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort, '--no-ping'], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -188,7 +188,7 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort, '--no-ping'], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, @@ -198,7 +198,7 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort, '--no-ping'], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -348,7 +348,7 @@ describeIf( ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json', '-vv'], + ['nodes', 'ping', agent1NodeId, '--format', 'json'], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, @@ -363,7 +363,7 @@ describeIf( ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json', '-vv'], + ['nodes', 'ping', agent2NodeId, '--format', 'json'], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, diff --git a/tests/nat/noNAT.test.ts b/tests/nat/noNAT.test.ts index 737f36c08..0690261bb 100644 --- a/tests/nat/noNAT.test.ts +++ b/tests/nat/noNAT.test.ts @@ -142,7 +142,7 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort, '--no-ping'], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -152,7 +152,7 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort, '--no-ping'], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, diff --git a/tests/nat/utils.ts b/tests/nat/utils.ts index 9b83fdab3..13aa13cea 100644 --- a/tests/nat/utils.ts +++ b/tests/nat/utils.ts @@ -1362,32 +1362,6 @@ async function setupNATWithSeedNode( rlOutNode2.once('close', reject); }); const nodeId2 = JSON.parse(stdoutNode2).nodeId; - // Until nodes add the information of nodes that connect to them must - // do it manually - const agent1ProxyPort = - agent1NAT === 'dmz' || agent1NAT === 'edmSimple' ? mappedPort : agent1Port; - const agent2ProxyPort = - agent2NAT === 'dmz' || agent2NAT === 'edmSimple' ? mappedPort : agent2Port; - await pkExecNs( - usrns.pid!, - seedNode.pid!, - ['nodes', 'add', nodeId1, agent1RouterHostExtIp, agent1ProxyPort], - { - PK_NODE_PATH: path.join(dataDir, 'seed'), - PK_PASSWORD: password, - }, - dataDir, - ); - await pkExecNs( - usrns.pid!, - seedNode.pid!, - ['nodes', 'add', nodeId2, agent2RouterHostExtIp, agent2ProxyPort], - { - PK_NODE_PATH: path.join(dataDir, 'seed'), - PK_PASSWORD: password, - }, - dataDir, - ); return { userPid: usrns.pid, agent1Pid: agent1Netns.pid, From a0adb358e18d8ac5fd90fbcae4f683531850f6b3 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 22 Jun 2022 16:09:14 +1000 Subject: [PATCH 128/137] build: upgraded `async-init`, `async-locks` and `js-logger` --- package-lock.json | 46 +++++++++++++++++++++++----------------------- package.json | 6 +++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56ae4cab3..b12a9624a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,12 @@ "license": "GPL-3.0", "dependencies": { "@grpc/grpc-js": "1.6.7", - "@matrixai/async-init": "^1.7.3", - "@matrixai/async-locks": "^2.2.5", + "@matrixai/async-init": "^1.8.0", + "@matrixai/async-locks": "^2.3.1", "@matrixai/db": "^4.0.5", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", - "@matrixai/logger": "^2.1.1", + "@matrixai/logger": "^2.2.0", "@matrixai/resources": "^1.1.3", "@matrixai/workers": "^1.3.3", "ajv": "^7.0.4", @@ -2537,18 +2537,18 @@ } }, "node_modules/@matrixai/async-init": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.7.3.tgz", - "integrity": "sha512-Sf3q5ODhVJqrYiAdGXmwj606956lgEMKGM9LMFU5scIOh13WokHo3GthjB1yh/umCV75NYvHJn60R9gnudVZ3Q==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.8.0.tgz", + "integrity": "sha512-Y2yxG0s5UQQR/WqIvMhud0tRmcGrUynwE/vdbkSsLeLARpAAOmSgbIzP963VqOiAs8/W3FVJgMaMjo4rIaJPtg==", "dependencies": { - "@matrixai/async-locks": "^2.2.4", + "@matrixai/async-locks": "^2.3.1", "@matrixai/errors": "^1.1.1" } }, "node_modules/@matrixai/async-locks": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.2.5.tgz", - "integrity": "sha512-Yokd3p64FciLNSW04Qox+UHJulxnWQIhHt3h9sMmgoiTsyZcOgeYfPAJrtZiRnhaUXhfBczPy4VPP2e5lrXgig==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.3.1.tgz", + "integrity": "sha512-STz8VyiIXleaa72zMsq01x/ZO1gPzukUgMe25+uqMWn/nPrC9EtJOR7e3CW0DODfYDZ0748z196GeOjS3jh+4g==", "dependencies": { "@matrixai/errors": "^1.1.1", "@matrixai/resources": "^1.1.3", @@ -2588,9 +2588,9 @@ } }, "node_modules/@matrixai/logger": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.1.1.tgz", - "integrity": "sha512-79KM0PyJTpfkALf9DK2xGniU+9gngsb5O8hcdUviWz+zR2W0hnTQq/g7tJW0YnIEhmDe/GkJf0Bnbs+gWfj3BA==" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.2.0.tgz", + "integrity": "sha512-GNAFEophgqhJZI01s5OuosbxJO/GSmDZU4rfKmNS3l/dbaOuI32RKEv6XNd6O9HpjmX886rGSxks1/rBZw+cRw==" }, "node_modules/@matrixai/resources": { "version": "1.1.3", @@ -13644,18 +13644,18 @@ } }, "@matrixai/async-init": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.7.3.tgz", - "integrity": "sha512-Sf3q5ODhVJqrYiAdGXmwj606956lgEMKGM9LMFU5scIOh13WokHo3GthjB1yh/umCV75NYvHJn60R9gnudVZ3Q==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.8.0.tgz", + "integrity": "sha512-Y2yxG0s5UQQR/WqIvMhud0tRmcGrUynwE/vdbkSsLeLARpAAOmSgbIzP963VqOiAs8/W3FVJgMaMjo4rIaJPtg==", "requires": { - "@matrixai/async-locks": "^2.2.4", + "@matrixai/async-locks": "^2.3.1", "@matrixai/errors": "^1.1.1" } }, "@matrixai/async-locks": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.2.5.tgz", - "integrity": "sha512-Yokd3p64FciLNSW04Qox+UHJulxnWQIhHt3h9sMmgoiTsyZcOgeYfPAJrtZiRnhaUXhfBczPy4VPP2e5lrXgig==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-2.3.1.tgz", + "integrity": "sha512-STz8VyiIXleaa72zMsq01x/ZO1gPzukUgMe25+uqMWn/nPrC9EtJOR7e3CW0DODfYDZ0748z196GeOjS3jh+4g==", "requires": { "@matrixai/errors": "^1.1.1", "@matrixai/resources": "^1.1.3", @@ -13695,9 +13695,9 @@ } }, "@matrixai/logger": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.1.1.tgz", - "integrity": "sha512-79KM0PyJTpfkALf9DK2xGniU+9gngsb5O8hcdUviWz+zR2W0hnTQq/g7tJW0YnIEhmDe/GkJf0Bnbs+gWfj3BA==" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.2.0.tgz", + "integrity": "sha512-GNAFEophgqhJZI01s5OuosbxJO/GSmDZU4rfKmNS3l/dbaOuI32RKEv6XNd6O9HpjmX886rGSxks1/rBZw+cRw==" }, "@matrixai/resources": { "version": "1.1.3", diff --git a/package.json b/package.json index 2fdc8cbff..5fe9c750d 100644 --- a/package.json +++ b/package.json @@ -76,12 +76,12 @@ }, "dependencies": { "@grpc/grpc-js": "1.6.7", - "@matrixai/async-init": "^1.7.3", - "@matrixai/async-locks": "^2.2.5", + "@matrixai/async-init": "^1.8.0", + "@matrixai/async-locks": "^2.3.1", "@matrixai/db": "^4.0.5", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", - "@matrixai/logger": "^2.1.1", + "@matrixai/logger": "^2.2.0", "@matrixai/resources": "^1.1.3", "@matrixai/workers": "^1.3.3", "ajv": "^7.0.4", From 8fdde5450d4ff12c918b7f6638da8a186aa5c987 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 22 Jun 2022 16:10:49 +1000 Subject: [PATCH 129/137] feat: removing `edmSimple` configuration Now that nodes add the details of a node that contacts them, we no longer need the `edmSimple` configuration to do this manually. --- .../service/nodesHolePunchMessageSend.ts | 1 - tests/nat/endpointDependentNAT.test.ts | 54 ++---- tests/nat/endpointIndependentNAT.test.ts | 34 +--- tests/nat/utils.ts | 179 +----------------- 4 files changed, 22 insertions(+), 246 deletions(-) diff --git a/src/agent/service/nodesHolePunchMessageSend.ts b/src/agent/service/nodesHolePunchMessageSend.ts index 5e388809b..beafc3bd2 100644 --- a/src/agent/service/nodesHolePunchMessageSend.ts +++ b/src/agent/service/nodesHolePunchMessageSend.ts @@ -55,7 +55,6 @@ function nodesHolePunchMessageSend({ sourceId: call.request.getSrcId(), }, ); - logger.info('IN AGENT CLIENT'); // Firstly, check if this node is the desired node // If so, then we want to make this node start sending hole punching packets // back to the source node. diff --git a/tests/nat/endpointDependentNAT.test.ts b/tests/nat/endpointDependentNAT.test.ts index 4d8cfcec7..432796226 100644 --- a/tests/nat/endpointDependentNAT.test.ts +++ b/tests/nat/endpointDependentNAT.test.ts @@ -48,7 +48,7 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], + ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort, '--no-ping'], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -89,48 +89,20 @@ describeIf( agent1Host, agent1ProxyPort, agent2NodeId, - agent2Host, - agent2ProxyPort, tearDownNAT, - } = await testNatUtils.setupNAT('dmz', 'edmSimple', logger); + } = await testNatUtils.setupNAT('dmz', 'edm', logger); + // Agent 2 must ping Agent 1 first, since Agent 2 is behind a NAT await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort], + ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort, '--no-ping'], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, }, dataDir, ); - await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - ); - // If we try to ping Agent 2 it will fail let exitCode, stdout; - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent1NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', - }); - // But Agent 2 can ping Agent 1 because Agent 1 is not behind a NAT ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, agent2Pid!, @@ -181,8 +153,8 @@ describeIf( agent2NodeId, tearDownNAT, } = await testNatUtils.setupNATWithSeedNode( - 'edmSimple', - 'edmSimple', + 'edm', + 'edm', logger, ); // Contact details are retrieved from the seed node, but cannot be used @@ -202,9 +174,9 @@ describeIf( expect(exitCode).toBe(1); expect(JSON.parse(stdout)).toEqual({ success: false, - message: 'No response received', + message: `Failed to resolve node ID ${agent1NodeId} to an address.`, }); - // Node 1 -> Node 2 ping should also fail + // Node 1 -> Node 2 ping should also fail for the same reason ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, agent1Pid!, @@ -218,7 +190,7 @@ describeIf( expect(exitCode).toBe(1); expect(JSON.parse(stdout)).toEqual({ success: false, - message: 'No response received', + message: `Failed to resolve node ID ${agent2NodeId} to an address.`, }); await tearDownNAT(); }, @@ -238,13 +210,13 @@ describeIf( agent1NodeId, agent2NodeId, tearDownNAT, - } = await testNatUtils.setupNATWithSeedNode('edmSimple', 'eim', logger); + } = await testNatUtils.setupNATWithSeedNode('edm', 'eim', logger); // Since one of the nodes uses EDM NAT we cannot punch through let exitCode, stdout; ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json', '-vv'], + ['nodes', 'ping', agent1NodeId, '--format', 'json'], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, @@ -254,7 +226,7 @@ describeIf( expect(exitCode).toBe(1); expect(JSON.parse(stdout)).toEqual({ success: false, - message: 'No response received', + message: `Failed to resolve node ID ${agent1NodeId} to an address.`, }); ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, @@ -269,7 +241,7 @@ describeIf( expect(exitCode).toBe(1); expect(JSON.parse(stdout)).toEqual({ success: false, - message: 'No response received', + message: `Failed to resolve node ID ${agent2NodeId} to an address.`, }); await tearDownNAT(); }, diff --git a/tests/nat/endpointIndependentNAT.test.ts b/tests/nat/endpointIndependentNAT.test.ts index 23d46e84d..f6023010a 100644 --- a/tests/nat/endpointIndependentNAT.test.ts +++ b/tests/nat/endpointIndependentNAT.test.ts @@ -273,9 +273,8 @@ describeIf( agent2NodeId, tearDownNAT, } = await testNatUtils.setupNATWithSeedNode('eim', 'eim', logger); - // Contact details can be retrieved from the seed node so don't need to - // add manually - // If we try to ping Agent 2 it will fail + // Should be able to ping straight away using the seed node as a + // signaller let exitCode, stdout; ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, @@ -287,34 +286,17 @@ describeIf( }, dataDir, )); - expect(exitCode).toBe(1); - expect(JSON.parse(stdout)).toEqual({ - success: false, - message: 'No response received', - }); - // But Agent 2 can ping Agent 1 now because it's expecting a response - ({ exitCode, stdout } = await testNatUtils.pkExecNs( - userPid!, - agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json'], - { - PK_NODE_PATH: agent2NodePath, - PK_PASSWORD: password, - }, - dataDir, - )); expect(exitCode).toBe(0); expect(JSON.parse(stdout)).toEqual({ success: true, message: 'Node is Active.', }); - // Can now ping Agent 2 (it will also be expecting a response) ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, - agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json'], + agent2Pid!, + ['nodes', 'ping', agent1NodeId, '--format', 'json'], { - PK_NODE_PATH: agent1NodePath, + PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, }, dataDir, @@ -342,7 +324,7 @@ describeIf( agent1NodeId, agent2NodeId, tearDownNAT, - } = await testNatUtils.setupNATWithSeedNode('eim', 'edmSimple', logger); + } = await testNatUtils.setupNATWithSeedNode('eim', 'edm', logger); // Since one of the nodes uses EDM NAT we cannot punch through let exitCode, stdout; ({ exitCode, stdout } = await testNatUtils.pkExecNs( @@ -358,7 +340,7 @@ describeIf( expect(exitCode).toBe(1); expect(JSON.parse(stdout)).toEqual({ success: false, - message: 'No response received', + message: `Failed to resolve node ID ${agent1NodeId} to an address.`, }); ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, @@ -373,7 +355,7 @@ describeIf( expect(exitCode).toBe(1); expect(JSON.parse(stdout)).toEqual({ success: false, - message: 'No response received', + message: `Failed to resolve node ID ${agent2NodeId} to an address.`, }); await tearDownNAT(); }, diff --git a/tests/nat/utils.ts b/tests/nat/utils.ts index 13aa13cea..c2efe6b25 100644 --- a/tests/nat/utils.ts +++ b/tests/nat/utils.ts @@ -8,7 +8,7 @@ import readline from 'readline'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import * as testBinUtils from '../bin/utils'; -type NATType = 'eim' | 'edm' | 'dmz' | 'edmSimple'; +type NATType = 'eim' | 'edm' | 'dmz'; // Constants for all util functions // Veth pairs (ends) @@ -951,121 +951,6 @@ async function setupNATEndpointDependentMapping( } } -/** - * Setup Port-Restricted Cone NAT for a namespace (on the router namespace) - */ -async function setupNATSimplifiedEDMAgent( - usrnsPid: number, - routerNsPid: number, - agentIp: string, - routerExt: string, - routerInt: string, - logger: Logger = new Logger(setupNATSimplifiedEDMAgent.name), -) { - const natCommand = [ - ...nsenter(usrnsPid, routerNsPid), - 'iptables', - '--table', - 'nat', - '--append', - 'POSTROUTING', - '--protocol', - 'udp', - '--source', - `${agentIp}${subnetMask}`, - '--out-interface', - routerExt, - '--jump', - 'MASQUERADE', - '--to-ports', - '44444', - ]; - const acceptLocalCommand = [ - ...nsenter(usrnsPid, routerNsPid), - 'iptables', - '--table', - 'filter', - '--append', - 'INPUT', - '--in-interface', - routerInt, - '--jump', - 'ACCEPT', - ]; - const acceptEstablishedCommand = [ - ...nsenter(usrnsPid, routerNsPid), - 'iptables', - '--table', - 'filter', - '--append', - 'INPUT', - '--match', - 'conntrack', - '--ctstate', - 'RELATED,ESTABLISHED', - '--jump', - 'ACCEPT', - ]; - const dropCommand = [ - ...nsenter(usrnsPid, routerNsPid), - 'iptables', - '--table', - 'filter', - '--append', - 'INPUT', - '--jump', - 'DROP', - ]; - try { - logger.info(['nsenter', ...acceptLocalCommand].join(' ')); - await testBinUtils.exec('nsenter', acceptLocalCommand); - logger.info(['nsenter', ...acceptEstablishedCommand].join(' ')); - await testBinUtils.exec('nsenter', acceptEstablishedCommand); - logger.info(['nsenter', ...dropCommand].join(' ')); - await testBinUtils.exec('nsenter', dropCommand); - logger.info(['nsenter', ...natCommand].join(' ')); - await testBinUtils.exec('nsenter', natCommand); - } catch (e) { - logger.error(e.message); - } -} - -/** - * Setup Port-Restricted Cone NAT for a namespace (on the router namespace) - */ -async function setupNATSimplifiedEDMSeed( - usrnsPid: number, - routerNsPid: number, - agentIp: string, - routerExt: string, - logger: Logger = new Logger(setupNATSimplifiedEDMSeed.name), -) { - const natCommand = [ - ...nsenter(usrnsPid, routerNsPid), - 'iptables', - '--table', - 'nat', - '--append', - 'POSTROUTING', - '--protocol', - 'udp', - '--source', - `${agentIp}${subnetMask}`, - '--out-interface', - routerExt, - '--jump', - 'MASQUERADE', - '--to-ports', - '55555', - ]; - try { - logger.info(['nsenter', ...natCommand].join(' ')); - await testBinUtils.exec('nsenter', natCommand); - } catch (e) { - logger.error(e.message); - } -} - async function setupNATWithSeedNode( agent1NAT: NATType, agent2NAT: NATType, @@ -1142,24 +1027,6 @@ async function setupNATWithSeedNode( ); break; } - case 'edmSimple': { - await setupNATSimplifiedEDMAgent( - usrns.pid!, - router1Netns.pid!, - agent1HostIp, - agent1RouterHostExt, - agent1RouterHostInt, - logger, - ); - await setupNATSimplifiedEDMSeed( - usrns.pid!, - router1Netns.pid!, - agent1HostIp, - router1SeedHost, - logger, - ); - break; - } } switch (agent2NAT) { case 'dmz': { @@ -1217,24 +1084,6 @@ async function setupNATWithSeedNode( ); break; } - case 'edmSimple': { - await setupNATSimplifiedEDMAgent( - usrns.pid!, - router2Netns.pid!, - agent2HostIp, - agent2RouterHostExt, - agent2RouterHostInt, - logger, - ); - await setupNATSimplifiedEDMSeed( - usrns.pid!, - router2Netns.pid!, - agent2HostIp, - router2SeedHost, - logger, - ); - break; - } } await setupNetworkNamespaceInterfaces( usrns.pid!, @@ -1451,17 +1300,6 @@ async function setupNAT( ); break; } - case 'edmSimple': { - await setupNATSimplifiedEDMAgent( - usrns.pid!, - router1Netns.pid!, - agent1HostIp, - agent1RouterHostExt, - agent1RouterHostInt, - logger, - ); - break; - } } switch (agent2NAT) { case 'dmz': { @@ -1496,17 +1334,6 @@ async function setupNAT( ); break; } - case 'edmSimple': { - await setupNATSimplifiedEDMAgent( - usrns.pid!, - router2Netns.pid!, - agent2HostIp, - agent2RouterHostExt, - agent2RouterHostInt, - logger, - ); - break; - } } await setupNetworkNamespaceInterfaces( usrns.pid!, @@ -1601,16 +1428,12 @@ async function setupNAT( agent1ProxyPort: agent1NAT === 'dmz' ? mappedPort - : agent1NAT === 'edmSimple' - ? '44444' : agent1Port, agent2NodeId: nodeId2, agent2Host: agent2RouterHostExtIp, agent2ProxyPort: agent2NAT === 'dmz' ? mappedPort - : agent2NAT === 'edmSimple' - ? '44444' : agent2Port, tearDownNAT: async () => { agent2.kill('SIGTERM'); From 9800c4abb58b64d4382abd116f8407ea54bd8da2 Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Wed, 22 Jun 2022 16:28:16 +1000 Subject: [PATCH 130/137] style: linting and other style fixes General linting, using capitals for constants in NAT utils, and lowercase test descriptions --- src/agent/service/nodesChainDataGet.ts | 3 +- .../service/nodesClosestLocalNodesGet.ts | 3 +- .../service/nodesHolePunchMessageSend.ts | 3 +- src/client/service/agentLockAll.ts | 3 +- src/client/service/agentStatus.ts | 3 +- src/client/service/agentStop.ts | 3 +- src/client/service/agentUnlock.ts | 3 +- .../service/gestaltsActionsGetByIdentity.ts | 3 +- .../service/gestaltsActionsGetByNode.ts | 3 +- .../service/gestaltsDiscoveryByIdentity.ts | 3 +- src/client/service/gestaltsDiscoveryByNode.ts | 3 +- .../service/gestaltsGestaltGetByIdentity.ts | 3 +- .../service/gestaltsGestaltGetByNode.ts | 3 +- src/client/service/gestaltsGestaltList.ts | 3 +- .../service/identitiesAuthenticatedGet.ts | 3 +- src/client/service/identitiesProvidersList.ts | 3 +- src/client/service/identitiesTokenDelete.ts | 3 +- src/client/service/identitiesTokenGet.ts | 3 +- src/client/service/identitiesTokenPut.ts | 3 +- src/client/service/keysCertsChainGet.ts | 3 +- src/client/service/keysCertsGet.ts | 3 +- src/client/service/keysDecrypt.ts | 3 +- src/client/service/keysEncrypt.ts | 3 +- src/client/service/keysKeyPairRenew.ts | 3 +- src/client/service/keysKeyPairReset.ts | 3 +- src/client/service/keysKeyPairRoot.ts | 3 +- src/client/service/keysPasswordChange.ts | 3 +- src/client/service/keysSign.ts | 3 +- src/client/service/keysVerify.ts | 3 +- src/client/service/nodesAdd.ts | 3 +- src/client/service/notificationsClear.ts | 3 +- src/client/service/notificationsRead.ts | 3 +- src/client/service/vaultsList.ts | 3 +- tests/nat/{noNAT.test.ts => DMZ.test.ts} | 24 +- tests/nat/endpointDependentNAT.test.ts | 32 +- tests/nat/endpointIndependentNAT.test.ts | 55 ++- tests/nat/utils.ts | 391 +++++++++++------- 37 files changed, 384 insertions(+), 217 deletions(-) rename tests/nat/{noNAT.test.ts => DMZ.test.ts} (94%) diff --git a/src/agent/service/nodesChainDataGet.ts b/src/agent/service/nodesChainDataGet.ts index 5d0f263ed..10175c706 100644 --- a/src/agent/service/nodesChainDataGet.ts +++ b/src/agent/service/nodesChainDataGet.ts @@ -51,7 +51,8 @@ function nodesChainDataGet({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - !agentUtils.isAgentClientError(e) && logger.error(`${nodesChainDataGet.name}:${e}`); + !agentUtils.isAgentClientError(e) && + logger.error(`${nodesChainDataGet.name}:${e}`); return; } }; diff --git a/src/agent/service/nodesClosestLocalNodesGet.ts b/src/agent/service/nodesClosestLocalNodesGet.ts index 9cb9f45f6..4c987667d 100644 --- a/src/agent/service/nodesClosestLocalNodesGet.ts +++ b/src/agent/service/nodesClosestLocalNodesGet.ts @@ -63,7 +63,8 @@ function nodesClosestLocalNodesGet({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - !agentUtils.isAgentClientError(e) && logger.error(`${nodesClosestLocalNodesGet.name}:${e}`); + !agentUtils.isAgentClientError(e) && + logger.error(`${nodesClosestLocalNodesGet.name}:${e}`); return; } }; diff --git a/src/agent/service/nodesHolePunchMessageSend.ts b/src/agent/service/nodesHolePunchMessageSend.ts index beafc3bd2..c610d7428 100644 --- a/src/agent/service/nodesHolePunchMessageSend.ts +++ b/src/agent/service/nodesHolePunchMessageSend.ts @@ -74,7 +74,8 @@ function nodesHolePunchMessageSend({ return; } catch (e) { callback(grpcUtils.fromError(e, true)); - !agentUtils.isAgentClientError(e) && logger.error(`${nodesHolePunchMessageSend.name}:${e}`); + !agentUtils.isAgentClientError(e) && + logger.error(`${nodesHolePunchMessageSend.name}:${e}`); return; } }; diff --git a/src/client/service/agentLockAll.ts b/src/client/service/agentLockAll.ts index 9bb315c8f..2c2c7505e 100644 --- a/src/client/service/agentLockAll.ts +++ b/src/client/service/agentLockAll.ts @@ -33,7 +33,8 @@ function agentLockAll({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${agentLockAll.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${agentLockAll.name}:${e}`); return; } }; diff --git a/src/client/service/agentStatus.ts b/src/client/service/agentStatus.ts index 4ddb3b316..3ebb00b5d 100644 --- a/src/client/service/agentStatus.ts +++ b/src/client/service/agentStatus.ts @@ -50,7 +50,8 @@ function agentStatus({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${agentStatus.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${agentStatus.name}:${e}`); return; } }; diff --git a/src/client/service/agentStop.ts b/src/client/service/agentStop.ts index e6a640d43..2332c732e 100644 --- a/src/client/service/agentStop.ts +++ b/src/client/service/agentStop.ts @@ -33,7 +33,8 @@ function agentStop({ callback(null, response); } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${agentStop.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${agentStop.name}:${e}`); return; } // Stop is called after GRPC resources are cleared diff --git a/src/client/service/agentUnlock.ts b/src/client/service/agentUnlock.ts index 0480ab097..991a51c9f 100644 --- a/src/client/service/agentUnlock.ts +++ b/src/client/service/agentUnlock.ts @@ -24,7 +24,8 @@ function agentUnlock({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${agentUnlock.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${agentUnlock.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsActionsGetByIdentity.ts b/src/client/service/gestaltsActionsGetByIdentity.ts index ec8e8e316..3375ed15d 100644 --- a/src/client/service/gestaltsActionsGetByIdentity.ts +++ b/src/client/service/gestaltsActionsGetByIdentity.ts @@ -63,7 +63,8 @@ function gestaltsActionsGetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${gestaltsActionsGetByIdentity.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${gestaltsActionsGetByIdentity.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsActionsGetByNode.ts b/src/client/service/gestaltsActionsGetByNode.ts index ba572d818..ea0e4298d 100644 --- a/src/client/service/gestaltsActionsGetByNode.ts +++ b/src/client/service/gestaltsActionsGetByNode.ts @@ -57,7 +57,8 @@ function gestaltsActionsGetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${gestaltsActionsGetByNode.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${gestaltsActionsGetByNode.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsDiscoveryByIdentity.ts b/src/client/service/gestaltsDiscoveryByIdentity.ts index 18bcb2ee8..08f2df64e 100644 --- a/src/client/service/gestaltsDiscoveryByIdentity.ts +++ b/src/client/service/gestaltsDiscoveryByIdentity.ts @@ -52,7 +52,8 @@ function gestaltsDiscoveryByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${gestaltsDiscoveryByIdentity.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${gestaltsDiscoveryByIdentity.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsDiscoveryByNode.ts b/src/client/service/gestaltsDiscoveryByNode.ts index 0584e55c3..f6ed454b0 100644 --- a/src/client/service/gestaltsDiscoveryByNode.ts +++ b/src/client/service/gestaltsDiscoveryByNode.ts @@ -48,7 +48,8 @@ function gestaltsDiscoveryByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${gestaltsDiscoveryByNode.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${gestaltsDiscoveryByNode.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsGestaltGetByIdentity.ts b/src/client/service/gestaltsGestaltGetByIdentity.ts index b81df554d..8768ad136 100644 --- a/src/client/service/gestaltsGestaltGetByIdentity.ts +++ b/src/client/service/gestaltsGestaltGetByIdentity.ts @@ -60,7 +60,8 @@ function gestaltsGestaltGetByIdentity({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${gestaltsGestaltGetByIdentity.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${gestaltsGestaltGetByIdentity.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsGestaltGetByNode.ts b/src/client/service/gestaltsGestaltGetByNode.ts index 48aff4729..207859fb5 100644 --- a/src/client/service/gestaltsGestaltGetByNode.ts +++ b/src/client/service/gestaltsGestaltGetByNode.ts @@ -56,7 +56,8 @@ function gestaltsGestaltGetByNode({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${gestaltsGestaltGetByNode.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${gestaltsGestaltGetByNode.name}:${e}`); return; } }; diff --git a/src/client/service/gestaltsGestaltList.ts b/src/client/service/gestaltsGestaltList.ts index c5d49123c..d07fb9f32 100644 --- a/src/client/service/gestaltsGestaltList.ts +++ b/src/client/service/gestaltsGestaltList.ts @@ -40,7 +40,8 @@ function gestaltsGestaltList({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientClientError(e) && logger.error(`${gestaltsGestaltList.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${gestaltsGestaltList.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesAuthenticatedGet.ts b/src/client/service/identitiesAuthenticatedGet.ts index cae567830..106a1f53a 100644 --- a/src/client/service/identitiesAuthenticatedGet.ts +++ b/src/client/service/identitiesAuthenticatedGet.ts @@ -64,7 +64,8 @@ function identitiesAuthenticatedGet({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientClientError(e) && logger.error(`${identitiesAuthenticatedGet.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${identitiesAuthenticatedGet.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesProvidersList.ts b/src/client/service/identitiesProvidersList.ts index 752d9eea5..17ae7bf31 100644 --- a/src/client/service/identitiesProvidersList.ts +++ b/src/client/service/identitiesProvidersList.ts @@ -30,7 +30,8 @@ function identitiesProvidersList({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${identitiesProvidersList.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${identitiesProvidersList.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesTokenDelete.ts b/src/client/service/identitiesTokenDelete.ts index 3bf584d8d..2b4a78b9b 100644 --- a/src/client/service/identitiesTokenDelete.ts +++ b/src/client/service/identitiesTokenDelete.ts @@ -57,7 +57,8 @@ function identitiesTokenDelete({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${identitiesTokenDelete.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${identitiesTokenDelete.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesTokenGet.ts b/src/client/service/identitiesTokenGet.ts index 41872941e..c829da281 100644 --- a/src/client/service/identitiesTokenGet.ts +++ b/src/client/service/identitiesTokenGet.ts @@ -57,7 +57,8 @@ function identitiesTokenGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${identitiesTokenGet.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${identitiesTokenGet.name}:${e}`); return; } }; diff --git a/src/client/service/identitiesTokenPut.ts b/src/client/service/identitiesTokenPut.ts index d8a19ed9e..b7ae0139f 100644 --- a/src/client/service/identitiesTokenPut.ts +++ b/src/client/service/identitiesTokenPut.ts @@ -67,7 +67,8 @@ function identitiesTokenPut({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${identitiesTokenPut.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${identitiesTokenPut.name}:${e}`); return; } }; diff --git a/src/client/service/keysCertsChainGet.ts b/src/client/service/keysCertsChainGet.ts index fabb933d4..fc074a239 100644 --- a/src/client/service/keysCertsChainGet.ts +++ b/src/client/service/keysCertsChainGet.ts @@ -34,7 +34,8 @@ function keysCertsChainGet({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientClientError(e) && logger.error(`${keysCertsChainGet.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${keysCertsChainGet.name}:${e}`); return; } }; diff --git a/src/client/service/keysCertsGet.ts b/src/client/service/keysCertsGet.ts index 2b89ddb34..ff5e3d525 100644 --- a/src/client/service/keysCertsGet.ts +++ b/src/client/service/keysCertsGet.ts @@ -30,7 +30,8 @@ function keysCertsGet({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${keysCertsGet.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${keysCertsGet.name}:${e}`); return; } }; diff --git a/src/client/service/keysDecrypt.ts b/src/client/service/keysDecrypt.ts index fcd95f2ae..c155c0d8d 100644 --- a/src/client/service/keysDecrypt.ts +++ b/src/client/service/keysDecrypt.ts @@ -31,7 +31,8 @@ function keysDecrypt({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${keysDecrypt.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${keysDecrypt.name}:${e}`); return; } }; diff --git a/src/client/service/keysEncrypt.ts b/src/client/service/keysEncrypt.ts index 9c9264dc6..71a5a84ff 100644 --- a/src/client/service/keysEncrypt.ts +++ b/src/client/service/keysEncrypt.ts @@ -31,7 +31,8 @@ function keysEncrypt({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${keysEncrypt.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${keysEncrypt.name}:${e}`); return; } }; diff --git a/src/client/service/keysKeyPairRenew.ts b/src/client/service/keysKeyPairRenew.ts index 89d03fd51..a44df0628 100644 --- a/src/client/service/keysKeyPairRenew.ts +++ b/src/client/service/keysKeyPairRenew.ts @@ -31,7 +31,8 @@ function keysKeyPairRenew({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${keysKeyPairRenew.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${keysKeyPairRenew.name}:${e}`); return; } }; diff --git a/src/client/service/keysKeyPairReset.ts b/src/client/service/keysKeyPairReset.ts index 3f0b7bf33..a1ba20365 100644 --- a/src/client/service/keysKeyPairReset.ts +++ b/src/client/service/keysKeyPairReset.ts @@ -31,7 +31,8 @@ function keysKeyPairReset({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${keysKeyPairReset.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${keysKeyPairReset.name}:${e}`); return; } }; diff --git a/src/client/service/keysKeyPairRoot.ts b/src/client/service/keysKeyPairRoot.ts index 8da9aa3b8..2b1cdce82 100644 --- a/src/client/service/keysKeyPairRoot.ts +++ b/src/client/service/keysKeyPairRoot.ts @@ -31,7 +31,8 @@ function keysKeyPairRoot({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${keysKeyPairRoot.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${keysKeyPairRoot.name}:${e}`); return; } }; diff --git a/src/client/service/keysPasswordChange.ts b/src/client/service/keysPasswordChange.ts index d94a650ed..a7f4ed029 100644 --- a/src/client/service/keysPasswordChange.ts +++ b/src/client/service/keysPasswordChange.ts @@ -29,7 +29,8 @@ function keysPasswordChange({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${keysPasswordChange.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${keysPasswordChange.name}:${e}`); return; } }; diff --git a/src/client/service/keysSign.ts b/src/client/service/keysSign.ts index 77d2d4d34..126d0c149 100644 --- a/src/client/service/keysSign.ts +++ b/src/client/service/keysSign.ts @@ -32,7 +32,8 @@ function keysSign({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${keysSign.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${keysSign.name}:${e}`); return; } }; diff --git a/src/client/service/keysVerify.ts b/src/client/service/keysVerify.ts index 6e7cee48e..d2c82bfba 100644 --- a/src/client/service/keysVerify.ts +++ b/src/client/service/keysVerify.ts @@ -33,7 +33,8 @@ function keysVerify({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${keysVerify.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${keysVerify.name}:${e}`); return; } }; diff --git a/src/client/service/nodesAdd.ts b/src/client/service/nodesAdd.ts index c5c1b8949..92de5581d 100644 --- a/src/client/service/nodesAdd.ts +++ b/src/client/service/nodesAdd.ts @@ -89,7 +89,8 @@ function nodesAdd({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${nodesAdd.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${nodesAdd.name}:${e}`); return; } }; diff --git a/src/client/service/notificationsClear.ts b/src/client/service/notificationsClear.ts index dbbfc761a..ebcea2af0 100644 --- a/src/client/service/notificationsClear.ts +++ b/src/client/service/notificationsClear.ts @@ -33,7 +33,8 @@ function notificationsClear({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${notificationsClear.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${notificationsClear.name}:${e}`); return; } }; diff --git a/src/client/service/notificationsRead.ts b/src/client/service/notificationsRead.ts index 051f517c8..f706b5bd2 100644 --- a/src/client/service/notificationsRead.ts +++ b/src/client/service/notificationsRead.ts @@ -75,7 +75,8 @@ function notificationsRead({ return; } catch (e) { callback(grpcUtils.fromError(e)); - !clientUtils.isClientClientError(e) && logger.error(`${notificationsRead.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${notificationsRead.name}:${e}`); return; } }; diff --git a/src/client/service/vaultsList.ts b/src/client/service/vaultsList.ts index f8c6a92fb..c7d3da737 100644 --- a/src/client/service/vaultsList.ts +++ b/src/client/service/vaultsList.ts @@ -40,7 +40,8 @@ function vaultsList({ return; } catch (e) { await genWritable.throw(e); - !clientUtils.isClientClientError(e) && logger.error(`${vaultsList.name}:${e}`); + !clientUtils.isClientClientError(e) && + logger.error(`${vaultsList.name}:${e}`); return; } }; diff --git a/tests/nat/noNAT.test.ts b/tests/nat/DMZ.test.ts similarity index 94% rename from tests/nat/noNAT.test.ts rename to tests/nat/DMZ.test.ts index 0690261bb..9f78ffd56 100644 --- a/tests/nat/noNAT.test.ts +++ b/tests/nat/DMZ.test.ts @@ -17,11 +17,9 @@ describeIf( shell.which('iptables') && shell.which('nsenter') && shell.which('unshare'), - 'no NAT', + 'DMZ', () => { - const logger = new Logger('no NAT test', LogLevel.WARN, [ - new StreamHandler(), - ]); + const logger = new Logger('DMZ test', LogLevel.WARN, [new StreamHandler()]); let dataDir: string; beforeEach(async () => { dataDir = await fs.promises.mkdtemp( @@ -142,7 +140,14 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort, '--no-ping'], + [ + 'nodes', + 'add', + agent2NodeId, + agent2Host, + agent2ProxyPort, + '--no-ping', + ], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -152,7 +157,14 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort, '--no-ping'], + [ + 'nodes', + 'add', + agent1NodeId, + agent1Host, + agent1ProxyPort, + '--no-ping', + ], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, diff --git a/tests/nat/endpointDependentNAT.test.ts b/tests/nat/endpointDependentNAT.test.ts index 432796226..c815f6d6b 100644 --- a/tests/nat/endpointDependentNAT.test.ts +++ b/tests/nat/endpointDependentNAT.test.ts @@ -31,7 +31,7 @@ describeIf( }); }); test( - 'Node1 behind EDM NAT connects to Node2', + 'node1 behind EDM NAT connects to node2', async () => { const { userPid, @@ -48,7 +48,14 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort, '--no-ping'], + [ + 'nodes', + 'add', + agent2NodeId, + agent2Host, + agent2ProxyPort, + '--no-ping', + ], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -75,7 +82,7 @@ describeIf( global.defaultTimeout * 2, ); test( - 'Node1 connects to Node2 behind EDM NAT', + 'node1 connects to node2 behind EDM NAT', async () => { const { userPid, @@ -95,7 +102,14 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort, '--no-ping'], + [ + 'nodes', + 'add', + agent1NodeId, + agent1Host, + agent1ProxyPort, + '--no-ping', + ], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, @@ -139,7 +153,7 @@ describeIf( global.defaultTimeout * 2, ); test( - 'Node1 behind EDM NAT cannot connect to Node2 behind EDM NAT', + 'node1 behind EDM NAT cannot connect to node2 behind EDM NAT', async () => { const { userPid, @@ -152,11 +166,7 @@ describeIf( agent1NodeId, agent2NodeId, tearDownNAT, - } = await testNatUtils.setupNATWithSeedNode( - 'edm', - 'edm', - logger, - ); + } = await testNatUtils.setupNATWithSeedNode('edm', 'edm', logger); // Contact details are retrieved from the seed node, but cannot be used // since port mapping changes between targets in EDM mapping // Node 2 -> Node 1 ping should fail (Node 1 behind NAT) @@ -197,7 +207,7 @@ describeIf( global.defaultTimeout * 2, ); test( - 'Node1 behind EDM NAT cannot connect to Node2 behind EIM NAT', + 'node1 behind EDM NAT cannot connect to node2 behind EIM NAT', async () => { const { userPid, diff --git a/tests/nat/endpointIndependentNAT.test.ts b/tests/nat/endpointIndependentNAT.test.ts index f6023010a..9bdbf2abd 100644 --- a/tests/nat/endpointIndependentNAT.test.ts +++ b/tests/nat/endpointIndependentNAT.test.ts @@ -31,7 +31,7 @@ describeIf( }); }); test( - 'Node1 behind EIM NAT connects to Node2', + 'node1 behind EIM NAT connects to node2', async () => { const { userPid, @@ -48,7 +48,14 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort, '--no-ping'], + [ + 'nodes', + 'add', + agent2NodeId, + agent2Host, + agent2ProxyPort, + '--no-ping', + ], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -75,7 +82,7 @@ describeIf( global.defaultTimeout * 2, ); test( - 'Node1 connects to Node2 behind EIM NAT', + 'node1 connects to node2 behind EIM NAT', async () => { const { userPid, @@ -96,7 +103,14 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort, '--no-ping'], + [ + 'nodes', + 'add', + agent1NodeId, + agent1Host, + agent1ProxyPort, + '--no-ping', + ], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, @@ -106,7 +120,14 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort, '--no-ping'], + [ + 'nodes', + 'add', + agent2NodeId, + agent2Host, + agent2ProxyPort, + '--no-ping', + ], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -167,7 +188,7 @@ describeIf( global.defaultTimeout * 2, ); test( - 'Node1 behind EIM NAT connects to Node2 behind EIM NAT', + 'node1 behind EIM NAT connects to node2 behind EIM NAT', async () => { const { userPid, @@ -188,7 +209,14 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'add', agent1NodeId, agent1Host, agent1ProxyPort, '--no-ping'], + [ + 'nodes', + 'add', + agent1NodeId, + agent1Host, + agent1ProxyPort, + '--no-ping', + ], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, @@ -198,7 +226,14 @@ describeIf( await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'add', agent2NodeId, agent2Host, agent2ProxyPort, '--no-ping'], + [ + 'nodes', + 'add', + agent2NodeId, + agent2Host, + agent2ProxyPort, + '--no-ping', + ], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -259,7 +294,7 @@ describeIf( global.defaultTimeout * 2, ); test( - 'Node1 behind EIM NAT connects to Node2 behind EIM NAT via seed node', + 'node1 behind EIM NAT connects to node2 behind EIM NAT via seed node', async () => { const { userPid, @@ -311,7 +346,7 @@ describeIf( global.defaultTimeout * 2, ); test( - 'Node1 behind EIM NAT cannot connect to Node2 behind EDM NAT', + 'node1 behind EIM NAT cannot connect to node2 behind EDM NAT', async () => { const { userPid, diff --git a/tests/nat/utils.ts b/tests/nat/utils.ts index c2efe6b25..4509ebacc 100644 --- a/tests/nat/utils.ts +++ b/tests/nat/utils.ts @@ -10,34 +10,117 @@ import * as testBinUtils from '../bin/utils'; type NATType = 'eim' | 'edm' | 'dmz'; -// Constants for all util functions -// Veth pairs (ends) -const agent1Host = 'agent1'; -const agent2Host = 'agent2'; -const agent1RouterHostInt = 'router1-int'; -const agent1RouterHostExt = 'router1-ext'; -const agent2RouterHostInt = 'router2-int'; -const agent2RouterHostExt = 'router2-ext'; -const router1SeedHost = 'router1-seed'; -const router2SeedHost = 'router2-seed'; -const seedRouter1Host = 'seed-router1'; -const seedRouter2Host = 'seed-router2'; -// Subnets -const agent1HostIp = '10.0.0.2'; -const agent2HostIp = '10.0.0.2'; -const agent1RouterHostIntIp = '10.0.0.1'; -const agent2RouterHostIntIp = '10.0.0.1'; -const agent1RouterHostExtIp = '192.168.0.1'; -const agent2RouterHostExtIp = '192.168.0.2'; -const router1SeedHostIp = '192.168.0.1'; -const seedHostIp = '192.168.0.3'; -const router2SeedHostIp = '192.168.0.2'; -// Subnet mask -const subnetMask = '/24'; -// Ports -const agent1Port = '55551'; -const agent2Port = '55552'; -const mappedPort = '55555'; +/** + * Veth end for Agent 1 + * Connects to Router 1 + */ +const AGENT1_VETH = 'agent1'; +/** + * Veth end for Agent 2 + * Connects to Router 2 + */ +const AGENT2_VETH = 'agent2'; +/** + * Internal veth end for Router 1 + * Connects to Agent 1 + */ +const ROUTER1_VETH_INT = 'router1-int'; +/** + * External veth end for Router 1 + * Connects to Router 2 + */ +const ROUTER1_VETH_EXT = 'router1-ext'; +/** + * Internal veth end for Router 2 + * Connects to Agent 2 + */ +const ROUTER2_VETH_INT = 'router2-int'; +/** + * External veth end for Router 2 + * Connects to Router 1 + */ +const ROUTER2_VETH_EXT = 'router2-ext'; +/** + * External veth end for Router 1 + * Connects to a seed node + */ +const ROUTER1_VETH_SEED = 'router1-seed'; +/** + * External veth end for Router 2 + * Connects to a seed node + */ +const ROUTER2_VETH_SEED = 'router2-seed'; +/** + * Veth end for a seed node + * Connects to Router 1 + */ +const SEED_VETH_ROUTER1 = 'seed-router1'; +/** + * Veth end for a seed node + * Connects to Router 2 + */ +const SEED_VETH_ROUTER2 = 'seed-router2'; + +/** + * Subnet for Agent 1 + */ +const AGENT1_HOST = '10.0.0.2'; +/** + * Subnet for Agent 2 + */ +const AGENT2_HOST = '10.0.0.2'; +/** + * Subnet for internal communication from Router 1 + * Forwards to Agent 1 + */ +const ROUTER1_HOST_INT = '10.0.0.1'; +/** + * Subnet for internal communication from Router 2 + * Forwards to Agent 2 + */ +const ROUTER2_HOST_INT = '10.0.0.1'; +/** + * Subnet for external communication from Router 1 + * Forwards to Router 2 + */ +const ROUTER1_HOST_EXT = '192.168.0.1'; +/** + * Subnet for external communication from Router 2 + * Forwards to Router 1 + */ +const ROUTER2_HOST_EXT = '192.168.0.2'; +/** + * Subnet for external communication from Router 1 + * Forwards to a seed node + */ +const ROUTER1_HOST_SEED = '192.168.0.1'; +/** + * Subnet for external communication from a seed node + */ +const SEED_HOST = '192.168.0.3'; +/** + * Subnet for external communication from Router 2 + * Forwards to a seed node + */ +const ROUTER2_HOST_SEED = '192.168.0.2'; + +/** + * Subnet mask + */ +const SUBNET_MASK = '/24'; + +/** + * Port on Agent 1 + */ +const AGENT1_PORT = '55551'; +/** + * Port on Agent 2 + */ +const AGENT2_PORT = '55552'; +/** + * Mapped port for DMZ + */ +const DMZ_PORT = '55555'; /** * Formats the command to enter a namespace to run a process inside it @@ -172,12 +255,12 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'link', 'add', - agent1Host, + AGENT1_VETH, 'type', 'veth', 'peer', 'name', - agent1RouterHostInt, + ROUTER1_VETH_INT, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -186,12 +269,12 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'link', 'add', - agent1RouterHostExt, + ROUTER1_VETH_EXT, 'type', 'veth', 'peer', 'name', - agent2RouterHostExt, + ROUTER2_VETH_EXT, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -200,12 +283,12 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'link', 'add', - agent2RouterHostInt, + ROUTER2_VETH_INT, 'type', 'veth', 'peer', 'name', - agent2Host, + AGENT2_VETH, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -216,7 +299,7 @@ async function setupNetworkNamespaceInterfaces( 'link', 'set', 'dev', - agent1RouterHostInt, + ROUTER1_VETH_INT, 'netns', router1NetnsPid.toString(), ]; @@ -228,7 +311,7 @@ async function setupNetworkNamespaceInterfaces( 'link', 'set', 'dev', - agent2RouterHostExt, + ROUTER2_VETH_EXT, 'netns', router2NetnsPid.toString(), ]; @@ -240,7 +323,7 @@ async function setupNetworkNamespaceInterfaces( 'link', 'set', 'dev', - agent2Host, + AGENT2_VETH, 'netns', agent2NetnsPid.toString(), ]; @@ -252,7 +335,7 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'link', 'set', - agent1Host, + AGENT1_VETH, 'up', ]; logger.info(['nsenter', ...args].join(' ')); @@ -262,7 +345,7 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'link', 'set', - agent1RouterHostInt, + ROUTER1_VETH_INT, 'up', ]; logger.info(['nsenter', ...args].join(' ')); @@ -272,7 +355,7 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'link', 'set', - agent1RouterHostExt, + ROUTER1_VETH_EXT, 'up', ]; logger.info(['nsenter', ...args].join(' ')); @@ -282,7 +365,7 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'link', 'set', - agent2RouterHostExt, + ROUTER2_VETH_EXT, 'up', ]; logger.info(['nsenter', ...args].join(' ')); @@ -292,7 +375,7 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'link', 'set', - agent2RouterHostInt, + ROUTER2_VETH_INT, 'up', ]; logger.info(['nsenter', ...args].join(' ')); @@ -302,7 +385,7 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'link', 'set', - agent2Host, + AGENT2_VETH, 'up', ]; logger.info(['nsenter', ...args].join(' ')); @@ -313,9 +396,9 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'addr', 'add', - `${agent1HostIp}${subnetMask}`, + `${AGENT1_HOST}${SUBNET_MASK}`, 'dev', - agent1Host, + AGENT1_VETH, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -324,9 +407,9 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'addr', 'add', - `${agent1RouterHostIntIp}${subnetMask}`, + `${ROUTER1_HOST_INT}${SUBNET_MASK}`, 'dev', - agent1RouterHostInt, + ROUTER1_VETH_INT, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -335,9 +418,9 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'addr', 'add', - `${agent1RouterHostExtIp}${subnetMask}`, + `${ROUTER1_HOST_EXT}${SUBNET_MASK}`, 'dev', - agent1RouterHostExt, + ROUTER1_VETH_EXT, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -346,9 +429,9 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'addr', 'add', - `${agent2RouterHostExtIp}${subnetMask}`, + `${ROUTER2_HOST_EXT}${SUBNET_MASK}`, 'dev', - agent2RouterHostExt, + ROUTER2_VETH_EXT, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -357,9 +440,9 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'addr', 'add', - `${agent2RouterHostIntIp}${subnetMask}`, + `${ROUTER2_HOST_INT}${SUBNET_MASK}`, 'dev', - agent2RouterHostInt, + ROUTER2_VETH_INT, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -368,9 +451,9 @@ async function setupNetworkNamespaceInterfaces( 'ip', 'addr', 'add', - `${agent2HostIp}${subnetMask}`, + `${AGENT2_HOST}${SUBNET_MASK}`, 'dev', - agent2Host, + AGENT2_VETH, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -382,7 +465,7 @@ async function setupNetworkNamespaceInterfaces( 'add', 'default', 'via', - agent1RouterHostIntIp, + ROUTER1_HOST_INT, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -393,7 +476,7 @@ async function setupNetworkNamespaceInterfaces( 'add', 'default', 'via', - agent2RouterHostExtIp, + ROUTER2_HOST_EXT, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -404,7 +487,7 @@ async function setupNetworkNamespaceInterfaces( 'add', 'default', 'via', - agent1RouterHostExtIp, + ROUTER1_HOST_EXT, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -415,7 +498,7 @@ async function setupNetworkNamespaceInterfaces( 'add', 'default', 'via', - agent2RouterHostIntIp, + ROUTER2_HOST_INT, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -457,12 +540,12 @@ async function setupSeedNamespaceInterfaces( 'ip', 'link', 'add', - router1SeedHost, + ROUTER1_VETH_SEED, 'type', 'veth', 'peer', 'name', - seedRouter1Host, + SEED_VETH_ROUTER1, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -471,12 +554,12 @@ async function setupSeedNamespaceInterfaces( 'ip', 'link', 'add', - router2SeedHost, + ROUTER2_VETH_SEED, 'type', 'veth', 'peer', 'name', - seedRouter2Host, + SEED_VETH_ROUTER2, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -487,7 +570,7 @@ async function setupSeedNamespaceInterfaces( 'link', 'set', 'dev', - seedRouter1Host, + SEED_VETH_ROUTER1, 'netns', seedNetnsPid.toString(), ]; @@ -499,7 +582,7 @@ async function setupSeedNamespaceInterfaces( 'link', 'set', 'dev', - seedRouter2Host, + SEED_VETH_ROUTER2, 'netns', seedNetnsPid.toString(), ]; @@ -511,7 +594,7 @@ async function setupSeedNamespaceInterfaces( 'ip', 'link', 'set', - router1SeedHost, + ROUTER1_VETH_SEED, 'up', ]; logger.info(['nsenter', ...args].join(' ')); @@ -521,7 +604,7 @@ async function setupSeedNamespaceInterfaces( 'ip', 'link', 'set', - seedRouter1Host, + SEED_VETH_ROUTER1, 'up', ]; logger.info(['nsenter', ...args].join(' ')); @@ -531,7 +614,7 @@ async function setupSeedNamespaceInterfaces( 'ip', 'link', 'set', - seedRouter2Host, + SEED_VETH_ROUTER2, 'up', ]; logger.info(['nsenter', ...args].join(' ')); @@ -541,7 +624,7 @@ async function setupSeedNamespaceInterfaces( 'ip', 'link', 'set', - router2SeedHost, + ROUTER2_VETH_SEED, 'up', ]; logger.info(['nsenter', ...args].join(' ')); @@ -552,9 +635,9 @@ async function setupSeedNamespaceInterfaces( 'ip', 'addr', 'add', - `${router1SeedHostIp}${subnetMask}`, + `${ROUTER1_HOST_SEED}${SUBNET_MASK}`, 'dev', - router1SeedHost, + ROUTER1_VETH_SEED, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -563,9 +646,9 @@ async function setupSeedNamespaceInterfaces( 'ip', 'addr', 'add', - `${seedHostIp}${subnetMask}`, + `${SEED_HOST}${SUBNET_MASK}`, 'dev', - seedRouter1Host, + SEED_VETH_ROUTER1, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -574,9 +657,9 @@ async function setupSeedNamespaceInterfaces( 'ip', 'addr', 'add', - `${seedHostIp}${subnetMask}`, + `${SEED_HOST}${SUBNET_MASK}`, 'dev', - seedRouter2Host, + SEED_VETH_ROUTER2, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -585,9 +668,9 @@ async function setupSeedNamespaceInterfaces( 'ip', 'addr', 'add', - `${router2SeedHostIp}${subnetMask}`, + `${ROUTER2_HOST_SEED}${SUBNET_MASK}`, 'dev', - router2SeedHost, + ROUTER2_VETH_SEED, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -597,9 +680,9 @@ async function setupSeedNamespaceInterfaces( 'ip', 'route', 'add', - seedHostIp, + SEED_HOST, 'dev', - router1SeedHost, + ROUTER1_VETH_SEED, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -608,9 +691,9 @@ async function setupSeedNamespaceInterfaces( 'ip', 'route', 'add', - seedHostIp, + SEED_HOST, 'dev', - router2SeedHost, + ROUTER2_VETH_SEED, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -619,9 +702,9 @@ async function setupSeedNamespaceInterfaces( 'ip', 'route', 'add', - router1SeedHostIp, + ROUTER1_HOST_SEED, 'dev', - seedRouter1Host, + SEED_VETH_ROUTER1, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -630,9 +713,9 @@ async function setupSeedNamespaceInterfaces( 'ip', 'route', 'add', - router2SeedHostIp, + ROUTER2_HOST_SEED, 'dev', - seedRouter2Host, + SEED_VETH_ROUTER2, ]; logger.info(['nsenter', ...args].join(' ')); await testBinUtils.exec('nsenter', args); @@ -806,13 +889,13 @@ async function setupDMZ( '--protocol', 'udp', '--source', - `${agentIp}${subnetMask}`, + `${agentIp}${SUBNET_MASK}`, '--out-interface', routerExt, '--jump', 'SNAT', '--to-source', - `${routerExtIp}:${mappedPort}`, + `${routerExtIp}:${DMZ_PORT}`, ]; const preroutingCommand = [ ...nsenter(usrnsPid, routerNsPid), @@ -824,7 +907,7 @@ async function setupDMZ( '--protocol', 'udp', '--destination-port', - mappedPort, + DMZ_PORT, '--in-interface', routerExt, '--jump', @@ -863,7 +946,7 @@ async function setupNATEndpointIndependentMapping( '--protocol', 'udp', '--source', - `${agentIp}${subnetMask}`, + `${agentIp}${SUBNET_MASK}`, '--out-interface', routerExt, '--jump', @@ -976,19 +1059,19 @@ async function setupNATWithSeedNode( await setupDMZ( usrns.pid!, router1Netns.pid!, - agent1HostIp, - agent1Port, - agent1RouterHostExt, - agent1RouterHostExtIp, + AGENT1_HOST, + AGENT1_PORT, + ROUTER1_VETH_EXT, + ROUTER1_HOST_EXT, logger, ); await setupDMZ( usrns.pid!, router1Netns.pid!, - agent1HostIp, - agent1Port, - router1SeedHost, - router1SeedHostIp, + AGENT1_HOST, + AGENT1_PORT, + ROUTER1_VETH_SEED, + ROUTER1_HOST_SEED, logger, ); break; @@ -997,17 +1080,17 @@ async function setupNATWithSeedNode( await setupNATEndpointIndependentMapping( usrns.pid!, router1Netns.pid!, - agent1HostIp, - agent1RouterHostExt, - agent1RouterHostInt, + AGENT1_HOST, + ROUTER1_VETH_EXT, + ROUTER1_VETH_INT, logger, ); await setupNATEndpointIndependentMapping( usrns.pid!, router1Netns.pid!, - agent1HostIp, - router1SeedHost, - agent1RouterHostInt, + AGENT1_HOST, + ROUTER1_VETH_SEED, + ROUTER1_VETH_INT, logger, ); break; @@ -1016,13 +1099,13 @@ async function setupNATWithSeedNode( await setupNATEndpointDependentMapping( usrns.pid!, router1Netns.pid!, - agent1RouterHostExt, + ROUTER1_VETH_EXT, logger, ); await setupNATEndpointDependentMapping( usrns.pid!, router1Netns.pid!, - router1SeedHost, + ROUTER1_VETH_SEED, logger, ); break; @@ -1033,19 +1116,19 @@ async function setupNATWithSeedNode( await setupDMZ( usrns.pid!, router2Netns.pid!, - agent2HostIp, - agent2Port, - agent2RouterHostExt, - agent2RouterHostExtIp, + AGENT2_HOST, + AGENT2_PORT, + ROUTER2_VETH_EXT, + ROUTER2_HOST_EXT, logger, ); await setupDMZ( usrns.pid!, router2Netns.pid!, - agent2HostIp, - agent2Port, - router2SeedHost, - router2SeedHostIp, + AGENT2_HOST, + AGENT2_PORT, + ROUTER2_VETH_SEED, + ROUTER2_HOST_SEED, logger, ); break; @@ -1054,17 +1137,17 @@ async function setupNATWithSeedNode( await setupNATEndpointIndependentMapping( usrns.pid!, router2Netns.pid!, - agent2HostIp, - agent2RouterHostExt, - agent2RouterHostInt, + AGENT2_HOST, + ROUTER2_VETH_EXT, + ROUTER2_VETH_INT, logger, ); await setupNATEndpointIndependentMapping( usrns.pid!, router2Netns.pid!, - agent2HostIp, - router2SeedHost, - agent2RouterHostInt, + AGENT2_HOST, + ROUTER2_VETH_SEED, + ROUTER2_VETH_INT, logger, ); break; @@ -1073,13 +1156,13 @@ async function setupNATWithSeedNode( await setupNATEndpointDependentMapping( usrns.pid!, router2Netns.pid!, - agent2RouterHostExt, + ROUTER2_VETH_EXT, logger, ); await setupNATEndpointDependentMapping( usrns.pid!, router2Netns.pid!, - router2SeedHost, + ROUTER2_VETH_SEED, logger, ); break; @@ -1148,15 +1231,15 @@ async function setupNATWithSeedNode( '--client-host', '127.0.0.1', '--proxy-host', - `${agent1HostIp}`, + `${AGENT1_HOST}`, '--proxy-port', - `${agent1Port}`, + `${AGENT1_PORT}`, '--workers', '0', '--connection-timeout', '1000', '--seed-nodes', - `${nodeIdSeed}@${seedHostIp}:${proxyPortSeed}`, + `${nodeIdSeed}@${SEED_HOST}:${proxyPortSeed}`, '--verbose', '--format', 'json', @@ -1186,15 +1269,15 @@ async function setupNATWithSeedNode( '--client-host', '127.0.0.1', '--proxy-host', - `${agent2HostIp}`, + `${AGENT2_HOST}`, '--proxy-port', - `${agent2Port}`, + `${AGENT2_PORT}`, '--workers', '0', '--connection-timeout', '1000', '--seed-nodes', - `${nodeIdSeed}@${seedHostIp}:${proxyPortSeed}`, + `${nodeIdSeed}@${SEED_HOST}:${proxyPortSeed}`, '--verbose', '--format', 'json', @@ -1272,10 +1355,10 @@ async function setupNAT( await setupDMZ( usrns.pid!, router1Netns.pid!, - agent1HostIp, - agent1Port, - agent1RouterHostExt, - agent1RouterHostExtIp, + AGENT1_HOST, + AGENT1_PORT, + ROUTER1_VETH_EXT, + ROUTER1_HOST_EXT, logger, ); break; @@ -1284,9 +1367,9 @@ async function setupNAT( await setupNATEndpointIndependentMapping( usrns.pid!, router1Netns.pid!, - agent1HostIp, - agent1RouterHostExt, - agent1RouterHostInt, + AGENT1_HOST, + ROUTER1_VETH_EXT, + ROUTER1_VETH_INT, logger, ); break; @@ -1295,7 +1378,7 @@ async function setupNAT( await setupNATEndpointDependentMapping( usrns.pid!, router1Netns.pid!, - agent1RouterHostExt, + ROUTER1_VETH_EXT, logger, ); break; @@ -1306,10 +1389,10 @@ async function setupNAT( await setupDMZ( usrns.pid!, router2Netns.pid!, - agent2HostIp, - agent2Port, - agent2RouterHostExt, - agent2RouterHostExtIp, + AGENT2_HOST, + AGENT2_PORT, + ROUTER2_VETH_EXT, + ROUTER2_HOST_EXT, logger, ); break; @@ -1318,9 +1401,9 @@ async function setupNAT( await setupNATEndpointIndependentMapping( usrns.pid!, router2Netns.pid!, - agent2HostIp, - agent2RouterHostExt, - agent2RouterHostInt, + AGENT2_HOST, + ROUTER2_VETH_EXT, + ROUTER2_VETH_INT, logger, ); break; @@ -1329,7 +1412,7 @@ async function setupNAT( await setupNATEndpointDependentMapping( usrns.pid!, router2Netns.pid!, - agent2RouterHostExt, + ROUTER2_VETH_EXT, logger, ); break; @@ -1356,9 +1439,9 @@ async function setupNAT( '--client-host', '127.0.0.1', '--proxy-host', - `${agent1HostIp}`, + `${AGENT1_HOST}`, '--proxy-port', - `${agent1Port}`, + `${AGENT1_PORT}`, '--connection-timeout', '1000', '--workers', @@ -1392,9 +1475,9 @@ async function setupNAT( '--client-host', '127.0.0.1', '--proxy-host', - `${agent2HostIp}`, + `${AGENT2_HOST}`, '--proxy-port', - `${agent2Port}`, + `${AGENT2_PORT}`, '--connection-timeout', '1000', '--workers', @@ -1424,17 +1507,11 @@ async function setupNAT( agent1NodePath: path.join(dataDir, 'agent1'), agent2NodePath: path.join(dataDir, 'agent2'), agent1NodeId: nodeId1, - agent1Host: agent1RouterHostExtIp, - agent1ProxyPort: - agent1NAT === 'dmz' - ? mappedPort - : agent1Port, + agent1Host: ROUTER1_HOST_EXT, + agent1ProxyPort: agent1NAT === 'dmz' ? DMZ_PORT : AGENT1_PORT, agent2NodeId: nodeId2, - agent2Host: agent2RouterHostExtIp, - agent2ProxyPort: - agent2NAT === 'dmz' - ? mappedPort - : agent2Port, + agent2Host: ROUTER2_HOST_EXT, + agent2ProxyPort: agent2NAT === 'dmz' ? DMZ_PORT : AGENT2_PORT, tearDownNAT: async () => { agent2.kill('SIGTERM'); await testBinUtils.processExit(agent2); From 4f8d17e154606ceb2b8eba0f25eb67aed71a72cb Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 24 Jun 2022 13:58:50 +1000 Subject: [PATCH 131/137] fix: relay node for hole punch message now re-writes proxy address A relay node for a hole punch message was previously not modifying the proxy address in the message (which is the "return address" used to contact the source node). For nodes behind a NAT, who do not know their own public address, they rely on this overwriting so that nodes do not try to contact them on their private, inaccessible address. --- src/nodes/NodeConnectionManager.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index ffa54acaa..9b1189651 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -698,11 +698,20 @@ class NodeConnectionManager { message: nodesPB.Relay, timer?: Timer, ): Promise { + // First check if we already have an existing ID -> address record + // If we're relaying then we trust our own node graph records over + // what was provided in the message + const sourceNode = validationUtils.parseNodeId(message.getSrcId()); + const knownAddress = (await this.nodeGraph.getNode(sourceNode))?.address; + let proxyAddress = message.getProxyAddress(); + if (knownAddress != null) { + proxyAddress = networkUtils.buildAddress(knownAddress.host as Host, knownAddress.port); + } await this.sendHolePunchMessage( validationUtils.parseNodeId(message.getTargetId()), - validationUtils.parseNodeId(message.getSrcId()), + sourceNode, validationUtils.parseNodeId(message.getTargetId()), - message.getProxyAddress(), + proxyAddress, Buffer.from(message.getSignature()), timer, ); From 1095f8f71261efd88a30846d2b90a4ed6f40d0a6 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 24 Jun 2022 15:32:35 +1000 Subject: [PATCH 132/137] feat: added ability to pause `refreshBucketQueue` This will allow us to disable the queue for testing. --- src/nodes/NodeManager.ts | 17 ++++++++++ tests/nodes/NodeManager.test.ts | 59 +++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index bb264de4f..7245ab5c4 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -47,6 +47,7 @@ class NodeManager { protected refreshBucketQueueRunner: Promise; protected refreshBucketQueuePlug_: PromiseDeconstructed = promise(); protected refreshBucketQueueDrained_: PromiseDeconstructed = promise(); + protected refreshBucketQueuePause_: PromiseDeconstructed = promise(); protected refreshBucketQueueAbortController: AbortController; constructor({ @@ -664,12 +665,25 @@ class NodeManager { await this.refreshBucketQueueDrained_.p; } + public refreshBucketQueuePause() { + this.logger.debug('Pausing refreshBucketQueue'); + this.refreshBucketQueuePause_ = promise(); + } + + public refreshBucketQueueResume() { + this.logger.debug('Resuming refreshBucketQueue'); + this.refreshBucketQueuePause_.resolveP(); + } + private async startRefreshBucketQueue(): Promise { this.refreshBucketQueueRunning = true; this.refreshBucketQueuePlug(); + this.refreshBucketQueueResume(); let iterator: IterableIterator | undefined; this.refreshBucketQueueAbortController = new AbortController(); const pace = async () => { + // Wait if paused + await this.refreshBucketQueuePause_.p; // Wait for plug await this.refreshBucketQueuePlug_.p; if (iterator == null) { @@ -709,14 +723,17 @@ class NodeManager { this.refreshBucketQueueAbortController.abort(); this.refreshBucketQueueRunning = false; this.refreshBucketQueueUnplug(); + this.refreshBucketQueueResume(); } private refreshBucketQueuePlug() { + this.logger.debug('refresh bucket queue has plugged'); this.refreshBucketQueuePlug_ = promise(); this.refreshBucketQueueDrained_?.resolveP(); } private refreshBucketQueueUnplug() { + this.logger.debug('refresh bucket queue has unplugged'); this.refreshBucketQueueDrained_ = promise(); this.refreshBucketQueuePlug_?.resolveP(); } diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index 66bd40999..d32c869d9 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -1086,4 +1086,63 @@ describe(`${NodeManager.name} test`, () => { await queue.stop(); } }); + test('should pause, resume and stop queue while paused', async () => { + const refreshBucketTimeout = 1000000; + const queue = new Queue({ logger }); + const nodeManager = new NodeManager({ + db, + sigchain: {} as Sigchain, + keyManager, + nodeGraph, + nodeConnectionManager: dummyNodeConnectionManager, + queue, + refreshBucketTimerDefault: refreshBucketTimeout, + logger, + }); + const mockRefreshBucket = jest.spyOn( + NodeManager.prototype, + 'refreshBucket', + ); + try { + logger.setLevel(LogLevel.DEBUG); + await queue.start(); + await nodeManager.start(); + await nodeConnectionManager.start({ nodeManager }); + mockRefreshBucket.mockImplementation( + async (bucket, options: { signal?: AbortSignal } = {}) => { + const { signal } = { ...options }; + const prom = promise(); + const timer = setTimeout(prom.resolveP, 10); + signal?.addEventListener('abort', () => { + clearTimeout(timer); + prom.rejectP(new nodesErrors.ErrorNodeAborted()); + }); + await prom.p; + }, + ); + nodeManager.refreshBucketQueueAdd(1); + nodeManager.refreshBucketQueueAdd(2); + nodeManager.refreshBucketQueueAdd(3); + nodeManager.refreshBucketQueueAdd(4); + nodeManager.refreshBucketQueueAdd(5); + + // Can pause and resume + nodeManager.refreshBucketQueuePause(); + nodeManager.refreshBucketQueueAdd(6); + nodeManager.refreshBucketQueueAdd(7); + nodeManager.refreshBucketQueueResume(); + await nodeManager.refreshBucketQueueDrained(); + + // Can pause and stop + nodeManager.refreshBucketQueuePause(); + nodeManager.refreshBucketQueueAdd(8); + nodeManager.refreshBucketQueueAdd(9); + nodeManager.refreshBucketQueueAdd(10); + await nodeManager.stop(); + } finally { + mockRefreshBucket.mockRestore(); + await nodeManager.stop(); + await queue.stop(); + } + }); }); From 520b799fc9ff8d5fba251b2634ff26a4e130bf0a Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 24 Jun 2022 15:45:15 +1000 Subject: [PATCH 133/137] build: package upgrades to aid testing --- package-lock.json | 28 ++++++++++++++-------------- package.json | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index b12a9624a..be8b574bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,12 @@ "license": "GPL-3.0", "dependencies": { "@grpc/grpc-js": "1.6.7", - "@matrixai/async-init": "^1.8.0", + "@matrixai/async-init": "^1.8.1", "@matrixai/async-locks": "^2.3.1", "@matrixai/db": "^4.0.5", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", - "@matrixai/logger": "^2.2.0", + "@matrixai/logger": "^2.2.2", "@matrixai/resources": "^1.1.3", "@matrixai/workers": "^1.3.3", "ajv": "^7.0.4", @@ -2537,9 +2537,9 @@ } }, "node_modules/@matrixai/async-init": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.8.0.tgz", - "integrity": "sha512-Y2yxG0s5UQQR/WqIvMhud0tRmcGrUynwE/vdbkSsLeLARpAAOmSgbIzP963VqOiAs8/W3FVJgMaMjo4rIaJPtg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.8.1.tgz", + "integrity": "sha512-ZAS1yd/PC+r3NwvT9fEz3OtAm68A8mKXXGdZRcYQF1ajl43jsV8/B4aDwr2oLFlV+RYZgWl7UwjZj4rtoZSycQ==", "dependencies": { "@matrixai/async-locks": "^2.3.1", "@matrixai/errors": "^1.1.1" @@ -2588,9 +2588,9 @@ } }, "node_modules/@matrixai/logger": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.2.0.tgz", - "integrity": "sha512-GNAFEophgqhJZI01s5OuosbxJO/GSmDZU4rfKmNS3l/dbaOuI32RKEv6XNd6O9HpjmX886rGSxks1/rBZw+cRw==" + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.2.2.tgz", + "integrity": "sha512-6/G1svkcFiBMvmIdBv6YbxoLKwMWpXNzt93Cc4XbXXygCQrsn6oYwLvnRk/JNr6uM29M2T+Aa7K1o3n2XMTuLw==" }, "node_modules/@matrixai/resources": { "version": "1.1.3", @@ -13644,9 +13644,9 @@ } }, "@matrixai/async-init": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.8.0.tgz", - "integrity": "sha512-Y2yxG0s5UQQR/WqIvMhud0tRmcGrUynwE/vdbkSsLeLARpAAOmSgbIzP963VqOiAs8/W3FVJgMaMjo4rIaJPtg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.8.1.tgz", + "integrity": "sha512-ZAS1yd/PC+r3NwvT9fEz3OtAm68A8mKXXGdZRcYQF1ajl43jsV8/B4aDwr2oLFlV+RYZgWl7UwjZj4rtoZSycQ==", "requires": { "@matrixai/async-locks": "^2.3.1", "@matrixai/errors": "^1.1.1" @@ -13695,9 +13695,9 @@ } }, "@matrixai/logger": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.2.0.tgz", - "integrity": "sha512-GNAFEophgqhJZI01s5OuosbxJO/GSmDZU4rfKmNS3l/dbaOuI32RKEv6XNd6O9HpjmX886rGSxks1/rBZw+cRw==" + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-2.2.2.tgz", + "integrity": "sha512-6/G1svkcFiBMvmIdBv6YbxoLKwMWpXNzt93Cc4XbXXygCQrsn6oYwLvnRk/JNr6uM29M2T+Aa7K1o3n2XMTuLw==" }, "@matrixai/resources": { "version": "1.1.3", diff --git a/package.json b/package.json index 5fe9c750d..47f502c95 100644 --- a/package.json +++ b/package.json @@ -76,12 +76,12 @@ }, "dependencies": { "@grpc/grpc-js": "1.6.7", - "@matrixai/async-init": "^1.8.0", + "@matrixai/async-init": "^1.8.1", "@matrixai/async-locks": "^2.3.1", "@matrixai/db": "^4.0.5", "@matrixai/errors": "^1.1.1", "@matrixai/id": "^3.3.3", - "@matrixai/logger": "^2.2.0", + "@matrixai/logger": "^2.2.2", "@matrixai/resources": "^1.1.3", "@matrixai/workers": "^1.3.3", "ajv": "^7.0.4", From 1e35180c668911dd7e401986307ed641b45d71ba Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 24 Jun 2022 15:45:33 +1000 Subject: [PATCH 134/137] style: lintfix --- src/nodes/NodeConnectionManager.ts | 5 ++++- tests/nat/DMZ.test.ts | 8 ++++---- tests/nat/endpointDependentNAT.test.ts | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index 9b1189651..bd2288ca7 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -705,7 +705,10 @@ class NodeConnectionManager { const knownAddress = (await this.nodeGraph.getNode(sourceNode))?.address; let proxyAddress = message.getProxyAddress(); if (knownAddress != null) { - proxyAddress = networkUtils.buildAddress(knownAddress.host as Host, knownAddress.port); + proxyAddress = networkUtils.buildAddress( + knownAddress.host as Host, + knownAddress.port, + ); } await this.sendHolePunchMessage( validationUtils.parseNodeId(message.getTargetId()), diff --git a/tests/nat/DMZ.test.ts b/tests/nat/DMZ.test.ts index 9f78ffd56..3795dfaf0 100644 --- a/tests/nat/DMZ.test.ts +++ b/tests/nat/DMZ.test.ts @@ -175,7 +175,7 @@ describeIf( ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json', '--verbose'], + ['nodes', 'ping', agent2NodeId, '--format', 'json'], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -190,7 +190,7 @@ describeIf( ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json', '--verbose'], + ['nodes', 'ping', agent1NodeId, '--format', 'json'], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, @@ -227,7 +227,7 @@ describeIf( ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json', '--verbose'], + ['nodes', 'ping', agent2NodeId, '--format', 'json'], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, @@ -242,7 +242,7 @@ describeIf( ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, agent2Pid!, - ['nodes', 'ping', agent1NodeId, '--format', 'json', '--verbose'], + ['nodes', 'ping', agent1NodeId, '--format', 'json'], { PK_NODE_PATH: agent2NodePath, PK_PASSWORD: password, diff --git a/tests/nat/endpointDependentNAT.test.ts b/tests/nat/endpointDependentNAT.test.ts index c815f6d6b..663293f4a 100644 --- a/tests/nat/endpointDependentNAT.test.ts +++ b/tests/nat/endpointDependentNAT.test.ts @@ -241,7 +241,7 @@ describeIf( ({ exitCode, stdout } = await testNatUtils.pkExecNs( userPid!, agent1Pid!, - ['nodes', 'ping', agent2NodeId, '--format', 'json', '-vv'], + ['nodes', 'ping', agent2NodeId, '--format', 'json'], { PK_NODE_PATH: agent1NodePath, PK_PASSWORD: password, From 856388b65775cf95609f304beb46eab377f35f2b Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Fri, 24 Jun 2022 16:21:12 +1000 Subject: [PATCH 135/137] feat: added diagrams to DMZ tests #388 --- tests/nat/DMZ.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/nat/DMZ.test.ts b/tests/nat/DMZ.test.ts index 3795dfaf0..ae54d2d15 100644 --- a/tests/nat/DMZ.test.ts +++ b/tests/nat/DMZ.test.ts @@ -135,6 +135,15 @@ describeIf( agent2ProxyPort, tearDownNAT, } = await testNatUtils.setupNAT('dmz', 'dmz', logger); + // Namespace1 Namespace2 + // ┌────────────────────────────────────┐ ┌────────────────────────────────────┐ + // │ │ │ │ + // │ ┌────────┐ ┌─────────┐ │ │ ┌─────────┐ ┌────────┐ │ + // │ │ Agent1 ├────────┤ Router1 │ │ │ │ Router2 ├────────┤ Agent2 │ │ + // │ └────────┘ └─────────┘ │ │ └─────────┘ └────────┘ │ + // │ 10.0.0.2:55551 192.168.0.1:55555 │ │ 192.168.0.2:55555 10.0.0.2:55552 │ + // │ │ │ │ + // └────────────────────────────────────┘ └────────────────────────────────────┘ // Since neither node is behind a NAT can directly add eachother's // details using pk nodes add await testNatUtils.pkExecNs( @@ -221,6 +230,15 @@ describeIf( agent2NodeId, tearDownNAT, } = await testNatUtils.setupNATWithSeedNode('dmz', 'dmz', logger); + // Namespace1 Namespace3 Namespace2 + // ┌────────────────────────────────────┐ ┌──────────────────┐ ┌────────────────────────────────────┐ + // │ │ │ │ │ │ + // │ ┌────────┐ ┌─────────┐ │ │ ┌──────────┐ │ │ ┌─────────┐ ┌────────┐ │ + // │ │ Agent1 ├────────┤ Router1 │ │ │ │ SeedNode │ │ │ │ Router2 ├────────┤ Agent2 │ │ + // │ └────────┘ └─────────┘ │ │ └──────────┘ │ │ └─────────┘ └────────┘ │ + // │ 10.0.0.2:55551 192.168.0.1:55555 │ │ 192.168.0.3:PORT │ │ 192.168.0.2:55555 10.0.0.2:55552 │ + // │ │ │ │ │ │ + // └────────────────────────────────────┘ └──────────────────┘ └────────────────────────────────────┘ // Should be able to ping straight away using the details from the // seed node let exitCode, stdout; From 7c91acecd67420d16419c14455067dc7842849d2 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 24 Jun 2022 16:22:44 +1000 Subject: [PATCH 136/137] fix: async bug with composing connections the composed flag was set at the beginning of the compose function causing another function to throw an error due to an undefined property if it was called at the same time. --- src/network/ConnectionReverse.ts | 2 +- src/nodes/NodeConnection.ts | 2 +- src/nodes/NodeConnectionManager.ts | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/network/ConnectionReverse.ts b/src/network/ConnectionReverse.ts index ada434649..d7000d9d0 100644 --- a/src/network/ConnectionReverse.ts +++ b/src/network/ConnectionReverse.ts @@ -217,7 +217,6 @@ class ConnectionReverse extends Connection { if (this._composed) { throw new networkErrors.ErrorConnectionComposed(); } - this._composed = true; this.logger.info('Composing Connection Reverse'); // Promise for secure establishment const { p: secureP, resolveP: resolveSecureP } = promise(); @@ -306,6 +305,7 @@ class ConnectionReverse extends Connection { }); this.clientCertChain = clientCertChain; this.logger.info('Composed Connection Reverse'); + this._composed = true; } catch (e) { this._composed = false; throw e; diff --git a/src/nodes/NodeConnection.ts b/src/nodes/NodeConnection.ts index f4f4fbfb3..c90260afc 100644 --- a/src/nodes/NodeConnection.ts +++ b/src/nodes/NodeConnection.ts @@ -128,7 +128,7 @@ class NodeConnection { }, timer: timer, }), - holePunchPromises, + ...holePunchPromises, ]); // 5. When finished, you have a connection to other node // The GRPCClient is ready to be used for requests diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index bd2288ca7..30550b6a4 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -756,6 +756,7 @@ class NodeConnectionManager { const signature = await this.keyManager.signWithRootKeyPair( Buffer.from(proxyAddress), ); + // FIXME: this needs to handle aborting const holePunchPromises = Array.from(this.getSeedNodes(), (seedNodeId) => { return this.sendHolePunchMessage( seedNodeId, From 0bc3af5bf4c57427bd78e59064d9f3271ce708d0 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Tue, 28 Jun 2022 13:22:03 +1000 Subject: [PATCH 137/137] build: fix for `integration:nix` CI/CD job Problem was to do with the `nix-build` process not patching the shebangs of the `polykey.js` script. this resulted in it failing to run due to not finding node in it's environment. The fix was to make `src/bin/polykey.js` and `src/bin/polykey-agent.ts` executable. --- src/bin/polykey-agent.ts | 0 src/bin/polykey.ts | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 src/bin/polykey-agent.ts mode change 100644 => 100755 src/bin/polykey.ts diff --git a/src/bin/polykey-agent.ts b/src/bin/polykey-agent.ts old mode 100644 new mode 100755 diff --git a/src/bin/polykey.ts b/src/bin/polykey.ts old mode 100644 new mode 100755