From 6436cd56841d7076d8c885ac628195fb4ad14327 Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 8 Sep 2021 12:42:30 +0300 Subject: [PATCH] Update JS SDK API to the new version (#61) * FluenceClient renamed to FluencePeer. * Using Aqua compiler is now the recommended way for all interaction with the network, including services registration and sending requests * Old API (sendParticle etc) has been removed * Opaque seed format replaced with 32 byte ed25519 private key. KeyPair introduced * Documentation update --- .gitignore | 1 + README.md | 102 +- doc/stack.png | Bin 84850 -> 0 bytes package-lock.json | 1957 +++++++---------- package.json | 10 +- src/FluenceClient.ts | 150 -- src/__test__/integration/avm.spec.ts | 50 + src/__test__/integration/builtins.spec.ts | 122 - .../integration/compiler/compiler.spec.ts | 161 ++ src/__test__/integration/compiler/gen1.ts | 177 ++ src/__test__/integration/legacy.api.spec.ts | 126 -- .../{client.spec.ts => peer.spec.ts} | 113 +- ...ler.spec.ts => CallServiceHandler.spec.ts} | 11 +- src/__test__/unit/KeyPair.spec.ts | 32 + src/__test__/unit/RequestFlow.spec.ts | 6 +- src/__test__/unit/WsTransport.spec.ts | 4 +- src/__test__/unit/air.spec.ts | 197 -- src/__test__/unit/ast.spec.ts | 44 - src/__test__/unit/builtInHandler.spec.ts | 4 + src/__test__/unit/peerId.spec.ts | 13 - src/api.ts | 159 -- src/api.unstable.ts | 2 - src/index.ts | 10 +- src/internal/CallServiceHandler.ts | 53 +- src/internal/ClientImpl.ts | 236 -- src/internal/FluenceConnection.ts | 3 +- src/internal/FluencePeer.ts | 325 +++ src/internal/KeyPair.ts | 60 + src/internal/RequestFlow.ts | 1 + src/internal/builtins.ts | 342 --- src/internal/commonTypes.ts | 40 + src/internal/compilerSupport/v1.ts | 5 + src/internal/defaultClientHandler.ts | 2 +- src/internal/defaultMiddlewares.ts | 14 + src/internal/peerIdUtils.ts | 48 - src/internal/utils.ts | 72 + tsconfig.json | 1 + 37 files changed, 1880 insertions(+), 2773 deletions(-) delete mode 100644 doc/stack.png delete mode 100644 src/FluenceClient.ts create mode 100644 src/__test__/integration/avm.spec.ts delete mode 100644 src/__test__/integration/builtins.spec.ts create mode 100644 src/__test__/integration/compiler/compiler.spec.ts create mode 100644 src/__test__/integration/compiler/gen1.ts delete mode 100644 src/__test__/integration/legacy.api.spec.ts rename src/__test__/integration/{client.spec.ts => peer.spec.ts} (68%) rename src/__test__/unit/{AquaHandler.spec.ts => CallServiceHandler.spec.ts} (95%) create mode 100644 src/__test__/unit/KeyPair.spec.ts delete mode 100644 src/__test__/unit/air.spec.ts delete mode 100644 src/__test__/unit/ast.spec.ts delete mode 100644 src/__test__/unit/peerId.spec.ts delete mode 100644 src/api.ts delete mode 100644 src/api.unstable.ts delete mode 100644 src/internal/ClientImpl.ts create mode 100644 src/internal/FluencePeer.ts create mode 100644 src/internal/KeyPair.ts delete mode 100644 src/internal/builtins.ts create mode 100644 src/internal/compilerSupport/v1.ts create mode 100644 src/internal/defaultMiddlewares.ts delete mode 100644 src/internal/peerIdUtils.ts create mode 100644 src/internal/utils.ts diff --git a/.gitignore b/.gitignore index 8f47dc62..ff09d829 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ lerna-debug.log* # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release bundle/ +docs/ # Dependency directories node_modules/ diff --git a/README.md b/README.md index 5b7b6275..8a4dd060 100644 --- a/README.md +++ b/README.md @@ -2,105 +2,17 @@ [![npm](https://img.shields.io/npm/v/@fluencelabs/fluence)](https://www.npmjs.com/package/@fluencelabs/fluence) -Official SDK for building web-based applications for Fluence - -## About Fluence - -Fluence is an open application platform where apps can build on each other, share data and users - -| Layer | Tech | Scale | State | Based on | -| :-------------------: | :-------------------------------------------------------------------------------------------------------------------------------: | :------------------------------: | :-------------------------------: | :-----------------------------------------------------------------------------------------------------------: | -| Execution | [FCE](https://github.com/fluencelabs/fce) | Single peer | Disk, network, external processes | Wasm, [IT](https://github.com/fluencelabs/interface-types), [Wasmer\*](https://github.com/fluencelabs/wasmer) | -| Composition | [Aquamarine](https://github.com/fluencelabs/aquamarine) | Involved peers | Results and signatures | ⇅, π-calculus | -| Topology | [TrustGraph](https://github.com/fluencelabs/fluence/tree/master/trust-graph), [DHT\*](https://github.com/fluencelabs/rust-libp2p) | Distributed with Kademlia\* algo | Actual state of the network | [libp2p](https://github.com/libp2p/rust-libp2p) | -| Security & Accounting | Blockchain | Whole network | Licenses & payments | substrate? | - -aquamarine scheme - -## Installation - -With npm - -```bash -npm install @fluencelabs/fluence -``` - -With yarn - -```bash -yarn add @fluencelabs/fluence -``` +Official SDK providing javascript-based implementation of the Fluence Peer. ## Getting started -Pick a node to connect to the Fluence network. The easiest way to do so is by using [fluence-network-environment](https://github.com/fluencelabs/fluence-network-environment) package +To start developing applications with JS SDK refer to the official [gitbook page](https://doc.fluence.dev/docs/js-sdk) -```typescript -import { dev } from '@fluencelabs/fluence-network-environment'; +## Contributing -export const relayNode = dev[0]; -``` +While the project is still in the early stages of development, you are welcome to track progress and contribute. As the project is undergoing rapid changes, interested contributors should contact the team before embarking on larger pieces of work. All contributors should consult with and agree to our [basic contributing rules](CONTRIBUTING.md). -Initialize client - -```typescript -import { createClient, FluenceClient } from '@fluencelabs/fluence'; - -const client = await createClient(relayNode); -``` - -Respond to service function calls - -```typescript -subscribeToEvent(client, 'helloService', 'helloFunction', (args) => { - const [networkInfo] = args; - console.log(networkInfo); -}); -``` - -Make a particle - -```typescript -const particle = new Particle( - ` - (seq - (call myRelay ("peer" "identify") [] result) - (call %init_peer_id% ("helloService" "helloFunction") [result]) - )`, - { - myRelay: client.relayPeerId, - }, -); -``` - -Send it to the network - -```typescript -await sendParticle(client, particle); -``` - -Observe the result in browser console - -```json -{ - "external_addresses": ["/ip4/1.2.3.4/tcp/7777", "/dns4/dev.fluence.dev/tcp/19002"] -} -``` - -## Documentation - -Guide on building applications: [doc.fluence.dev](https://doc.fluence.dev/docs/tutorials_tutorials/building-a-frontend-with-js-sdk) - -Sample applications: - -- [FluentPad](https://github.com/fluencelabs/fluent-pad): a collaborative text editor with users online status synchronization -- [Examples](https://github.com/fluencelabs/examples): examples of using the Aqua programming language - -About [Fluence](https://fluence.network/) - -## Developing - -### Setting up Dev +### Setting up dev environment Install node packages @@ -140,10 +52,6 @@ To run all tests npm run test:all ``` -## Contributing - -While the project is still in the early stages of development, you are welcome to track progress and contribute. As the project is undergoing rapid changes, interested contributors should contact the team before embarking on larger pieces of work. All contributors should consult with and agree to our [basic contributing rules](CONTRIBUTING.md). - ## License [Apache 2.0](LICENSE) diff --git a/doc/stack.png b/doc/stack.png deleted file mode 100644 index 7557c5e8c2204b294dc1302400949094cab2b5ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 84850 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%0D((n*lv3DX4S~o%@G}tQHJOm> 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 NJYD@<);T3K0RVj4eM$fT diff --git a/package-lock.json b/package-lock.json index 9a3975c3..86763495 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,35 +5,35 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", "dev": true, "requires": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.14.5" } }, "@babel/compat-data": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.12.tgz", - "integrity": "sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==", + "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 }, "@babel/core": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.14.tgz", - "integrity": "sha512-wZso/vyF4ki0l0znlgM4inxbdrUvCb+cVz8grxDq+6C9k6qbqoIJteQOKicaKjCipU3ISV+XedCqpL2RJJVehA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", + "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.9", - "@babel/helper-compilation-targets": "^7.13.13", - "@babel/helper-module-transforms": "^7.13.14", - "@babel/helpers": "^7.13.10", - "@babel/parser": "^7.13.13", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.13", - "@babel/types": "^7.13.14", + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.0", + "@babel/helper-compilation-targets": "^7.15.0", + "@babel/helper-module-transforms": "^7.15.0", + "@babel/helpers": "^7.14.8", + "@babel/parser": "^7.15.0", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -51,12 +51,12 @@ } }, "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", + "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", "dev": true, "requires": { - "@babel/types": "^7.13.0", + "@babel/types": "^7.15.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -70,146 +70,155 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz", - "integrity": "sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", + "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", "dev": true, "requires": { - "@babel/compat-data": "^7.13.12", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", + "@babel/compat-data": "^7.15.0", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", "semver": "^6.3.0" } }, "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", + "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-get-function-arity": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", + "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", + "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", - "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", + "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.15.0" } }, "@babel/helper-module-imports": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", - "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", + "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.14.5" } }, "@babel/helper-module-transforms": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz", - "integrity": "sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", + "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-replace-supers": "^7.13.12", - "@babel/helper-simple-access": "^7.13.12", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.12.11", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.13", - "@babel/types": "^7.13.14" + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-replace-supers": "^7.15.0", + "@babel/helper-simple-access": "^7.14.8", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.9", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0" } }, "@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", - "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", + "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.14.5" } }, "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "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 }, "@babel/helper-replace-supers": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", - "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", + "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.13.12", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" + "@babel/helper-member-expression-to-functions": "^7.15.0", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0" } }, "@babel/helper-simple-access": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", - "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", + "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.14.8" } }, "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", + "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.14.5" } }, "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", + "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", - "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", + "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 }, "@babel/helpers": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz", - "integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==", + "version": "7.15.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.3.tgz", + "integrity": "sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==", "dev": true, "requires": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0" } }, "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", + "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, "requires": { - "@babel/helper-validator-identifier": "^7.12.11", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -267,9 +276,9 @@ } }, "@babel/parser": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz", - "integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==", + "version": "7.15.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.3.tgz", + "integrity": "sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -372,49 +381,49 @@ } }, "@babel/plugin-syntax-top-level-await": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz", - "integrity": "sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==", + "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.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", + "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/traverse": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz", - "integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", + "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.9", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.13", - "@babel/types": "^7.13.13", + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.0", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.15.0", + "@babel/types": "^7.15.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz", - "integrity": "sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", + "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", + "@babel/helper-validator-identifier": "^7.14.9", "to-fast-properties": "^2.0.0" } }, @@ -455,28 +464,6 @@ "readable-stream": "^3.4.0" } }, - "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" - } - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, "it-length-prefixed": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz", @@ -486,11 +473,6 @@ "buffer": "^6.0.3", "varint": "^6.0.0" } - }, - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" } } }, @@ -505,9 +487,9 @@ } }, "@fluencelabs/avm": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.14.3.tgz", - "integrity": "sha512-HCRIn8WHshHDkZmoW9ITnEzdr+XcZBo9SjlcbKHd8+ls1LkX4SiGe2tKh3QQwtmJ6xFh9TypTwjWeDYCGIw7JA==", + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.14.4.tgz", + "integrity": "sha512-XyR+1H5k0CAc+mDHOkl81viX8XeW1Yqbw793xbsfUfju5bUb/hqk+gHv3q8lAFdbrCG5P45gdOT08a5RNODZaQ==", "requires": { "base64-js": "1.5.1" } @@ -579,14 +561,6 @@ "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "@jest/environment": { @@ -657,14 +631,6 @@ "string-length": "^4.0.1", "terminal-link": "^2.0.0", "v8-to-istanbul": "^7.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "@jest/source-map": { @@ -676,14 +642,6 @@ "callsites": "^3.0.0", "graceful-fs": "^4.2.4", "source-map": "^0.6.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "@jest/test-result": { @@ -709,14 +667,6 @@ "jest-haste-map": "^26.6.2", "jest-runner": "^26.6.3", "jest-runtime": "^26.6.3" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "@jest/transform": { @@ -740,14 +690,6 @@ "slash": "^3.0.0", "source-map": "^0.6.1", "write-file-atomic": "^3.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "@jest/types": { @@ -774,16 +716,6 @@ "request": "^2.88.2", "unordered-array-remove": "^1.0.2", "xml2js": "^0.4.23" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - } } }, "@protobufjs/aspromise": { @@ -841,9 +773,9 @@ "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" }, "@sinonjs/commons": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz", - "integrity": "sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw==", + "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" @@ -984,10 +916,16 @@ "@stablelib/wipe": "^1.0.1" } }, + "@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 + }, "@types/babel__core": { - "version": "7.1.14", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", - "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", + "version": "7.1.15", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz", + "integrity": "sha512-bxlMKPDbY8x5h6HBwVzEOk2C8fb6SLfYQ5Jw3uBYuYF1lfWk/kbLd81la82vrIkBb0l+JdmrZaDikPrNxpS/Ew==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -998,18 +936,18 @@ } }, "@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", + "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", "dev": true, "requires": { "@babel/types": "^7.0.0" } }, "@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "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", @@ -1017,9 +955,9 @@ } }, "@types/babel__traverse": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", - "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", + "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, "requires": { "@babel/types": "^7.3.0" @@ -1050,18 +988,18 @@ } }, "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "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.22", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.22.tgz", - "integrity": "sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw==", + "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, "requires": { "jest-diff": "^26.0.0", @@ -1079,20 +1017,20 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" }, "@types/node": { - "version": "13.13.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.2.tgz", - "integrity": "sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A==" + "version": "16.7.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.6.tgz", + "integrity": "sha512-VESVNFoa/ahYA62xnLBjo5ur6gPsgEE5cNRy8SrdnkZ2nwJSW0kJ4ufbFr2zuU9ALtHM8juY53VcRoTA7htXSg==" }, "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "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/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", "dev": true }, "@types/retry": { @@ -1101,24 +1039,24 @@ "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" }, "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", + "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/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", "dev": true, "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, "@vascosantos/moving-average": { @@ -1149,9 +1087,9 @@ } }, "acorn": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", - "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", + "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", "dev": true }, "acorn-globals": { @@ -1178,6 +1116,15 @@ "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" + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -1360,14 +1307,6 @@ "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "slash": "^3.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "babel-plugin-istanbul": { @@ -1426,9 +1365,9 @@ } }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base": { "version": "0.11.2", @@ -1519,16 +1458,6 @@ "file-uri-to-path": "1.0.0" } }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, "bn.js": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", @@ -1603,18 +1532,18 @@ } }, "buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "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.0.2", - "ieee754": "^1.1.4" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "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": { @@ -1667,9 +1596,9 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "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", @@ -1698,6 +1627,17 @@ "multibase": "~0.7.0", "multicodec": "^1.0.1", "multihashes": "~0.4.17" + }, + "dependencies": { + "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" + } + } } }, "cjs-module-lexer": { @@ -1813,9 +1753,9 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "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" @@ -1841,24 +1781,13 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "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, + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, "cssom": { @@ -1904,11 +1833,11 @@ } }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "decamelize": { @@ -1918,9 +1847,9 @@ "dev": true }, "decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", + "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": { @@ -1947,83 +1876,6 @@ "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "requires": { "execa": "^5.0.0" - }, - "dependencies": { - "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", - "which": "^2.0.1" - } - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "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" - } - }, - "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==" - }, - "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==" - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - }, - "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==", - "requires": { - "path-key": "^3.0.0" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "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==" - }, - "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" - } - } } }, "define-property": { @@ -2092,16 +1944,6 @@ "debug": "^4.3.1", "native-fetch": "^3.0.0", "receptacle": "^1.3.2" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - } } }, "domexception": { @@ -2128,19 +1970,12 @@ "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" - }, - "dependencies": { - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - } } }, "electron-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/electron-fetch/-/electron-fetch-1.7.3.tgz", - "integrity": "sha512-1AVMaxrHXTTMqd7EK0MGWusdqNr07Rpj8Th6bG4at0oNgIi/1LBwa9CjT/0Zy+M0k/tSJPS04nFxHj0SXDVgVw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/electron-fetch/-/electron-fetch-1.7.4.tgz", + "integrity": "sha512-+fBLXEy4CJWQ5bz8dyaeSG1hD6JJ15kBZyj3eh24pIVrd3hLM47H/umffrdQfS6GZ0falF0g9JT9f3Rs6AVUhw==", "requires": { "encoding": "^0.1.13" } @@ -2183,16 +2018,6 @@ "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "requires": { "iconv-lite": "^0.6.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } } }, "end-of-stream": { @@ -2288,18 +2113,19 @@ "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, + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "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" + "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" } }, "exit": { @@ -2595,13 +2421,9 @@ "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", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" }, "get-value": { "version": "2.0.6", @@ -2618,9 +2440,9 @@ } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -2637,6 +2459,12 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "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 + }, "growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", @@ -2644,6 +2472,19 @@ "dev": true, "optional": 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", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -2776,6 +2617,17 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "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", + "agent-base": "6", + "debug": "4" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -2786,25 +2638,33 @@ "sshpk": "^1.7.0" } }, - "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 - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "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, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "agent-base": "6", + "debug": "4" + } + }, + "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==" + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "import-local": { "version": "3.0.2", @@ -2843,9 +2703,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "interface-datastore": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-5.1.1.tgz", - "integrity": "sha512-HG/P3kr3N/51MfsW55Q692hD7kmegXobPaZOFu5rNWWeJ27tnes7L/yma3vylrvrTCEUpVgJYigDqHXFICdvRg==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-5.1.2.tgz", + "integrity": "sha512-nRFl19/IkilNzuPdCUJHejyJCZrVAk4lIRcRXJkekuTdaiagIEnCd9GfmTTQlo2afiVISk8Iy/PxSgnfmrdEIw==", "requires": { "err-code": "^3.0.1", "interface-store": "^0.1.1", @@ -2855,7 +2715,17 @@ "it-filter": "^1.0.2", "it-take": "^1.0.1", "nanoid": "^3.0.2", - "uint8arrays": "^2.1.5" + "uint8arrays": "^3.0.0" + }, + "dependencies": { + "uint8arrays": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", + "integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==", + "requires": { + "multiformats": "^9.4.2" + } + } } }, "interface-store": { @@ -2870,6 +2740,13 @@ "requires": { "jsbn": "1.1.0", "sprintf-js": "1.1.2" + }, + "dependencies": { + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha1-sBMHyym2GKHtJux56RH4A8TaAEA=" + } } }, "ip-regex": { @@ -2878,9 +2755,9 @@ "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==" }, "ipfs-utils": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/ipfs-utils/-/ipfs-utils-8.1.4.tgz", - "integrity": "sha512-QJjyRh4KzlkmtAOn/fOHYyjHGuG+Ows7xJGG8eiM/v325VvJhjJ1tWJobI6zrNDeFKjZcx1uNysE3MR2/dSiXQ==", + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/ipfs-utils/-/ipfs-utils-8.1.6.tgz", + "integrity": "sha512-V/cwb6113DrDhrjDTWImA6+zmJbpdbUkxdxmEQO7it8ykV76bBmzU1ZXSM0QR0qxGy9VW8dkUlPAC2K10VgSmw==", "requires": { "abort-controller": "^3.0.0", "any-signal": "^2.1.0", @@ -2895,7 +2772,7 @@ "nanoid": "^3.1.20", "native-abort-controller": "^1.0.3", "native-fetch": "^3.0.0", - "node-fetch": "npm:@achingbrain/node-fetch@^2.6.4", + "node-fetch": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz", "react-native-fetch-api": "^2.0.0", "stream-to-it": "^0.2.2" }, @@ -2913,6 +2790,10 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "node-fetch": { + "version": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-iTASGs+HTFK5E4ZqcMsHmeJ4zodyq8L38lZV33jwqcBJYoUt3HjN4+ot+O9/0b+ke8ddE7UgOtVuZN/OkV19/g==" } } }, @@ -2949,9 +2830,9 @@ "dev": true }, "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" }, "is-ci": { "version": "2.0.0", @@ -2963,9 +2844,9 @@ } }, "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", + "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", "dev": true, "requires": { "has": "^1.0.3" @@ -3017,9 +2898,9 @@ } }, "is-docker": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.0.tgz", - "integrity": "sha512-K4GwB4i/HzhAzwP/XSlspzRdFTI9N8OxJOyOU7Y5Rz+p+WBokXWVWblaJeBkggthmoSV0OoGTH5thJNvplpkvQ==", + "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 }, @@ -3086,10 +2967,9 @@ "dev": true }, "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, "is-typedarray": { "version": "1.0.0", @@ -3221,20 +3101,6 @@ "inherits": "^2.0.4", "readable-stream": "^3.4.0" } - }, - "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" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" } } }, @@ -3263,12 +3129,12 @@ } }, "it-handshake": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/it-handshake/-/it-handshake-1.0.2.tgz", - "integrity": "sha512-uutOim5xF1eyDQD3u8qd3TxbWKwxqGMlbvacZsRsPdjO1BD9lnPTVci0jSMGsvMOu+5Y3W/QQ4hPQb87qPmPVQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/it-handshake/-/it-handshake-2.0.0.tgz", + "integrity": "sha512-K4q+mz8aLlCK3vTjtgNdHC9c/JbuOATsfogarjMsLcBZC5vYfKbX3Gq3AWcCdjIsIrPqzTlhPKSxl64LJkrt2w==", "requires": { "it-pushable": "^1.4.0", - "it-reader": "^2.0.0", + "it-reader": "^3.0.0", "p-defer": "^3.0.0" } }, @@ -3280,6 +3146,32 @@ "bl": "^4.0.2", "buffer": "^5.5.0", "varint": "^5.0.0" + }, + "dependencies": { + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.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" + } + }, + "varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==" + } } }, "it-map": { @@ -3304,34 +3196,33 @@ } }, "it-pb-rpc": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/it-pb-rpc/-/it-pb-rpc-0.1.9.tgz", - "integrity": "sha512-IMPXz+a+lUEclV5qIlT/1WAjCMIZyqQtMRaKaL8cwgvH2P5LtMJlrbNZr3b4VEONK1H6mqAV1upfMTSSBSrOqA==", + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/it-pb-rpc/-/it-pb-rpc-0.1.11.tgz", + "integrity": "sha512-1Yvae7LNHNM/WzxWT7OyHqwpA7DZoGos22JioMZ5H6i9iExQf71NHE0phHKEfkJdWLo7SRqPLLbqs2zaeKCwPA==", "requires": { - "is-buffer": "^2.0.4", - "it-handshake": "^1.0.2", - "it-length-prefixed": "^3.1.0" + "is-buffer": "^2.0.5", + "it-handshake": "^2.0.0", + "it-length-prefixed": "^5.0.2" }, "dependencies": { - "it-length-prefixed": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-3.1.0.tgz", - "integrity": "sha512-E5GwT6qfZEwh3/XThyYwgjKJ4/hxvTC9kdbj3gxXDeUDKtC7+K2T647sPeX7xDEWqunsnoQyvOrjoHPegaT3uw==", + "bl": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz", + "integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==", "requires": { - "@types/bl": "^2.1.0", - "bl": "^4.0.2", - "buffer": "^5.5.0", - "varint": "^5.0.0" - }, - "dependencies": { - "@types/bl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/bl/-/bl-2.1.0.tgz", - "integrity": "sha512-1TdA9IXOy4sdqn8vgieQ6GZAiHiPNrOiO1s2GJjuYPw4QVY7gYoVjkW049avj33Ez7IcIvu43hQsMsoUFbCn2g==", - "requires": { - "@types/node": "*" - } - } + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "it-length-prefixed": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz", + "integrity": "sha512-b+jDHLcnOnPDQN79ronmzF5jeBjdJsy0ce2O6i6X4J5tnaO8Fd146ZA/tMbzaLlKnTpXa0eKtofpYhumXGENeg==", + "requires": { + "bl": "^5.0.0", + "buffer": "^6.0.3", + "varint": "^6.0.0" } } } @@ -3350,11 +3241,23 @@ } }, "it-reader": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-2.1.0.tgz", - "integrity": "sha512-hSysqWTO9Tlwc5EGjVf8JYZzw0D2FsxD/g+eNNWrez9zODxWt6QlN6JAMmycK72Mv4jHEKEXoyzUN4FYGmJaZw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-3.0.0.tgz", + "integrity": "sha512-NxR40odATeaBmSefn6Xn43DplYvn2KtEKQzn4jrTRuPYXMky5M4e+KQ7aTJh0k0vkytLyeenGO1I1GXlGm4laQ==", "requires": { - "bl": "^4.0.0" + "bl": "^5.0.0" + }, + "dependencies": { + "bl": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz", + "integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==", + "requires": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + } } }, "it-take": { @@ -3373,22 +3276,6 @@ "p-defer": "^3.0.0", "p-fifo": "^1.0.0", "readable-stream": "^3.6.0" - }, - "dependencies": { - "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" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - } } }, "it-ws": { @@ -3400,22 +3287,6 @@ "event-iterator": "^2.0.0", "iso-url": "^1.1.2", "ws": "^7.3.1" - }, - "dependencies": { - "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" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - } } }, "jest": { @@ -3429,12 +3300,6 @@ "jest-cli": "^26.6.3" }, "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, "jest-cli": { "version": "26.6.3", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", @@ -3469,17 +3334,6 @@ "throat": "^5.0.0" }, "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, "execa": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", @@ -3506,50 +3360,11 @@ "pump": "^3.0.0" } }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "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 - }, - "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" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "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==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } } } }, @@ -3577,14 +3392,6 @@ "jest-validate": "^26.6.2", "micromatch": "^4.0.2", "pretty-format": "^26.6.2" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "jest-diff": { @@ -3676,14 +3483,6 @@ "micromatch": "^4.0.2", "sane": "^4.0.3", "walker": "^1.0.7" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "jest-jasmine2": { @@ -3749,14 +3548,6 @@ "pretty-format": "^26.6.2", "slash": "^3.0.0", "stack-utils": "^2.0.2" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "jest-mock": { @@ -3795,14 +3586,6 @@ "read-pkg-up": "^7.0.1", "resolve": "^1.18.1", "slash": "^3.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "jest-resolve-dependencies": { @@ -3842,14 +3625,6 @@ "jest-worker": "^26.6.2", "source-map-support": "^0.5.6", "throat": "^5.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "jest-runtime": { @@ -3885,14 +3660,6 @@ "slash": "^3.0.0", "strip-bom": "^4.0.0", "yargs": "^15.4.1" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "jest-serializer": { @@ -3903,14 +3670,6 @@ "requires": { "@types/node": "*", "graceful-fs": "^4.2.4" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "jest-snapshot": { @@ -3937,12 +3696,6 @@ "semver": "^7.3.2" }, "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -3966,14 +3719,6 @@ "graceful-fs": "^4.2.4", "is-ci": "^2.0.0", "micromatch": "^4.0.2" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } } }, "jest-validate": { @@ -4041,18 +3786,18 @@ } }, "jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha1-sBMHyym2GKHtJux56RH4A8TaAEA=" + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsdom": { - "version": "16.5.2", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.2.tgz", - "integrity": "sha512-JxNtPt9C1ut85boCbJmffaQ06NBnzkQY/MWO3YxPW8IWS38A26z+B1oBvA9LwKrytewdfymnhi4UNH3/RAgZrg==", + "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", - "acorn": "^8.1.0", + "acorn": "^8.2.4", "acorn-globals": "^6.0.0", "cssom": "^0.4.4", "cssstyle": "^2.3.0", @@ -4060,12 +3805,13 @@ "decimal.js": "^10.2.1", "domexception": "^2.0.1", "escodegen": "^2.0.0", + "form-data": "^3.0.0", "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", + "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", - "request": "^2.88.2", - "request-promise-native": "^1.0.9", "saxes": "^5.0.1", "symbol-tree": "^3.2.4", "tough-cookie": "^4.0.0", @@ -4075,8 +3821,32 @@ "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.5.0", - "ws": "^7.4.4", + "ws": "^7.4.6", "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "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", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "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" + } + } } }, "jsesc": { @@ -4226,38 +3996,6 @@ "readable-stream": "^3.4.0" } }, - "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" - } - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "it-handshake": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/it-handshake/-/it-handshake-2.0.0.tgz", - "integrity": "sha512-K4q+mz8aLlCK3vTjtgNdHC9c/JbuOATsfogarjMsLcBZC5vYfKbX3Gq3AWcCdjIsIrPqzTlhPKSxl64LJkrt2w==", - "requires": { - "it-pushable": "^1.4.0", - "it-reader": "^3.0.0", - "p-defer": "^3.0.0" - } - }, "it-length-prefixed": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz", @@ -4267,32 +4005,6 @@ "buffer": "^6.0.3", "varint": "^6.0.0" } - }, - "it-reader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-3.0.0.tgz", - "integrity": "sha512-NxR40odATeaBmSefn6Xn43DplYvn2KtEKQzn4jrTRuPYXMky5M4e+KQ7aTJh0k0vkytLyeenGO1I1GXlGm4laQ==", - "requires": { - "bl": "^5.0.0" - } - }, - "multiaddr": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-10.0.0.tgz", - "integrity": "sha512-yP3LzFkM0GORZHNenS8Ok2spsaICRBhxLEohAfKKwwrgHIEWrDUhMRIkh/MONDBThNqaiGl7Ch1H7qblRDNHyg==", - "requires": { - "dns-over-http-resolver": "^1.0.0", - "err-code": "^3.0.1", - "is-ip": "^3.1.0", - "multiformats": "^9.0.2", - "uint8arrays": "^2.1.3", - "varint": "^6.0.0" - } - }, - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" } } }, @@ -4314,26 +4026,6 @@ "ursa-optional": "^0.10.1" }, "dependencies": { - "protobufjs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", - "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", - "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" - } - }, "uint8arrays": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", @@ -4345,9 +4037,9 @@ } }, "libp2p-interfaces": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/libp2p-interfaces/-/libp2p-interfaces-1.0.1.tgz", - "integrity": "sha512-OKUpCL07oiaRi4wygDCi/TPuAZTDCj6efz0I5CBtXCV20k/onelR4xB312LvX6fW6H563JEg4UrUL+7uunFZ3w==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/libp2p-interfaces/-/libp2p-interfaces-1.1.0.tgz", + "integrity": "sha512-5nc/HZJgeks1qfkyYQdI84hcZLF4SJKJSUx33JpO0w7v7R+obz+HOwk0GSa4/ZvQHjX+/+OWC4NYVA0yZxZXag==", "requires": { "abort-controller": "^3.0.0", "abortable-iterator": "^3.0.0", @@ -4361,7 +4053,7 @@ "multiformats": "^9.1.2", "peer-id": "^0.15.0", "protobufjs": "^6.10.2", - "uint8arrays": "^2.1.3" + "uint8arrays": "^3.0.0" }, "dependencies": { "bl": { @@ -4374,28 +4066,6 @@ "readable-stream": "^3.4.0" } }, - "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" - } - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, "it-length-prefixed": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz", @@ -4406,23 +4076,13 @@ "varint": "^6.0.0" } }, - "multiaddr": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-10.0.0.tgz", - "integrity": "sha512-yP3LzFkM0GORZHNenS8Ok2spsaICRBhxLEohAfKKwwrgHIEWrDUhMRIkh/MONDBThNqaiGl7Ch1H7qblRDNHyg==", + "uint8arrays": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", + "integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==", "requires": { - "dns-over-http-resolver": "^1.0.0", - "err-code": "^3.0.1", - "is-ip": "^3.1.0", - "multiformats": "^9.0.2", - "uint8arrays": "^2.1.3", - "varint": "^6.0.0" + "multiformats": "^9.4.2" } - }, - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" } } }, @@ -4450,33 +4110,6 @@ "inherits": "^2.0.4", "readable-stream": "^3.4.0" } - }, - "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" - } - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" } } }, @@ -4492,34 +4125,6 @@ "is-loopback-addr": "^1.0.0", "multiaddr": "^10.0.0", "private-ip": "^2.1.1" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - }, - "multiaddr": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-10.0.0.tgz", - "integrity": "sha512-yP3LzFkM0GORZHNenS8Ok2spsaICRBhxLEohAfKKwwrgHIEWrDUhMRIkh/MONDBThNqaiGl7Ch1H7qblRDNHyg==", - "requires": { - "dns-over-http-resolver": "^1.0.0", - "err-code": "^3.0.1", - "is-ip": "^3.1.0", - "multiformats": "^9.0.2", - "uint8arrays": "^2.1.3", - "varint": "^6.0.0" - } - }, - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" - } } }, "libp2p-websockets": { @@ -4539,34 +4144,6 @@ "multiaddr-to-uri": "^8.0.0", "p-defer": "^3.0.0", "p-timeout": "^4.1.0" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - }, - "multiaddr": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-10.0.0.tgz", - "integrity": "sha512-yP3LzFkM0GORZHNenS8Ok2spsaICRBhxLEohAfKKwwrgHIEWrDUhMRIkh/MONDBThNqaiGl7Ch1H7qblRDNHyg==", - "requires": { - "dns-over-http-resolver": "^1.0.0", - "err-code": "^3.0.1", - "is-ip": "^3.1.0", - "multiformats": "^9.0.2", - "uint8arrays": "^2.1.3", - "varint": "^6.0.0" - } - }, - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" - } } }, "lines-and-columns": { @@ -4609,32 +4186,18 @@ "yallist": "^4.0.0" } }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "mafmt": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/mafmt/-/mafmt-10.0.0.tgz", "integrity": "sha512-K1bziJOXcnepfztu+2Xy9FLKVLaFMDuspmiyJIYRxnO0WOxFSV7XKSdMxMrVZxcvg1+YjlTIvSGTImUHU2k4Aw==", "requires": { "multiaddr": "^10.0.0" - }, - "dependencies": { - "multiaddr": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-10.0.0.tgz", - "integrity": "sha512-yP3LzFkM0GORZHNenS8Ok2spsaICRBhxLEohAfKKwwrgHIEWrDUhMRIkh/MONDBThNqaiGl7Ch1H7qblRDNHyg==", - "requires": { - "dns-over-http-resolver": "^1.0.0", - "err-code": "^3.0.1", - "is-ip": "^3.1.0", - "multiformats": "^9.0.2", - "uint8arrays": "^2.1.3", - "varint": "^6.0.0" - } - }, - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" - } } }, "make-dir": { @@ -4676,6 +4239,12 @@ "object-visit": "^1.0.0" } }, + "marked": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.2.tgz", + "integrity": "sha512-TMJQQ79Z0e3rJYazY0tIoMsFzteUGw9fB3FD+gzuIT3zLuG9L9ckIvUfF51apdJkcqc208jJN2KbtPbOvXtbjA==", + "dev": true + }, "merge-options": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", @@ -4690,26 +4259,26 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "mime-db": { - "version": "1.45.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", - "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==" + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", + "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==" }, "mime-types": { - "version": "2.1.28", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", - "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", + "version": "2.1.32", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", + "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", "requires": { - "mime-db": "1.45.0" + "mime-db": "1.49.0" } }, "mimic-fn": { @@ -4783,13 +4352,6 @@ "multiformats": "^9.0.2", "uint8arrays": "^2.1.3", "varint": "^6.0.0" - }, - "dependencies": { - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" - } } }, "multiaddr-to-uri": { @@ -4798,26 +4360,6 @@ "integrity": "sha512-dq4p/vsOOUdVEd1J1gl+R2GFrXJQH8yjLtz4hodqdVbieg39LvBOdMQRdQnfbg5LSM/q1BYNVf5CBbwZFFqBgA==", "requires": { "multiaddr": "^10.0.0" - }, - "dependencies": { - "multiaddr": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-10.0.0.tgz", - "integrity": "sha512-yP3LzFkM0GORZHNenS8Ok2spsaICRBhxLEohAfKKwwrgHIEWrDUhMRIkh/MONDBThNqaiGl7Ch1H7qblRDNHyg==", - "requires": { - "dns-over-http-resolver": "^1.0.0", - "err-code": "^3.0.1", - "is-ip": "^3.1.0", - "multiformats": "^9.0.2", - "uint8arrays": "^2.1.3", - "varint": "^6.0.0" - } - }, - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" - } } }, "multibase": { @@ -4827,36 +4369,79 @@ "requires": { "base-x": "^3.0.8", "buffer": "^5.5.0" + }, + "dependencies": { + "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" + } + } } }, "multicodec": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.1.tgz", - "integrity": "sha512-yrrU/K8zHyAH2B0slNVeq3AiwluflHpgQ3TAzwNJcuO2AoPyXgBT2EDkdbP1D8B/yFOY+S2hDYmFlI1vhVFkQw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", "requires": { - "buffer": "^5.5.0", + "buffer": "^5.6.0", "varint": "^5.0.0" + }, + "dependencies": { + "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" + } + }, + "varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==" + } } }, "multiformats": { - "version": "9.4.5", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.4.5.tgz", - "integrity": "sha512-zQxukxsHM34EJi3yT3MkUlycY9wEouyrAz0PSN+CyCj6cYchJZ4LrTH74YtlsxVyAK6waz/gnVLmJwi3P0knKg==" + "version": "9.4.6", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.4.6.tgz", + "integrity": "sha512-ngZRO82P7mPvw/3gu5NQ2QiUJGYTS0LAxvQnEAlWCJakvn7YpK2VAd9JWM5oosYUeqoVbkylH/FsqRc4fc2+ag==" }, "multihashes": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.19.tgz", - "integrity": "sha512-ej74GAfA20imjj00RO5h34aY3pGUFyzn9FJZFWwdeUHlHTkKmv90FrNpvYT4jYf1XXCy5O/5EjVnxTaESgOM6A==", + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", "requires": { "buffer": "^5.5.0", "multibase": "^0.7.0", "varint": "^5.0.0" + }, + "dependencies": { + "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" + } + }, + "varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==" + } } }, "multistream-select": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/multistream-select/-/multistream-select-2.0.0.tgz", - "integrity": "sha512-MhzWeoIh2Rojqm32glGNmWbzyffrGrYtg68sWKwj8ZuALHGDySNiU5j6wV69BpUtKRQmQ6zWNUB5few57VB7/w==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/multistream-select/-/multistream-select-2.0.1.tgz", + "integrity": "sha512-ziVNT/vux0uUElP4OKNMVr0afU/X6PciAmT2UJNolhzhSLXIwFAaYfmLajD8NoZ+DsBQ1bp0zZ2nMVPF+FhClA==", "requires": { "bl": "^5.0.0", "debug": "^4.1.1", @@ -4867,7 +4452,7 @@ "it-pipe": "^1.0.1", "it-reader": "^3.0.0", "p-defer": "^3.0.0", - "uint8arrays": "^2.1.4" + "uint8arrays": "^3.0.0" }, "dependencies": { "bl": { @@ -4880,30 +4465,6 @@ "readable-stream": "^3.4.0" } }, - "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" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "it-handshake": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/it-handshake/-/it-handshake-2.0.0.tgz", - "integrity": "sha512-K4q+mz8aLlCK3vTjtgNdHC9c/JbuOATsfogarjMsLcBZC5vYfKbX3Gq3AWcCdjIsIrPqzTlhPKSxl64LJkrt2w==", - "requires": { - "it-pushable": "^1.4.0", - "it-reader": "^3.0.0", - "p-defer": "^3.0.0" - } - }, "it-length-prefixed": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz", @@ -4914,18 +4475,13 @@ "varint": "^6.0.0" } }, - "it-reader": { + "uint8arrays": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-3.0.0.tgz", - "integrity": "sha512-NxR40odATeaBmSefn6Xn43DplYvn2KtEKQzn4jrTRuPYXMky5M4e+KQ7aTJh0k0vkytLyeenGO1I1GXlGm4laQ==", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", + "integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==", "requires": { - "bl": "^5.0.0" + "multiformats": "^9.4.2" } - }, - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" } } }, @@ -4979,6 +4535,12 @@ "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 + }, "netmask": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", @@ -4990,16 +4552,16 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "noble-ed25519": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/noble-ed25519/-/noble-ed25519-1.2.5.tgz", + "integrity": "sha512-7vst+4UhM5QU3jJ3pUqPMKBCOePrxBojmoQa59qcSnYvjFF/T4jqb4WISlfslcWyBw7G5H9V/acpcAxMd8DzUQ==" + }, "node-addon-api": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" }, - "node-fetch": { - "version": "npm:@achingbrain/node-fetch@2.6.7", - "resolved": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-iTASGs+HTFK5E4ZqcMsHmeJ4zodyq8L38lZV33jwqcBJYoUt3HjN4+ot+O9/0b+ke8ddE7UgOtVuZN/OkV19/g==" - }, "node-forge": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", @@ -5046,16 +4608,6 @@ "requires": { "lru-cache": "^6.0.0" } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "optional": true, - "requires": { - "isexe": "^2.0.0" - } } } }, @@ -5092,12 +4644,11 @@ "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=", - "dev": true, + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "requires": { - "path-key": "^2.0.0" + "path-key": "^3.0.0" } }, "nwsapi": { @@ -5183,6 +4734,32 @@ "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.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -5333,10 +4910,9 @@ "dev": true }, "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true + "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", @@ -5381,9 +4957,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, "pirates": { @@ -5437,6 +5013,12 @@ "netmask": "^2.0.2" } }, + "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.1", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", @@ -5448,9 +5030,9 @@ } }, "protobufjs": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.2.tgz", - "integrity": "sha512-27yj+04uF6ya9l+qfpH187aqEzfCF4+Uit0I9ZBQVqK09hk/SQzKa2MUqUpXaVa7LOFRg1TSSr3lVxGOk6c0SQ==", + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -5463,7 +5045,7 @@ "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/long": "^4.0.1", - "@types/node": "^13.7.0", + "@types/node": ">=13.7.0", "long": "^4.0.0" } }, @@ -5610,15 +5192,6 @@ "uuid": "^3.3.2" }, "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -5626,38 +5199,6 @@ } } }, - "request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "requires": { - "lodash": "^4.17.19" - } - }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "dev": true, - "requires": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -5733,9 +5274,9 @@ "dev": true }, "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + "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", @@ -5807,6 +5348,34 @@ } } }, + "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" + } + }, + "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" + } + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -5830,6 +5399,15 @@ } } }, + "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" + } + }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -5856,6 +5434,12 @@ } } }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -5886,6 +5470,42 @@ "remove-trailing-separator": "^1.0.1" } }, + "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, + "requires": { + "path-key": "^2.0.0" + } + }, + "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 + }, "to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", @@ -5895,6 +5515,15 @@ "is-number": "^3.0.0", "repeat-string": "^1.6.1" } + }, + "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" + } } } }, @@ -5971,19 +5600,17 @@ } }, "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, + "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": "^1.0.0" + "shebang-regex": "^3.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 + "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", @@ -5992,6 +5619,17 @@ "dev": true, "optional": true }, + "shiki": { + "version": "0.9.10", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.10.tgz", + "integrity": "sha512-xeM7Oc6hY+6iW5O/T5hor8ul7mEprzyl5y4r5zthEHToQNw7MIhREMgU3r2gKDB0NaMLNrkcEQagudCdzE13Lg==", + "dev": true, + "requires": { + "json5": "^2.2.0", + "onigasm": "^2.2.5", + "vscode-textmate": "5.2.0" + } + }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -6205,9 +5843,9 @@ } }, "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "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 }, "split-string": { @@ -6238,13 +5876,6 @@ "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" - }, - "dependencies": { - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - } } }, "stack-utils": { @@ -6285,12 +5916,6 @@ } } }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, "stream-to-it": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/stream-to-it/-/stream-to-it-0.2.4.tgz", @@ -6360,9 +5985,9 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" }, "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "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" @@ -6487,28 +6112,18 @@ } }, "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, + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "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 - } + "psl": "^1.1.28", + "punycode": "^2.1.1" } }, "tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "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" @@ -6523,9 +6138,9 @@ } }, "ts-jest": { - "version": "26.5.4", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.4.tgz", - "integrity": "sha512-I5Qsddo+VTm94SukBJ4cPimOoFZsYTeElR2xy6H2TOVs+NsvgYglW8KuQgKoApOKuaU/Ix/vrF9ebFZlb5D2Pg==", + "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, "requires": { "bs-logger": "0.x", @@ -6550,9 +6165,9 @@ } }, "yargs-parser": { - "version": "20.2.7", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", - "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", + "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 } } @@ -6600,12 +6215,50 @@ "is-typedarray": "^1.0.0" } }, - "typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "typedoc": { + "version": "0.21.9", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.21.9.tgz", + "integrity": "sha512-VRo7aII4bnYaBBM1lhw4bQFmUcDQV8m8tqgjtc7oXl87jc1Slbhfw2X5MccfcR2YnEClHDWgsiQGgNB8KJXocA==", + "dev": true, + "requires": { + "glob": "^7.1.7", + "handlebars": "^4.7.7", + "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" + } + }, + "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 }, + "typedoc-plugin-markdown": { + "version": "3.10.4", + "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.10.4.tgz", + "integrity": "sha512-if9w7S9fXLg73AYi/EoRSEhTOZlg3I8mIP8YEmvzSE33VrNXC9/hA0nVcLEwFVJeQY7ay6z67I6kW0KIv7LjeA==", + "dev": true, + "requires": { + "handlebars": "^4.7.7" + } + }, + "typescript": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", + "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", + "dev": true + }, + "uglify-js": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.1.tgz", + "integrity": "sha512-JhS3hmcVaXlp/xSo3PKY5R0JqKs5M3IV+exdLHW99qKvKivPO4Z8qbej6mte17SOPqAOVMjt/XGgWacnFSzM3g==", + "dev": true, + "optional": true + }, "uint8arrays": { "version": "2.1.10", "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-2.1.10.tgz", @@ -6626,6 +6279,12 @@ "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==", + "dev": true + }, "unordered-array-remove": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz", @@ -6716,9 +6375,9 @@ "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==" }, "v8-to-istanbul": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.1.tgz", - "integrity": "sha512-p0BB09E5FRjx0ELN6RgusIPsSPhtgexSRcKETybEs6IGOTXJSZqfwxp7r//55nnu0f1AxltY5VvdVqy2vZf9AA==", + "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, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -6745,9 +6404,9 @@ } }, "varint": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", - "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" }, "verror": { "version": "1.10.0", @@ -6759,6 +6418,12 @@ "extsprintf": "^1.2.0" } }, + "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", @@ -6799,6 +6464,17 @@ "dev": true, "requires": { "iconv-lite": "0.4.24" + }, + "dependencies": { + "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" + } + } } }, "whatwg-mimetype": { @@ -6808,13 +6484,13 @@ "dev": true }, "whatwg-url": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz", - "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==", + "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", - "tr46": "^2.0.2", + "tr46": "^2.1.0", "webidl-conversions": "^6.1.0" } }, @@ -6827,10 +6503,9 @@ } }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, + "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" } @@ -6847,6 +6522,12 @@ "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": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", diff --git a/package.json b/package.json index 785b7c69..67a18bb5 100644 --- a/package.json +++ b/package.json @@ -13,14 +13,15 @@ "test:node:all": "jest --env=node", "test:node:unit": "jest --env=node --testPathPattern=src/__test__/unit", "test:node:integration": "jest --env=node --testPathPattern=src/__test__/integration", - "build": "tsc" + "build": "tsc", + "build:docs": "typedoc --out docs --excludePrivate --hideBreadcrumbs --publicPath js-sdk/6_reference/ src/index.ts" }, "repository": "https://github.com/fluencelabs/fluence-js", "author": "Fluence Labs", "license": "Apache-2.0", "dependencies": { "@chainsafe/libp2p-noise": "4.0.0", - "@fluencelabs/avm": "0.14.3", + "@fluencelabs/avm": "0.14.4", "async": "3.2.0", "base64-js": "1.5.1", "bs58": "4.0.1", @@ -33,6 +34,7 @@ "libp2p-websockets": "0.16.1", "loglevel": "1.7.0", "multiaddr": "10.0.0", + "noble-ed25519": "^1.2.5", "peer-id": "0.15.3", "uuid": "8.3.0" }, @@ -40,6 +42,8 @@ "@types/jest": "^26.0.22", "jest": "^26.6.3", "ts-jest": "^26.5.4", - "typescript": "^3.9.5" + "typedoc": "^0.21.9", + "typedoc-plugin-markdown": "^3.10.4", + "typescript": "^4.0.0" } } diff --git a/src/FluenceClient.ts b/src/FluenceClient.ts deleted file mode 100644 index 20a33172..00000000 --- a/src/FluenceClient.ts +++ /dev/null @@ -1,150 +0,0 @@ -import log from 'loglevel'; -import { Multiaddr } from 'multiaddr'; -import PeerId, { isPeerId } from 'peer-id'; - -import { CallServiceHandler } from './internal/CallServiceHandler'; -import { ClientImpl } from './internal/ClientImpl'; -import { PeerIdB58 } from './internal/commonTypes'; -import { FluenceConnectionOptions } from './internal/FluenceConnection'; -import { generatePeerId, seedToPeerId } from './internal/peerIdUtils'; -import { RequestFlow } from './internal/RequestFlow'; -import { RequestFlowBuilder } from './internal/RequestFlowBuilder'; - -/** - * The class represents interface to Fluence Platform. To create a client use @see {@link createClient} function. - */ -export interface FluenceClient { - /** - * { string } Gets the base58 representation of the current peer id. Read only - */ - readonly relayPeerId: PeerIdB58 | undefined; - - /** - * { string } Gets the base58 representation of the connected relay's peer id. Read only - */ - readonly selfPeerId: PeerIdB58; - - /** - * { string } True if the client is connected to network. False otherwise. Read only - */ - readonly isConnected: boolean; - - /** - * The base handler which is used by every RequestFlow executed by this FluenceClient. - * Please note, that the handler is combined with the handler from RequestFlow before the execution occures. - * After this combination, middlewares from RequestFlow are executed before client handler's middlewares. - */ - readonly callServiceHandler: CallServiceHandler; - - /** - * Disconnects the client from the network - */ - disconnect(): Promise; - - /** - * Establish a connection to the node. If the connection is already established, disconnect and reregister all services in a new connection. - * - * @param multiaddr - */ - connect(multiaddr: string | Multiaddr): Promise; - - /** - * Initiates RequestFlow execution @see { @link RequestFlow } - * @param { RequestFlow } [ request ] - RequestFlow to start the execution of - */ - initiateFlow(request: RequestFlow): Promise; -} - -type Node = { - peerId: string; - multiaddr: string; -}; - -/** - * Creates a Fluence client. If the `connectTo` is specified connects the client to the network - * @param { string | Multiaddr | Node } [connectTo] - Node in Fluence network to connect to. If not specified client will not be connected to the n - * @param { PeerId | string } [peerIdOrSeed] - The Peer Id of the created client. Specified either as PeerId structure or as seed string. Will be generated randomly if not specified - * @param { FluenceConnectionOptions } [options] - additional configuraton options for Fluence Connection made with the client - * @returns { Promise } Promise which will be resolved with the created FluenceClient - */ -export const createClient = async ( - connectTo?: string | Multiaddr | Node, - peerIdOrSeed?: PeerId | string, - options?: FluenceConnectionOptions, -): Promise => { - let peerId; - if (!peerIdOrSeed) { - peerId = await generatePeerId(); - } else if (isPeerId(peerIdOrSeed)) { - // keep unchanged - peerId = peerIdOrSeed; - } else { - // peerId is string, therefore seed - peerId = await seedToPeerId(peerIdOrSeed); - } - - const client = new ClientImpl(peerId); - await client.initAirInterpreter(); - - if (connectTo) { - let theAddress: Multiaddr; - let fromNode = (connectTo as any).multiaddr; - if (fromNode) { - theAddress = new Multiaddr(fromNode); - } else { - theAddress = new Multiaddr(connectTo as string); - } - - await client.connect(theAddress, options); - - if (options?.skipCheckConnection) { - if (!(await checkConnection(client, options.checkConnectionTTL))) { - throw new Error( - 'Connection check failed. Check if the node is working or try to connect to another node', - ); - } - } - } - - return client; -}; - -/** - * Checks the network connection by sending a ping-like request to relat node - * @param { FluenceClient } client - The Fluence Client instance. - */ -export const checkConnection = async (client: FluenceClient, ttl?: number): Promise => { - if (!client.isConnected) { - return false; - } - - const msg = Math.random().toString(36).substring(7); - const callbackFn = 'checkConnection'; - const callbackService = '_callback'; - - const [request, promise] = new RequestFlowBuilder() - .withRawScript( - `(seq - (call init_relay ("op" "identity") [msg] result) - (call %init_peer_id% ("${callbackService}" "${callbackFn}") [result]) - )`, - ) - .withTTL(ttl) - .withVariables({ - msg, - }) - .buildAsFetch<[string]>(callbackService, callbackFn); - - await client.initiateFlow(request); - - try { - const [result] = await promise; - if (result != msg) { - log.warn("unexpected behavior. 'identity' must return the passed arguments."); - } - return true; - } catch (e) { - log.error('Error on establishing connection: ', e); - return false; - } -}; diff --git a/src/__test__/integration/avm.spec.ts b/src/__test__/integration/avm.spec.ts new file mode 100644 index 00000000..b48ec537 --- /dev/null +++ b/src/__test__/integration/avm.spec.ts @@ -0,0 +1,50 @@ +import { FluencePeer } from '../../index'; +import { RequestFlowBuilder } from '../../internal/RequestFlowBuilder'; + +const peer = new FluencePeer(); + +describe('Avm spec', () => { + afterEach(async () => { + if (peer) { + await peer.uninit(); + } + }); + + it('Par execution should work', async () => { + // arrange + await peer.init(); + + let request; + const promise = new Promise((resolve) => { + let res = []; + request = new RequestFlowBuilder() + .withRawScript( + ` + (seq + (par + (call %init_peer_id% ("print" "print") ["1"]) + (null) + ) + (call %init_peer_id% ("print" "print") ["2"]) + ) + `, + ) + .configHandler((h) => { + h.onEvent('print', 'print', async (args) => { + res.push(args[0]); + if (res.length == 2) { + resolve(res); + } + }); + }) + .build(); + }); + + // act + await peer.internals.initiateFlow(request); + const res = await promise; + + // assert + expect(res).toStrictEqual(['1', '2']); + }); +}); diff --git a/src/__test__/integration/builtins.spec.ts b/src/__test__/integration/builtins.spec.ts deleted file mode 100644 index ec32026f..00000000 --- a/src/__test__/integration/builtins.spec.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { - addBlueprint, - addScript, - createService, - getBlueprints, - getInterfaces, - getModules, - removeScript, - uploadModule, -} from '../../internal/builtins'; -import { ModuleConfig } from '../../internal/moduleConfig'; -import { createClient, FluenceClient } from '../../FluenceClient'; -import { nodes } from '../connection'; - -let client: FluenceClient; - -describe('Builtins usage suite', () => { - afterEach(async () => { - if (client) { - await client.disconnect(); - } - }); - - jest.setTimeout(10000); - - it('get_modules', async function () { - client = await createClient(nodes[0].multiaddr); - - let modulesList = await getModules(client); - - expect(modulesList).not.toBeUndefined; - }); - - it('get_interfaces', async function () { - client = await createClient(nodes[0].multiaddr); - - let interfaces = await getInterfaces(client); - - expect(interfaces).not.toBeUndefined; - }); - - it('get_blueprints', async function () { - client = await createClient(nodes[0].multiaddr); - - let bpList = await getBlueprints(client); - - expect(bpList).not.toBeUndefined; - }); - - it('upload_modules', async function () { - client = await createClient(nodes[0].multiaddr); - - let config: ModuleConfig = { - name: 'test_broken_module', - mem_pages_count: 100, - logger_enabled: true, - wasi: { - envs: { a: 'b' }, - preopened_files: ['a', 'b'], - mapped_dirs: { c: 'd' }, - }, - mounted_binaries: { e: 'f' }, - }; - - let base64 = 'MjNy'; - - await uploadModule(client, 'test_broken_module', base64, config, 10000); - }); - - it('add_blueprint', async function () { - client = await createClient(nodes[0].multiaddr); - - let bpId = 'some'; - - let bpIdReturned = await addBlueprint(client, 'test_broken_blueprint', ['test_broken_module'], bpId); - let allBps = await getBlueprints(client); - const allBpIds = allBps.map((x) => x.id); - - expect(allBpIds).toContain(bpIdReturned); - }); - - it('create broken blueprint', async function () { - client = await createClient(nodes[0].multiaddr); - - let promise = createService(client, 'test_broken_blueprint'); - - await expect(promise).rejects.toMatchObject({ - msg: expect.stringContaining("Blueprint 'test_broken_blueprint' wasn't found"), - instruction: expect.stringContaining('blueprint_id'), - }); - }); - - it('add and remove script', async function () { - client = await createClient(nodes[0].multiaddr); - - let script = ` - (seq - (call "${client.relayPeerId}" ("op" "identity") []) - (call "${client.selfPeerId}" ("test" "test1") ["1" "2" "3"] result) - ) - `; - - let resMakingPromise = new Promise((resolve) => { - client.callServiceHandler.on('test', 'test1', (args, _) => { - resolve([...args]); - return {}; - }); - }); - - let scriptId = await addScript(client, script); - - await resMakingPromise - .then((args) => { - expect(args as string[]).toEqual(['1', '2', '3']); - }) - .finally(() => { - removeScript(client, scriptId); - }); - - expect(scriptId).not.toBeUndefined; - }); -}); diff --git a/src/__test__/integration/compiler/compiler.spec.ts b/src/__test__/integration/compiler/compiler.spec.ts new file mode 100644 index 00000000..c13b702c --- /dev/null +++ b/src/__test__/integration/compiler/compiler.spec.ts @@ -0,0 +1,161 @@ +import { FluencePeer } from '../../..'; +import { RequestFlowBuilder } from '../../../internal/RequestFlowBuilder'; +import { callMeBack, registerHelloWorld } from './gen1'; + +describe('Compiler support infrastructure tests', () => { + it('Compiled code for function should work', async () => { + // arrange + await FluencePeer.default.init(); + + // act + const res = new Promise((resolve) => { + callMeBack((arg0, arg1, params) => { + resolve({ + arg0: arg0, + arg1: arg1, + arg0Tetraplet: params.tetraplets.arg0[0], // completion should work here + arg1Tetraplet: params.tetraplets.arg1[0], // completion should work here + }); + }); + }); + + // assert + expect(await res).toMatchObject({ + arg0: 'hello, world', + arg1: 42, + + arg0Tetraplet: { + function_name: '', + json_path: '', + // peer_pk: '12D3KooWMwDDVRPEn5YGrN5LvVFLjNuBmokaeKfpLUgxsSkqRwwv', + service_id: '', + }, + + arg1Tetraplet: { + function_name: '', + json_path: '', + // peer_pk: '12D3KooWMwDDVRPEn5YGrN5LvVFLjNuBmokaeKfpLUgxsSkqRwwv', + service_id: '', + }, + }); + + await FluencePeer.default.uninit(); + }); + + it('Compiled code for service should work', async () => { + // arrange + await FluencePeer.default.init(); + + // act + const helloPromise = new Promise((resolve) => { + registerHelloWorld('hello_world', { + sayHello: (s, params) => { + const tetrapelt = params.tetraplets.s; // completion should work here + resolve(s); + }, + getNumber: (params) => { + // ctx.tetraplets should be {} + return 42; + }, + }); + }); + + const [request, getNumberPromise] = new RequestFlowBuilder() + .withRawScript( + `(seq + (seq + (call %init_peer_id% ("hello_world" "sayHello") ["hello world!"]) + (call %init_peer_id% ("hello_world" "getNumber") [] result) + ) + (call %init_peer_id% ("callback" "callback") [result]) + )`, + ) + .buildAsFetch<[string]>('callback', 'callback'); + await FluencePeer.default.internals.initiateFlow(request); + + // assert + expect(await helloPromise).toBe('hello world!'); + expect(await getNumberPromise).toStrictEqual([42]); + + await FluencePeer.default.uninit(); + }); + + it('Compiled code for function should work with another peer', async () => { + // arrange + const peer = new FluencePeer(); + await peer.init(); + + // act + const res = new Promise((resolve) => { + callMeBack(peer, (arg0, arg1, params) => { + resolve({ + arg0: arg0, + arg1: arg1, + arg0Tetraplet: params.tetraplets.arg0[0], // completion should work here + arg1Tetraplet: params.tetraplets.arg1[0], // completion should work here + }); + }); + }); + + // assert + expect(await res).toMatchObject({ + arg0: 'hello, world', + arg1: 42, + + arg0Tetraplet: { + function_name: '', + json_path: '', + // peer_pk: '12D3KooWMwDDVRPEn5YGrN5LvVFLjNuBmokaeKfpLUgxsSkqRwwv', + service_id: '', + }, + + arg1Tetraplet: { + function_name: '', + json_path: '', + // peer_pk: '12D3KooWMwDDVRPEn5YGrN5LvVFLjNuBmokaeKfpLUgxsSkqRwwv', + service_id: '', + }, + }); + + await peer.uninit(); + }); + + it('Compiled code for service should work another peer', async () => { + // arrange + const peer = new FluencePeer(); + await peer.init(); + + // act + const helloPromise = new Promise((resolve) => { + registerHelloWorld(peer, 'hello_world', { + sayHello: (s, params) => { + const tetrapelt = params.tetraplets.s; // completion should work here + resolve(s); + }, + getNumber: (params) => { + // ctx.tetraplets should be {} + return 42; + }, + }); + }); + + const [request, getNumberPromise] = new RequestFlowBuilder() + .withRawScript( + `(seq + (seq + (call %init_peer_id% ("hello_world" "sayHello") ["hello world!"]) + (call %init_peer_id% ("hello_world" "getNumber") [] result) + ) + (call %init_peer_id% ("callback" "callback") [result]) + )`, + ) + .buildAsFetch<[string]>('callback', 'callback'); + await peer.internals.initiateFlow(request); + + // assert + expect(await helloPromise).toBe('hello world!'); + expect(await getNumberPromise).toStrictEqual([42]); + + await peer.uninit(); + }); +}); diff --git a/src/__test__/integration/compiler/gen1.ts b/src/__test__/integration/compiler/gen1.ts new file mode 100644 index 00000000..045898d4 --- /dev/null +++ b/src/__test__/integration/compiler/gen1.ts @@ -0,0 +1,177 @@ +import { ResultCodes, RequestFlow, RequestFlowBuilder, CallParams } from '../../../internal/compilerSupport/v1'; +import { FluencePeer } from '../../../index'; + +/* + +-- file to generate functions below from + +service HelloWorld("default"): + sayHello(s: string) + getNumber() -> i32 + +func callMeBack(callback: string, i32 -> ()): + callback("hello, world", 42) + +*/ + +/** + * + * This file is auto-generated. Do not edit manually: changes may be erased. + * Generated by Aqua compiler: https://github.com/fluencelabs/aqua/. + * If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues + * Aqua version: 0.2.2-SNAPSHOT + * + */ + +// Services + +export interface HelloWorldDef { + getNumber: (callParams: CallParams) => number; + sayHello: (s: string, callParams: CallParams<'s'>) => void; +} + +export function registerHelloWorld(service: HelloWorldDef): void; +export function registerHelloWorld(serviceId: string, service: HelloWorldDef): void; +export function registerHelloWorld(peer: FluencePeer, service: HelloWorldDef): void; +export function registerHelloWorld(peer: FluencePeer, serviceId: string, service: HelloWorldDef): void; +export function registerHelloWorld(...args) { + let peer: FluencePeer; + let serviceId; + let service; + if (args[0] instanceof FluencePeer) { + peer = args[0]; + } else { + peer = FluencePeer.default; + } + + if (typeof args[0] === 'string') { + serviceId = args[0]; + } else if (typeof args[1] === 'string') { + serviceId = args[1]; + } else { + serviceId = 'default'; + } + + if (!(args[0] instanceof FluencePeer) && typeof args[0] === 'object') { + service = args[0]; + } else if (typeof args[1] === 'object') { + service = args[1]; + } else { + service = args[2]; + } + + peer.internals.callServiceHandler.use((req, resp, next) => { + if (req.serviceId !== serviceId) { + next(); + return; + } + + if (req.fnName === 'getNumber') { + const callParams = { + ...req.particleContext, + tetraplets: {}, + }; + resp.retCode = ResultCodes.success; + resp.result = service.getNumber(callParams); + } + + if (req.fnName === 'sayHello') { + const callParams = { + ...req.particleContext, + tetraplets: { + s: req.tetraplets[0], + }, + }; + resp.retCode = ResultCodes.success; + service.sayHello(req.args[0], callParams); + resp.result = {}; + } + + next(); + }); +} + +// Functions + +export function callMeBack( + callback: (arg0: string, arg1: number, callParams: CallParams<'arg0' | 'arg1'>) => void, + config?: { ttl?: number }, +): Promise; +export function callMeBack( + peer: FluencePeer, + callback: (arg0: string, arg1: number, callParams: CallParams<'arg0' | 'arg1'>) => void, + config?: { ttl?: number }, +): Promise; +export function callMeBack(...args) { + let peer: FluencePeer; + let callback; + let config; + if (args[0] instanceof FluencePeer) { + peer = args[0]; + callback = args[1]; + config = args[2]; + } else { + peer = FluencePeer.default; + callback = args[0]; + config = args[1]; + } + + let request: RequestFlow; + const promise = new Promise((resolve, reject) => { + const r = new RequestFlowBuilder() + .disableInjections() + .withRawScript( + ` + (xor + (seq + (call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-) + (xor + (call %init_peer_id% ("callbackSrv" "callback") ["hello, world" 42]) + (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1]) + ) + ) + (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2]) +) + + `, + ) + .configHandler((h) => { + h.on('getDataSrv', '-relay-', () => { + return peer.connectionInfo.connectedRelay || null; + }); + + h.use((req, resp, next) => { + if (req.serviceId === 'callbackSrv' && req.fnName === 'callback') { + const callParams = { + ...req.particleContext, + tetraplets: { + arg0: req.tetraplets[0], + arg1: req.tetraplets[1], + }, + }; + resp.retCode = ResultCodes.success; + callback(req.args[0], req.args[1], callParams); + resp.result = {}; + } + next(); + }); + + h.onEvent('callbackSrv', 'response', (args) => {}); + + h.onEvent('errorHandlingSrv', 'error', (args) => { + const [err] = args; + reject(err); + }); + }) + .handleScriptError(reject) + .handleTimeout(() => { + reject('Request timed out for callMeBack'); + }); + if (config && config.ttl) { + r.withTTL(config.ttl); + } + request = r.build(); + }); + peer.internals.initiateFlow(request!); + return Promise.race([promise, Promise.resolve()]); +} diff --git a/src/__test__/integration/legacy.api.spec.ts b/src/__test__/integration/legacy.api.spec.ts deleted file mode 100644 index d5b42375..00000000 --- a/src/__test__/integration/legacy.api.spec.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { Particle, sendParticle, registerServiceFunction, subscribeToEvent, sendParticleAsFetch } from '../../api'; -import { FluenceClient, createClient } from '../../FluenceClient'; -import { nodes } from '../connection'; - -let client: FluenceClient; - -describe('Legacy api suite', () => { - afterEach(async () => { - if (client) { - await client.disconnect(); - } - }); - - it('sendParticle', async () => { - client = await createClient(nodes[0]); - - const result = new Promise((resolve) => { - subscribeToEvent(client, 'callback', 'callback', (args) => { - resolve(args[0]); - }); - }); - - const script = `(seq - (call init_relay ("op" "identity") []) - (call %init_peer_id% ("callback" "callback") [arg]) - )`; - - const data = { - arg: 'hello world!', - }; - - await sendParticle(client, new Particle(script, data, 7000)); - - expect(await result).toBe('hello world!'); - }); - - it('sendParticle Error', async () => { - client = await createClient(nodes[0]); - - const script = ` - (call init_relay ("incorrect" "service") []) - `; - - const promise = new Promise((resolve, reject) => { - sendParticle(client, new Particle(script), reject); - }); - - await expect(promise).rejects.toMatchObject({ - msg: expect.stringContaining("Service with id 'incorrect' not found"), - instruction: expect.stringContaining('incorrect'), - }); - }); - - it('sendParticleAsFetch', async () => { - client = await createClient(nodes[0]); - - const script = `(seq - (call init_relay ("op" "identity") []) - (call %init_peer_id% ("service" "fn") [arg]) - )`; - - const data = { - arg: 'hello world!', - }; - - const [result] = await sendParticleAsFetch<[string]>(client, new Particle(script, data, 7000), 'fn', 'service'); - - expect(result).toBe('hello world!'); - }); - - it('sendParticleAsFetch Error', async () => { - client = await createClient(nodes[0]); - - const script = ` - (call init_relay ("incorrect" "service") []) - `; - - const promise = sendParticleAsFetch<[string]>(client, new Particle(script), 'fn', 'service'); - - await expect(promise).rejects.toMatchObject({ - msg: expect.stringContaining("Service with id 'incorrect' not found"), - instruction: expect.stringContaining('incorrect'), - }); - }); - - it('registerServiceFunction', async () => { - client = await createClient(nodes[0]); - - registerServiceFunction(client, 'service', 'fn', (args) => { - return { res: args[0] + ' world!' }; - }); - - const script = `(seq - (call %init_peer_id% ("service" "fn") ["hello"] result) - (call %init_peer_id% ("callback" "callback") [result]) - )`; - - const [result] = await sendParticleAsFetch<[string]>( - client, - new Particle(script, {}, 7000), - 'callback', - 'callback', - ); - - expect(result).toEqual({ res: 'hello world!' }); - }); - - it('subscribeToEvent', async () => { - client = await createClient(nodes[0]); - - const promise = new Promise((resolve) => { - subscribeToEvent(client, 'service', 'fn', (args) => { - resolve(args[0] + ' world!'); - }); - }); - - const script = ` - (call %init_peer_id% ("service" "fn") ["hello"]) - `; - - await sendParticle(client, new Particle(script, {}, 7000)); - - const result = await promise; - expect(result).toBe('hello world!'); - }); -}); diff --git a/src/__test__/integration/client.spec.ts b/src/__test__/integration/peer.spec.ts similarity index 68% rename from src/__test__/integration/client.spec.ts rename to src/__test__/integration/peer.spec.ts index 68770a13..73e4205c 100644 --- a/src/__test__/integration/client.spec.ts +++ b/src/__test__/integration/peer.spec.ts @@ -1,22 +1,22 @@ -import { checkConnection, createClient, FluenceClient } from '../../FluenceClient'; import { Multiaddr } from 'multiaddr'; import { nodes } from '../connection'; import { RequestFlowBuilder } from '../../internal/RequestFlowBuilder'; import log from 'loglevel'; +import { FluencePeer } from '../../index'; +import { checkConnection } from '../../internal/utils'; -let client: FluenceClient; +const peer = new FluencePeer(); describe('Typescript usage suite', () => { afterEach(async () => { - if (client) { - await client.disconnect(); + if (peer) { + await peer.uninit(); } }); it('should make a call through network', async () => { // arrange - client = await createClient(); - await client.connect(nodes[0].multiaddr); + await peer.init({ connectTo: nodes[0] }); // act const [request, promise] = new RequestFlowBuilder() @@ -27,7 +27,8 @@ describe('Typescript usage suite', () => { )`, ) .buildAsFetch<[string]>('callback', 'callback'); - await client.initiateFlow(request); + await peer.internals.initiateFlow(request); + console.log(request.getParticle().script); // assert const [result] = await promise; @@ -35,30 +36,30 @@ describe('Typescript usage suite', () => { }); it('check connection should work', async function () { - client = await createClient(); - await client.connect(nodes[0].multiaddr); + await peer.init({ connectTo: nodes[0] }); - let isConnected = await checkConnection(client); + let isConnected = await checkConnection(peer); expect(isConnected).toEqual(true); }); it('check connection should work with ttl', async function () { - client = await createClient(); - await client.connect(nodes[0].multiaddr); + await peer.init({ connectTo: nodes[0] }); - let isConnected = await checkConnection(client, 10000); + let isConnected = await checkConnection(peer, 10000); expect(isConnected).toEqual(true); }); it('two clients should work inside the same time browser', async () => { // arrange - const client1 = await createClient(nodes[0].multiaddr); - const client2 = await createClient(nodes[0].multiaddr); + const peer1 = new FluencePeer(); + await peer1.init({ connectTo: nodes[0] }); + const peer2 = new FluencePeer(); + await peer2.init({ connectTo: nodes[0] }); let resMakingPromise = new Promise((resolve) => { - client2.callServiceHandler.onEvent('test', 'test', (args, _) => { + peer2.internals.callServiceHandler.onEvent('test', 'test', (args, _) => { resolve([...args]); return {}; }); @@ -66,8 +67,8 @@ describe('Typescript usage suite', () => { let script = ` (seq - (call "${client1.relayPeerId}" ("op" "identity") []) - (call "${client2.selfPeerId}" ("test" "test") [a b c d]) + (call "${peer1.connectionInfo.connectedRelay}" ("op" "identity") []) + (call "${peer2.connectionInfo.selfPeerId}" ("test" "test") [a b c d]) ) `; @@ -77,23 +78,23 @@ describe('Typescript usage suite', () => { data.set('c', 'some c'); data.set('d', 'some d'); - await client1.initiateFlow(new RequestFlowBuilder().withRawScript(script).withVariables(data).build()); + await peer1.internals.initiateFlow(new RequestFlowBuilder().withRawScript(script).withVariables(data).build()); let res = await resMakingPromise; expect(res).toEqual(['some a', 'some b', 'some c', 'some d']); - await client1.disconnect(); - await client2.disconnect(); + await peer1.uninit(); + await peer2.uninit(); }); describe('should make connection to network', () => { it('address as string', async () => { // arrange - const addr = nodes[0].multiaddr; + const addr = nodes[0]; // act - client = await createClient(addr); - const isConnected = await checkConnection(client); + await peer.init({ connectTo: addr }); + const isConnected = await checkConnection(peer); // assert expect(isConnected).toBeTruthy; @@ -104,8 +105,8 @@ describe('Typescript usage suite', () => { const addr = new Multiaddr(nodes[0].multiaddr); // act - client = await createClient(addr); - const isConnected = await checkConnection(client); + await peer.init({ connectTo: addr }); + const isConnected = await checkConnection(peer); // assert expect(isConnected).toBeTruthy; @@ -116,8 +117,8 @@ describe('Typescript usage suite', () => { const addr = nodes[0]; // act - client = await createClient(addr); - const isConnected = await checkConnection(client); + await peer.init({ connectTo: addr }); + const isConnected = await checkConnection(peer); // assert expect(isConnected).toBeTruthy; @@ -125,11 +126,11 @@ describe('Typescript usage suite', () => { it('peerid as peer id', async () => { // arrange - const addr = nodes[0].multiaddr; + const addr = nodes[0]; // act - client = await createClient(addr); - const isConnected = await checkConnection(client); + await peer.init({ connectTo: addr }); + const isConnected = await checkConnection(peer); // assert expect(isConnected).toBeTruthy; @@ -137,11 +138,11 @@ describe('Typescript usage suite', () => { it('peerid as seed', async () => { // arrange - const addr = nodes[0].multiaddr; + const addr = nodes[0]; // act - client = await createClient(addr); - const isConnected = await checkConnection(client); + await peer.init({ connectTo: addr }); + const isConnected = await checkConnection(peer); // assert expect(isConnected).toBeTruthy; @@ -149,11 +150,11 @@ describe('Typescript usage suite', () => { it('With connection options: dialTimeout', async () => { // arrange - const addr = nodes[0].multiaddr; + const addr = nodes[0]; // act - client = await createClient(addr, undefined, { dialTimeout: 100000 }); - const isConnected = await checkConnection(client); + await peer.init({ connectTo: addr, dialTimeoutMs: 100000 }); + const isConnected = await checkConnection(peer); // assert expect(isConnected).toBeTruthy; @@ -161,11 +162,11 @@ describe('Typescript usage suite', () => { it('With connection options: skipCheckConnection', async () => { // arrange - const addr = nodes[0].multiaddr; + const addr = nodes[0]; // act - client = await createClient(addr, undefined, { skipCheckConnection: true }); - const isConnected = await checkConnection(client); + await peer.init({ connectTo: addr, skipCheckConnection: true }); + const isConnected = await checkConnection(peer); // assert expect(isConnected).toBeTruthy; @@ -173,11 +174,11 @@ describe('Typescript usage suite', () => { it('With connection options: checkConnectionTTL', async () => { // arrange - const addr = nodes[0].multiaddr; + const addr = nodes[0]; // act - client = await createClient(addr, undefined, { checkConnectionTTL: 1000 }); - const isConnected = await checkConnection(client); + await peer.init({ connectTo: addr, checkConnectionTimeoutMs: 1000 }); + const isConnected = await checkConnection(peer); // assert expect(isConnected).toBeTruthy; @@ -198,8 +199,8 @@ describe('Typescript usage suite', () => { .buildWithErrorHandling(); // act - client = await createClient(nodes[0].multiaddr); - await client.initiateFlow(request); + await peer.init({ connectTo: nodes[0] }); + await peer.internals.initiateFlow(request); // assert await expect(promise).rejects.toMatchObject({ @@ -225,19 +226,19 @@ describe('Typescript usage suite', () => { .buildWithErrorHandling(); // act - client = await createClient(); - await client.initiateFlow(request); + await peer.init(); + await peer.internals.initiateFlow(request); // assert await expect(promise).rejects.toMatch('service failed internally'); }); - it('Should throw correct message when calling non existing local service', async function () { + it.skip('Should throw correct message when calling non existing local service', async function () { // arrange - client = await createClient(); + await peer.init(); // act - const res = callIdentifyOnInitPeerId(client); + const res = callIdentifyOnInitPeerId(peer); // assert await expect(res).rejects.toMatchObject({ @@ -250,7 +251,7 @@ describe('Typescript usage suite', () => { it('Should not crash if undefined is passed as a variable', async () => { // arrange - client = await createClient(); + await peer.init(); const [request, promise] = new RequestFlowBuilder() .withRawScript( ` @@ -264,7 +265,7 @@ describe('Typescript usage suite', () => { .buildAsFetch('return', 'return'); // act - await client.initiateFlow(request); + await peer.internals.initiateFlow(request); const [res] = await promise; // assert @@ -273,14 +274,14 @@ describe('Typescript usage suite', () => { it('Should throw correct error when the client tries to send a particle not to the relay', async () => { // arrange - client = await createClient(); + await peer.init(); // act const [req, promise] = new RequestFlowBuilder() .withRawScript('(call "incorrect_peer_id" ("any" "service") [])') .buildWithErrorHandling(); - await client.initiateFlow(req); + await peer.internals.initiateFlow(req); // assert await expect(promise).rejects.toMatch( @@ -289,7 +290,7 @@ describe('Typescript usage suite', () => { }); }); -async function callIdentifyOnInitPeerId(client: FluenceClient): Promise { +async function callIdentifyOnInitPeerId(peer: FluencePeer): Promise { let request; const promise = new Promise((resolve, reject) => { request = new RequestFlowBuilder() @@ -301,6 +302,6 @@ async function callIdentifyOnInitPeerId(client: FluenceClient): Promise ({ +const req = (): CallServiceData => ({ serviceId: 'service', fnName: 'fn name', args: [], tetraplets: [], particleContext: { particleId: 'id', + initPeerId: 'init peer id', + timestamp: 595951200, + ttl: 595961200, + signature: 'sig', }, }); @@ -102,7 +107,7 @@ describe('Call service handler tests', () => { // assert expect(res).toMatchObject({ retCode: ResultCodes.exceptionInHandler, - result: 'Error: some error', + result: 'Handler failed. fnName="fn name" serviceId="service" error: Error: some error', }); }); diff --git a/src/__test__/unit/KeyPair.spec.ts b/src/__test__/unit/KeyPair.spec.ts new file mode 100644 index 00000000..bcac9e04 --- /dev/null +++ b/src/__test__/unit/KeyPair.spec.ts @@ -0,0 +1,32 @@ +import { encode } from 'bs58'; +import * as base64 from 'base64-js'; +import PeerId from 'peer-id'; +import { KeyPair } from '../../internal/KeyPair'; + +describe('KeyPair tests', () => { + it('should create private key from seed and back', async function () { + // arrange + const sk = 'z1x3cVXhk9nJKE1pZaX9KxccUBzxu3aGlaUjDdAB2oY='; + + // act + const keyPair = await KeyPair.fromEd25519SK(sk); + const sk2 = peerIdToEd25519SK(keyPair.Libp2pPeerId); + + // assert + expect(sk2).toBe(sk); + }); +}); + +/** + * Converts peer id into base64 string contatining the 32 byte Ed25519S secret key + * @returns - base64 of Ed25519S secret key + */ +export const peerIdToEd25519SK = (peerId: PeerId): string => { + // export as [...private, ...public] array + const privateAndPublicKeysArray = peerId.privKey.marshal(); + // extract the private key + const pk = privateAndPublicKeysArray.slice(0, 32); + // serialize private key as base64 + const b64 = base64.fromByteArray(pk); + return b64; +}; diff --git a/src/__test__/unit/RequestFlow.spec.ts b/src/__test__/unit/RequestFlow.spec.ts index 7f475792..af96dae3 100644 --- a/src/__test__/unit/RequestFlow.spec.ts +++ b/src/__test__/unit/RequestFlow.spec.ts @@ -1,16 +1,16 @@ -import { seedToPeerId } from '../../internal/peerIdUtils'; +import { KeyPair } from '../../internal/KeyPair'; import { RequestFlow } from '../../internal/RequestFlow'; describe('Request flow tests', () => { it('particle initiation should work', async () => { // arrange jest.useFakeTimers(); - const seed = '4vzv3mg6cnjpEK24TXXLA3Ye7QrvKWPKqfbDvAKAyLK6'; + const sk = 'z1x3cVXhk9nJKE1pZaX9KxccUBzxu3aGlaUjDdAB2oY='; const mockDate = new Date(Date.UTC(2021, 2, 14)).valueOf(); Date.now = jest.fn(() => mockDate); const request = RequestFlow.createLocal('(null)', 10000); - const peerId = await seedToPeerId(seed); + const peerId = await (await KeyPair.fromEd25519SK(sk)).Libp2pPeerId; // act await request.initState(peerId); diff --git a/src/__test__/unit/WsTransport.spec.ts b/src/__test__/unit/WsTransport.spec.ts index 50c99b18..e32922d2 100644 --- a/src/__test__/unit/WsTransport.spec.ts +++ b/src/__test__/unit/WsTransport.spec.ts @@ -1,7 +1,7 @@ import { FluenceConnection } from '../../internal/FluenceConnection'; import Peer from 'libp2p'; import { Multiaddr } from 'multiaddr'; -import { generatePeerId } from '../../internal/peerIdUtils'; +import { KeyPair } from '../../internal/KeyPair'; describe('Ws Transport', () => { // TODO:: fix test @@ -10,7 +10,7 @@ describe('Ws Transport', () => { let multiaddr = new Multiaddr( '/ip4/127.0.0.1/tcp/1234/ws/p2p/12D3KooWMJ78GJrtCxVUpjLEedbPtnLDxkFQJ2wuefEdrxq6zwSs', ); - let peerId = await generatePeerId(); + let peerId = (await KeyPair.randomEd25519()).Libp2pPeerId; const connection = new FluenceConnection(multiaddr, peerId, peerId, (_) => {}); await (connection as any).createPeer(); let node = (connection as any).node as Peer; diff --git a/src/__test__/unit/air.spec.ts b/src/__test__/unit/air.spec.ts deleted file mode 100644 index cb3b49a9..00000000 --- a/src/__test__/unit/air.spec.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { createClient, FluenceClient } from '../../FluenceClient'; -import { RequestFlow } from '../../internal/RequestFlow'; -import { RequestFlowBuilder } from '../../internal/RequestFlowBuilder'; - -let client: FluenceClient; - -describe('== AIR suite', () => { - afterEach(async () => { - if (client) { - await client.disconnect(); - } - }); - - it('check init_peer_id', async function () { - // arrange - const serviceId = 'test_service'; - const fnName = 'return_first_arg'; - const script = `(call %init_peer_id% ("${serviceId}" "${fnName}") [%init_peer_id%])`; - - // prettier-ignore - const [request, promise] = new RequestFlowBuilder() - .withRawScript(script) - .buildAsFetch(serviceId, fnName); - - // act - client = await createClient(); - await client.initiateFlow(request); - const [result] = await promise; - - // assert - expect(result).toBe(client.selfPeerId); - }); - - it('call local function', async function () { - // arrange - const serviceId = 'test_service'; - const fnName = 'return_first_arg'; - - client = await createClient(); - - let res; - client.callServiceHandler.on(serviceId, fnName, (args, _) => { - res = args[0]; - return res; - }); - - // act - const arg = 'hello'; - const script = `(call %init_peer_id% ("${serviceId}" "${fnName}") ["${arg}"])`; - await client.initiateFlow(RequestFlow.createLocal(script)); - - // assert - expect(res).toEqual(arg); - }); - - describe('error handling', () => { - it('call broken script', async function () { - // arrange - const script = `(incorrect)`; - // prettier-ignore - const [request, error] = new RequestFlowBuilder() - .withRawScript(script) - .buildWithErrorHandling(); - - // act - client = await createClient(); - await client.initiateFlow(request); - - // assert - await expect(error).rejects.toContain("air can't be parsed"); - }); - - it('call script without ttl', async function () { - // arrange - const script = `(null)`; - // prettier-ignore - const [request, promise] = new RequestFlowBuilder() - .withTTL(1) - .withRawScript(script) - .buildAsFetch(); - - // act - client = await createClient(); - await client.initiateFlow(request); - - // assert - await expect(promise).rejects.toContain('Timed out after'); - }); - }); - - it('check particle arguments', async function () { - // arrange - const serviceId = 'test_service'; - const fnName = 'return_first_arg'; - const script = `(call %init_peer_id% ("${serviceId}" "${fnName}") [arg1])`; - - // prettier-ignore - const [request, promise] = new RequestFlowBuilder() - .withRawScript(script) - .withVariable('arg1', 'hello') - .buildAsFetch(serviceId, fnName); - - // act - client = await createClient(); - await client.initiateFlow(request); - const [result] = await promise; - - // assert - expect(result).toEqual('hello'); - }); - - it('check security tetraplet', async function () { - // arrange - const makeDataServiceId = 'make_data_service'; - const makeDataFnName = 'make_data'; - const getDataServiceId = 'get_data_service'; - const getDataFnName = 'get_data'; - - client = await createClient(); - - client.callServiceHandler.on(makeDataServiceId, makeDataFnName, (args, _) => { - return { - field: 42, - }; - }); - let res; - client.callServiceHandler.on(getDataServiceId, getDataFnName, (args, tetraplets) => { - res = { - args: args, - tetraplets: tetraplets, - }; - return args[0]; - }); - - // act - const script = ` - (seq - (call %init_peer_id% ("${makeDataServiceId}" "${makeDataFnName}") [] result) - (call %init_peer_id% ("${getDataServiceId}" "${getDataFnName}") [result.$.field]) - )`; - await client.initiateFlow(new RequestFlowBuilder().withRawScript(script).build()); - - // assert - const tetraplet = res.tetraplets[0][0]; - expect(tetraplet).toMatchObject({ - service_id: 'make_data_service', - function_name: 'make_data', - json_path: '$.field', - }); - }); - - it('check chain of services work properly', async function () { - // arrange - client = await createClient(); - - const serviceId1 = 'check1'; - const fnName1 = 'fn1'; - let res1; - client.callServiceHandler.on(serviceId1, fnName1, (args, _) => { - res1 = args[0]; - return res1; - }); - - const serviceId2 = 'check2'; - const fnName2 = 'fn2'; - let res2; - client.callServiceHandler.on(serviceId2, fnName2, (args, _) => { - res2 = args[0]; - return res2; - }); - - const serviceId3 = 'check3'; - const fnName3 = 'fn3'; - let res3; - client.callServiceHandler.on(serviceId3, fnName3, (args, _) => { - res3 = args; - return res3; - }); - - const arg1 = 'arg1'; - const arg2 = 'arg2'; - - // act - const script = `(seq - (seq - (call %init_peer_id% ("${serviceId1}" "${fnName1}") ["${arg1}"] result1) - (call %init_peer_id% ("${serviceId2}" "${fnName2}") ["${arg2}"] result2)) - (call %init_peer_id% ("${serviceId3}" "${fnName3}") [result1 result2])) - `; - await client.initiateFlow(new RequestFlowBuilder().withRawScript(script).build()); - - // assert - expect(res1).toEqual(arg1); - expect(res2).toEqual(arg2); - expect(res3).toEqual([res1, res2]); - }); -}); diff --git a/src/__test__/unit/ast.spec.ts b/src/__test__/unit/ast.spec.ts deleted file mode 100644 index 87c9a62c..00000000 --- a/src/__test__/unit/ast.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { AirInterpreter } from '@fluencelabs/avm'; - -describe('== AST parsing suite', () => { - it('parse simple script and return ast', async function () { - const interpreter = await AirInterpreter.create( - undefined as any, - undefined as any, - undefined as any, - undefined as any, - ); - let ast = interpreter.parseAir(` - (call "node" ("service" "function") [1 2 3] output) - `); - - ast = JSON.parse(ast); - - expect(ast).toEqual({ - Call: { - peer_part: { PeerPk: { Literal: 'node' } }, - function_part: { ServiceIdWithFuncName: [{ Literal: 'service' }, { Literal: 'function' }] }, - args: [ - { - Number: { - Int: 1, - }, - }, - { - Number: { - Int: 2, - }, - }, - { - Number: { - Int: 3, - }, - }, - ], - output: { - Variable: { Scalar: 'output' }, - }, - }, - }); - }); -}); diff --git a/src/__test__/unit/builtInHandler.spec.ts b/src/__test__/unit/builtInHandler.spec.ts index ea1e5e9a..3dfd4be5 100644 --- a/src/__test__/unit/builtInHandler.spec.ts +++ b/src/__test__/unit/builtInHandler.spec.ts @@ -43,6 +43,10 @@ describe('Tests for default handler', () => { tetraplets: [], particleContext: { particleId: 'some', + initPeerId: 'init peer id', + timestamp: 595951200, + ttl: 595961200, + signature: 'sig', }, }; diff --git a/src/__test__/unit/peerId.spec.ts b/src/__test__/unit/peerId.spec.ts deleted file mode 100644 index a1d351da..00000000 --- a/src/__test__/unit/peerId.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { encode } from 'bs58'; -import { peerIdToSeed, seedToPeerId } from '../..'; - -describe('Peer Id utils', () => { - it('should create private key from seed and back', async function () { - // prettier-ignore - let seed = [46, 188, 245, 171, 145, 73, 40, 24, 52, 233, 215, 163, 54, 26, 31, 221, 159, 179, 126, 106, 27, 199, 189, 194, 80, 133, 235, 42, 42, 247, 80, 201]; - let seedStr = encode(seed); - - let pid = await seedToPeerId(seedStr); - expect(peerIdToSeed(pid)).toEqual(seedStr); - }); -}); diff --git a/src/api.ts b/src/api.ts deleted file mode 100644 index b9f5cccb..00000000 --- a/src/api.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { RequestFlowBuilder } from './internal/RequestFlowBuilder'; -import { FluenceClient } from './FluenceClient'; -import { CallServiceResultType } from './internal/CallServiceHandler'; -import { SecurityTetraplet } from '@fluencelabs/avm'; - -/** - * The class representing Particle - a data structure used to perform operations on Fluence Network. It originates on some peer in the network, travels the network through a predefined path, triggering function execution along its way. - */ -export class Particle { - script: string; - data: Map; - ttl: number; - - /** - * Creates a particle with specified parameters. - * @param { String }script - Air script which defines the execution of a particle – its path, functions it triggers on peers, and so on. - * @param { Map | Record } data - Variables passed to the particle in the form of either JS Map or JS object with keys representing variable names and values representing values correspondingly - * @param { [Number]=7000 } ttl - Time to live, a timout after which the particle execution is stopped by AVM. - */ - constructor(script: string, data?: Map | Record, ttl?: number) { - this.script = script; - if (data === undefined) { - this.data = new Map(); - } else if (data instanceof Map) { - this.data = data; - } else { - this.data = new Map(); - for (let k in data) { - this.data.set(k, data[k]); - } - } - - this.ttl = ttl ?? 7000; - } -} - -/** - * Send a particle to Fluence Network using the specified Fluence Client. - * @param { FluenceClient } client - The Fluence Client instance. - * @param { Particle } particle - The particle to send. - */ -export const sendParticle = async ( - client: FluenceClient, - particle: Particle, - onError?: (err) => void, -): Promise => { - const [req, errorPromise] = new RequestFlowBuilder() - .withRawScript(particle.script) - .withVariables(particle.data) - .withTTL(particle.ttl) - .buildWithErrorHandling(); - - errorPromise.catch(onError); - - await client.initiateFlow(req); - return req.id; -}; - -/* - This map stores functions which unregister callbacks registered by registerServiceFunction - The key sould be created with makeKey. The value is the unresitration function - This is only needed to support legacy api -*/ -const handlersUnregistratorsMap = new Map(); -const makeKey = (client: FluenceClient, serviceId: string, fnName: string) => { - const pid = client.selfPeerId || ''; - return `${pid}/${serviceId}/${fnName}`; -}; - -/** - * Registers a function which can be called on the client from AVM. The registration is per client basis. - * @param { FluenceClient } client - The Fluence Client instance. - * @param { string } serviceId - The identifier of service which would be used to make calls from AVM - * @param { string } fnName - The identifier of function which would be used to make calls from AVM - * @param { (args: any[], tetraplets: SecurityTetraplet[][]) => object | boolean | number | string } handler - The handler which would be called by AVM. The result is any object passed back to AVM - */ -export const registerServiceFunction = ( - client: FluenceClient, - serviceId: string, - fnName: string, - handler: (args: any[], tetraplets: SecurityTetraplet[][]) => CallServiceResultType, -) => { - const unregister = client.callServiceHandler.on(serviceId, fnName, handler); - handlersUnregistratorsMap.set(makeKey(client, serviceId, fnName), unregister); -}; - -// prettier-ignore -/** - * Removes registers for the function previously registered with {@link registerServiceFunction} - * @param { FluenceClient } client - The Fluence Client instance. - * @param { string } serviceId - The identifier of service used in {@link registerServiceFunction} call - * @param { string } fnName - The identifier of function used in {@link registerServiceFunction} call - */ -export const unregisterServiceFunction = ( - client: FluenceClient, - serviceId: string, - fnName: string -) => { - const key = makeKey(client, serviceId, fnName); - const unuse = handlersUnregistratorsMap.get(key); - if(unuse) { - unuse(); - } - handlersUnregistratorsMap.delete(key); -}; - -/** - * Registers an event-like handler for all calls to the specific service\function pair from AVM. The registration is per client basis. Return a function which when called removes the subscription. - * Same as registerServiceFunction which immediately returns empty object. - * @param { FluenceClient } client - The Fluence Client instance. - * @param { string } serviceId - The identifier of service calls to which from AVM are transformed into events. - * @param { string } fnName - The identifier of function calls to which from AVM are transformed into events. - * @param { (args: any[], tetraplets: SecurityTetraplet[][]) => object } handler - The handler which would be called by AVM - * @returns { Function } - A function which when called removes the subscription. - */ -export const subscribeToEvent = ( - client: FluenceClient, - serviceId: string, - fnName: string, - handler: (args: any[], tetraplets: SecurityTetraplet[][]) => void, -): Function => { - const realHandler = (args: any[], tetraplets: SecurityTetraplet[][]) => { - // dont' block - setTimeout(() => { - handler(args, tetraplets); - }, 0); - - return {}; - }; - registerServiceFunction(client, serviceId, fnName, realHandler); - return () => { - unregisterServiceFunction(client, serviceId, fnName); - }; -}; - -/** - * Send a particle with a fetch-like semantics. In order to for this to work you have to you have to make a call to the same callbackServiceId\callbackFnName pair from Air script as specified by the parameters. The arguments of the call are returned as the resolve value of promise - * @param { FluenceClient } client - The Fluence Client instance. - * @param { Particle } particle - The particle to send. - * @param { string } callbackFnName - The identifier of function which should be used in Air script to pass the data to fetch "promise" - * @param { [string]='_callback' } callbackServiceId - The service identifier which should be used in Air script to pass the data to fetch "promise" - * @returns { Promise } - A promise which would be resolved with the data returned from AVM - */ -export const sendParticleAsFetch = async ( - client: FluenceClient, - particle: Particle, - callbackFnName: string, - callbackServiceId: string = '_callback', -): Promise => { - const [request, promise] = new RequestFlowBuilder() - .withRawScript(particle.script) - .withVariables(particle.data) - .withTTL(particle.ttl) - .buildAsFetch(callbackServiceId, callbackFnName); - - await client.initiateFlow(request); - - return promise; -}; diff --git a/src/api.unstable.ts b/src/api.unstable.ts deleted file mode 100644 index b414445a..00000000 --- a/src/api.unstable.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { RequestFlowBuilder } from './internal/RequestFlowBuilder'; -export * from './internal/CallServiceHandler'; diff --git a/src/index.ts b/src/index.ts index 89cd6777..5045359f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,14 +14,12 @@ * limitations under the License. */ -export { seedToPeerId, peerIdToSeed, generatePeerId } from './internal/peerIdUtils'; -export { PeerIdB58 } from './internal/commonTypes'; -export { SecurityTetraplet } from '@fluencelabs/avm'; -export * from './api'; -export * from './FluenceClient'; -export * from './internal/builtins'; import log, { LogLevelDesc } from 'loglevel'; +export { KeyPair } from './internal/KeyPair'; +export { FluencePeer, AvmLoglevel } from './internal/FluencePeer'; +export { PeerIdB58, CallParams } from './internal/commonTypes'; + export const setLogLevel = (level: LogLevelDesc) => { log.setLevel(level); }; diff --git a/src/internal/CallServiceHandler.ts b/src/internal/CallServiceHandler.ts index ad16fa9c..57d3afde 100644 --- a/src/internal/CallServiceHandler.ts +++ b/src/internal/CallServiceHandler.ts @@ -1,10 +1,10 @@ import { SecurityTetraplet } from '@fluencelabs/avm'; +import { PeerIdB58 } from './commonTypes'; export enum ResultCodes { success = 0, - noServiceFound = 1, + unkownError = 1, exceptionInHandler = 2, - unkownError = 1024, } /** @@ -15,7 +15,10 @@ interface ParticleContext { * The particle ID */ particleId: string; - [x: string]: any; + initPeerId: PeerIdB58; + timestamp: number; + ttl: number; + signature: string; } /** @@ -82,6 +85,20 @@ export interface CallServiceResult { */ export type Middleware = (req: CallServiceData, resp: CallServiceResult, next: Function) => void; +export class CallServiceArg { + val: T; + tetraplet: SecurityTetraplet[]; + + constructor(val: T, tetraplet: SecurityTetraplet[]) { + this.val = val; + this.tetraplet = tetraplet; + } +} + +type CallParams = ParticleContext & { + wrappedArgs: CallServiceArg[]; +}; + /** * Convenience middleware factory. Registeres a handler for a pair of 'serviceId/fnName'. * The return value of the handler is passed back to AVM @@ -92,11 +109,11 @@ export type Middleware = (req: CallServiceData, resp: CallServiceResult, next: F export const fnHandler = ( serviceId: string, fnName: string, - handler: (args: any[], tetraplets: SecurityTetraplet[][]) => CallServiceResultType, + handler: (args: any[], callParams: CallParams) => CallServiceResultType, ) => { return (req: CallServiceData, resp: CallServiceResult, next: Function): void => { if (req.fnName === fnName && req.serviceId === serviceId) { - const res = handler(req.args, req.tetraplets); + const res = handler(req.args, { ...req.particleContext, wrappedArgs: req.wrappedArgs }); resp.retCode = ResultCodes.success; resp.result = res; } @@ -112,14 +129,14 @@ export const fnHandler = ( * @param { (args: any[], tetraplets: SecurityTetraplet[][]) => void } handler - The handler which should handle the call. */ export const fnAsEventHandler = ( - serviceId: string, + serviceId: string, // force format fnName: string, - handler: (args: any[], tetraplets: SecurityTetraplet[][]) => void, + handler: (args: any[], callParams: CallParams) => void, ) => { return (req: CallServiceData, resp: CallServiceResult, next: Function): void => { if (req.fnName === fnName && req.serviceId === serviceId) { setTimeout(() => { - handler(req.args, req.tetraplets); + handler(req.args, { ...req.particleContext, wrappedArgs: req.wrappedArgs }); }, 0); resp.retCode = ResultCodes.success; @@ -129,18 +146,6 @@ export const fnAsEventHandler = ( }; }; -/** - * Error catching middleware - */ -export const errorHandler: Middleware = (req: CallServiceData, resp: CallServiceResult, next: Function): void => { - try { - next(); - } catch (e) { - resp.retCode = ResultCodes.exceptionInHandler; - resp.result = e.toString(); - } -}; - type CallServiceFunction = (req: CallServiceData, resp: CallServiceResult) => void; /** @@ -188,9 +193,9 @@ export class CallServiceHandler { * Convinience method for registring @see { @link fnHandler } middleware */ on( - serviceId: string, + serviceId: string, // force format fnName: string, - handler: (args: any[], tetraplets: SecurityTetraplet[][]) => CallServiceResultType, + handler: (args: any[], callParams: CallParams) => CallServiceResultType, ): Function { const mw = fnHandler(serviceId, fnName, handler); this.use(mw); @@ -203,9 +208,9 @@ export class CallServiceHandler { * Convinience method for registring @see { @link fnAsEventHandler } middleware */ onEvent( - serviceId: string, + serviceId: string, // force format fnName: string, - handler: (args: any[], tetraplets: SecurityTetraplet[][]) => void, + handler: (args: any[], callParams: CallParams) => void, ): Function { const mw = fnAsEventHandler(serviceId, fnName, handler); this.use(mw); diff --git a/src/internal/ClientImpl.ts b/src/internal/ClientImpl.ts deleted file mode 100644 index a8d47bba..00000000 --- a/src/internal/ClientImpl.ts +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2020 Fluence Labs Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as PeerId from 'peer-id'; -import { Multiaddr } from 'multiaddr'; -import { FluenceConnection, FluenceConnectionOptions } from './FluenceConnection'; - -import { PeerIdB58 } from './commonTypes'; -import { FluenceClient } from '../FluenceClient'; -import { RequestFlow } from './RequestFlow'; -import { CallServiceHandler } from './CallServiceHandler'; -import { loadRelayFn, loadVariablesService } from './RequestFlowBuilder'; -import { logParticle, Particle } from './particle'; -import log from 'loglevel'; -import { - AirInterpreter, - ParticleHandler, - SecurityTetraplet, - CallServiceResult, - LogLevel as AvmLogLevel, -} from '@fluencelabs/avm'; -import makeDefaultClientHandler from './defaultClientHandler'; - -const createClient = (handler, peerId): Promise => { - let logLevel: AvmLogLevel = 'off'; - switch (log.getLevel()) { - case 0: // 'TRACE' - logLevel = 'trace'; - break; - case 1: // 'DEBUG' - logLevel = 'debug'; - break; - case 2: // 'INFO' - logLevel = 'info'; - break; - case 3: // 'WARN' - logLevel = 'warn'; - break; - case 4: // 'ERROR' - logLevel = 'error'; - break; - case 5: // 'SILENT' - logLevel = 'off'; - break; - } - const logFn = (level: AvmLogLevel, msg: string) => { - switch (level) { - case 'error': - log.error(msg); - break; - - case 'warn': - log.warn(msg); - break; - - case 'info': - log.info(msg); - break; - - case 'debug': - case 'trace': - log.log(msg); - break; - } - }; - return AirInterpreter.create(handler, peerId, logLevel, logFn); -}; - -export class ClientImpl implements FluenceClient { - readonly selfPeerIdFull: PeerId; - - private requests: Map = new Map(); - private currentRequestId: string | null = null; - private watchDog; - - get relayPeerId(): PeerIdB58 | undefined { - return this.connection?.nodePeerId.toB58String(); - } - - get selfPeerId(): PeerIdB58 { - return this.selfPeerIdFull.toB58String(); - } - - get isConnected(): boolean { - return this.connection?.isConnected(); - } - - private connection: FluenceConnection; - private interpreter: AirInterpreter; - - constructor(selfPeerIdFull: PeerId) { - this.selfPeerIdFull = selfPeerIdFull; - this.callServiceHandler = makeDefaultClientHandler(); - } - - callServiceHandler: CallServiceHandler; - - async disconnect(): Promise { - if (this.connection) { - await this.connection.disconnect(); - } - this.clearWathcDog(); - this.requests.forEach((r) => { - r.cancel(); - }); - } - - async initAirInterpreter(): Promise { - this.interpreter = await createClient(this.interpreterCallback.bind(this), this.selfPeerId); - } - - async connect(multiaddr: string | Multiaddr, options?: FluenceConnectionOptions): Promise { - multiaddr = new Multiaddr(multiaddr); - - const nodePeerId = multiaddr.getPeerId(); - if (!nodePeerId) { - throw Error("'multiaddr' did not contain a valid peer id"); - } - - if (this.connection) { - await this.connection.disconnect(); - } - - const node = PeerId.createFromB58String(nodePeerId); - const connection = new FluenceConnection( - multiaddr, - node, - this.selfPeerIdFull, - this.executeIncomingParticle.bind(this), - ); - await connection.connect(options); - this.connection = connection; - this.initWatchDog(); - } - - async initiateFlow(request: RequestFlow): Promise { - // setting `relayVariableName` here. If the client is not connected (i.e it is created as local) then there is no relay - request.handler.on(loadVariablesService, loadRelayFn, () => { - return this.relayPeerId || ''; - }); - await request.initState(this.selfPeerIdFull); - - logParticle(log.debug, 'executing local particle', request.getParticle()); - request.handler.combineWith(this.callServiceHandler); - this.requests.set(request.id, request); - - this.processRequest(request); - } - - async executeIncomingParticle(particle: Particle) { - logParticle(log.debug, 'external particle received', particle); - - let request = this.requests.get(particle.id); - if (request) { - request.receiveUpdate(particle); - } else { - request = RequestFlow.createExternal(particle); - request.handler.combineWith(this.callServiceHandler); - } - this.requests.set(request.id, request); - - await this.processRequest(request); - } - - private processRequest(request: RequestFlow) { - try { - this.currentRequestId = request.id; - request.execute(this.interpreter, this.connection, this.relayPeerId); - } catch (err) { - log.error('particle processing failed: ' + err); - } finally { - this.currentRequestId = null; - } - } - - private interpreterCallback: ParticleHandler = ( - serviceId: string, - fnName: string, - args: any[], - tetraplets: SecurityTetraplet[][], - ): CallServiceResult => { - if (this.currentRequestId === null) { - throw Error('current request can`t be null here'); - } - - const request = this.requests.get(this.currentRequestId); - const res = request.handler.execute({ - serviceId, - fnName, - args, - tetraplets, - particleContext: { - particleId: request.id, - }, - }); - - if (res.result === undefined) { - log.error( - `Call to serviceId=${serviceId} fnName=${fnName} unexpectedly returned undefined result, falling back to null`, - ); - res.result = null; - } - - return { - ret_code: res.retCode, - result: JSON.stringify(res.result), - }; - }; - - private initWatchDog() { - this.watchDog = setInterval(() => { - for (let key in this.requests.keys) { - if (this.requests.get(key).hasExpired()) { - this.requests.delete(key); - } - } - }, 5000); - } - - private clearWathcDog() { - clearInterval(this.watchDog); - } -} diff --git a/src/internal/FluenceConnection.ts b/src/internal/FluenceConnection.ts index 087e5fb0..c9f3824b 100644 --- a/src/internal/FluenceConnection.ts +++ b/src/internal/FluenceConnection.ts @@ -118,7 +118,8 @@ export class FluenceConnection { try { await this.node.dial(this.address); - } catch (e) { + } catch (e1) { + const e = e1 as any; if (e.name === 'AggregateError' && e._errors.length === 1) { const error = e._errors[0]; throw `Error dialing node ${this.address}:\n${error.code}\n${error.message}`; diff --git a/src/internal/FluencePeer.ts b/src/internal/FluencePeer.ts new file mode 100644 index 00000000..195c442a --- /dev/null +++ b/src/internal/FluencePeer.ts @@ -0,0 +1,325 @@ +import { AirInterpreter, CallServiceResult, LogLevel, ParticleHandler, SecurityTetraplet } from '@fluencelabs/avm'; +import log from 'loglevel'; +import { Multiaddr } from 'multiaddr'; +import PeerId from 'peer-id'; +import { CallServiceHandler } from './CallServiceHandler'; +import { PeerIdB58 } from './commonTypes'; +import makeDefaultClientHandler from './defaultClientHandler'; +import { FluenceConnection, FluenceConnectionOptions } from './FluenceConnection'; +import { logParticle, Particle } from './particle'; +import { KeyPair } from './KeyPair'; +import { RequestFlow } from './RequestFlow'; +import { loadRelayFn, loadVariablesService } from './RequestFlowBuilder'; +import { createInterpreter } from './utils'; + +/** + * Node of the Fluence detwork specified as a pair of node's multiaddr and it's peer id + */ +type Node = { + peerId: PeerIdB58; + multiaddr: string; +}; + +/** + * Enum representing the log level used in Aqua VM. + * Possible values: 'info', 'trace', 'debug', 'info', 'warn', 'error', 'off'; + */ +export type AvmLoglevel = LogLevel; + +/** + * Configuration used when initiating Fluence Peer + */ +export interface PeerConfig { + /** + * Node in Fluence network to connect to. + * Can be in the form of: + * - string: multiaddr in string format + * - Multiaddr: multiaddr object, @see https://github.com/multiformats/js-multiaddr + * - Node: node structure, @see Node + * If not specified the will work locally and would not be able to send or receive particles. + */ + connectTo?: string | Multiaddr | Node; + + avmLogLevel?: AvmLoglevel; + + /** + * Specify the KeyPair to be used to identify the Fluence Peer. + * Will be generated randomly if not specified + */ + KeyPair?: KeyPair; + + /** + * When the peer established the connection to the network it sends a ping-like message to check if it works correctly. + * The options allows to specify the timeout for that message in milliseconds. + * If not specified the default timeout will be used + */ + checkConnectionTimeoutMs?: number; + + /** + * When the peer established the connection to the network it sends a ping-like message to check if it works correctly. + * If set to true, the ping-like message will be skipped + * Default: false + */ + skipCheckConnection?: boolean; + + /** + * The dialing timeout in milliseconds + */ + dialTimeoutMs?: number; +} + +/** + * Information about Fluence Peer connection + */ +interface ConnectionInfo { + /** + * Is the peer connected to network or not + */ + isConnected: Boolean; + + /** + * The Peer's identification in the Fluence network + */ + selfPeerId: PeerIdB58; + + /** + * The relays's peer id to which the peer is connected to + */ + connectedRelay: PeerIdB58 | null; +} + +/** + * This class implements the Fluence protocol for javascript-based environments. + * It provides all the necessary features to communicate with Fluence network + */ +export class FluencePeer { + /** + * Creates a new Fluence Peer instance. Does not start the workflows. + * In order to work with the Peer it has to be initialized with the `init` method + */ + constructor() {} + + /** + * Get the information about Fluence Peer connections + */ + get connectionInfo(): ConnectionInfo { + const isConnected = this._connection?.isConnected(); + return { + isConnected: isConnected, + selfPeerId: this._selfPeerId, + connectedRelay: this._relayPeerId || null, + }; + } + + /** + * Initializes the peer: starts the Aqua VM, initializes the default call service handlers + * and (optionally) connect to the Fluence network + * @param config - object specifying peer configuration + */ + async init(config?: PeerConfig): Promise { + if (config?.KeyPair) { + this._keyPair = config!.KeyPair; + } else { + this._keyPair = await KeyPair.randomEd25519(); + } + + await this._initAirInterpreter(config?.avmLogLevel || 'off'); + + this._callServiceHandler = makeDefaultClientHandler(); + + if (config?.connectTo) { + let theAddress: Multiaddr; + let fromNode = (config.connectTo as any).multiaddr; + if (fromNode) { + theAddress = new Multiaddr(fromNode); + } else { + theAddress = new Multiaddr(config.connectTo as string); + } + + await this._connect(theAddress); + } + } + + /** + * Uninitializes the peer: stops all the underltying workflows, stops the Aqua VM + * and disconnects from the Fluence network + */ + async uninit() { + await this._disconnect(); + this._callServiceHandler = null; + } + + /** + * Get the default Fluence peer instance. The default peer is used automatically in all the functions generated + * by the Aqua compiler if not specified otherwise. + */ + static get default(): FluencePeer { + return this._default; + } + + // internal api + + /** + * Does not intended to be used manually. Subject to change + */ + get internals() { + return { + initiateFlow: this._initiateFlow.bind(this), + callServiceHandler: this._callServiceHandler, + }; + } + + // private + + private async _initiateFlow(request: RequestFlow): Promise { + // setting `relayVariableName` here. If the client is not connected (i.e it is created as local) then there is no relay + request.handler.on(loadVariablesService, loadRelayFn, () => { + return this._relayPeerId || ''; + }); + await request.initState(this._keyPair.Libp2pPeerId); + + logParticle(log.debug, 'executing local particle', request.getParticle()); + request.handler.combineWith(this._callServiceHandler); + this._requests.set(request.id, request); + + this._processRequest(request); + } + + private _callServiceHandler: CallServiceHandler; + + private static _default: FluencePeer = new FluencePeer(); + + private _keyPair: KeyPair; + private _requests: Map = new Map(); + private _currentRequestId: string | null = null; + private _watchdog; + + private _connection: FluenceConnection; + private _interpreter: AirInterpreter; + + private async _initAirInterpreter(logLevel: AvmLoglevel): Promise { + this._interpreter = await createInterpreter(this._interpreterCallback.bind(this), this._selfPeerId, logLevel); + } + + private async _connect(multiaddr: Multiaddr, options?: FluenceConnectionOptions): Promise { + const nodePeerId = multiaddr.getPeerId(); + if (!nodePeerId) { + throw Error("'multiaddr' did not contain a valid peer id"); + } + + if (this._connection) { + await this._connection.disconnect(); + } + + const node = PeerId.createFromB58String(nodePeerId); + const connection = new FluenceConnection( + multiaddr, + node, + this._keyPair.Libp2pPeerId, + this._executeIncomingParticle.bind(this), + ); + await connection.connect(options); + this._connection = connection; + this._initWatchDog(); + } + + private async _disconnect(): Promise { + if (this._connection) { + await this._connection.disconnect(); + } + this._clearWathcDog(); + this._requests.forEach((r) => { + r.cancel(); + }); + } + + private get _selfPeerId(): PeerIdB58 { + return this._keyPair.Libp2pPeerId.toB58String(); + } + + private get _relayPeerId(): PeerIdB58 | undefined { + return this._connection?.nodePeerId.toB58String(); + } + + private async _executeIncomingParticle(particle: Particle) { + logParticle(log.debug, 'incoming particle received', particle); + + let request = this._requests.get(particle.id); + if (request) { + await request.receiveUpdate(particle); + } else { + request = RequestFlow.createExternal(particle); + request.handler.combineWith(this._callServiceHandler); + } + this._requests.set(request.id, request); + + await this._processRequest(request); + } + + private _processRequest(request: RequestFlow) { + try { + this._currentRequestId = request.id; + request.execute(this._interpreter, this._connection, this._relayPeerId); + } catch (err) { + log.error('particle processing failed: ' + err); + } finally { + this._currentRequestId = null; + } + } + + private _interpreterCallback: ParticleHandler = ( + serviceId: string, + fnName: string, + args: any[], + tetraplets: SecurityTetraplet[][], + ): CallServiceResult => { + if (this._currentRequestId === null) { + throw Error('current request can`t be null here'); + } + + const request = this._requests.get(this._currentRequestId); + const particle = request.getParticle(); + if (particle === null) { + throw new Error("particle can't be null here, current request id: " + this._currentRequestId); + } + const res = request.handler.execute({ + serviceId, + fnName, + args, + tetraplets, + particleContext: { + particleId: request.id, + initPeerId: particle.init_peer_id, + timestamp: particle.timestamp, + ttl: particle.ttl, + signature: particle.signature, + }, + }); + + if (res.result === undefined) { + log.error( + `Call to serviceId=${serviceId} fnName=${fnName} unexpectedly returned undefined result, falling back to null. Particle id=${request.id}`, + ); + res.result = null; + } + + return { + ret_code: res.retCode, + result: JSON.stringify(res.result), + }; + }; + + private _initWatchDog() { + this._watchdog = setInterval(() => { + for (let key in this._requests.keys) { + if (this._requests.get(key).hasExpired()) { + this._requests.delete(key); + } + } + }, 5000); // TODO: make configurable + } + + private _clearWathcDog() { + clearInterval(this._watchdog); + } +} diff --git a/src/internal/KeyPair.ts b/src/internal/KeyPair.ts new file mode 100644 index 00000000..0f3ce72a --- /dev/null +++ b/src/internal/KeyPair.ts @@ -0,0 +1,60 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as PeerId from 'peer-id'; +import * as base64 from 'base64-js'; +import * as ed from 'noble-ed25519'; +import { keys } from 'libp2p-crypto'; + +export class KeyPair { + /** + * @deprecated + * Key pair in libp2p format. Used for backward compatibility with the current FluencePeer implementation + */ + public Libp2pPeerId: PeerId; + + /** + * Generates a new KeyPair from base64 string contatining the 32 byte Ed25519 secret key + * @returns - Promise with the created KeyPair + */ + static async fromEd25519SK(sk: string): Promise { + // deserialize secret key from base64 + const bytes = base64.toByteArray(sk); + // calculate ed25519 public key + const publicKey = await ed.getPublicKey(bytes); + // concatenate secret + public because that's what libp2p-crypto expects + const privateAndPublicKeysArray = new Uint8Array([...bytes, ...publicKey]); + // deserialize keys.supportedKeys.Ed25519PrivateKey + const privateKey = await keys.supportedKeys.ed25519.unmarshalEd25519PrivateKey(privateAndPublicKeysArray); + // serialize it to protobuf encoding because that's what PeerId expects + const protobuf = keys.marshalPrivateKey(privateKey); + // deserialize PeerId from protobuf encoding + const lib2p2Pid = await PeerId.createFromPrivKey(protobuf); + const res = new KeyPair(); + res.Libp2pPeerId = lib2p2Pid; + return res; + } + + /** + * Generates a new KeyPair with random secret key + * @returns - Promise with the created KeyPair + */ + static async randomEd25519(): Promise { + const res = new KeyPair(); + res.Libp2pPeerId = await PeerId.create({ keyType: 'Ed25519' }); + return res; + } +} diff --git a/src/internal/RequestFlow.ts b/src/internal/RequestFlow.ts index 874bcdcf..4d76a85d 100644 --- a/src/internal/RequestFlow.ts +++ b/src/internal/RequestFlow.ts @@ -5,6 +5,7 @@ import { CallServiceHandler } from './CallServiceHandler'; import { PeerIdB58 } from './commonTypes'; import { FluenceConnection } from './FluenceConnection'; import { Particle, genUUID, logParticle } from './particle'; +import { ParticleDataToString } from './utils'; export const DEFAULT_TTL = 7000; diff --git a/src/internal/builtins.ts b/src/internal/builtins.ts deleted file mode 100644 index 391aa729..00000000 --- a/src/internal/builtins.ts +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright 2020 Fluence Labs Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { FluenceClient } from '../FluenceClient'; -import { ModuleConfig } from './moduleConfig'; -import { RequestFlowBuilder } from './RequestFlowBuilder'; - -const nodeIdentityCall = (client: FluenceClient): string => { - return `(call "${client.relayPeerId}" ("op" "identity") [])`; -}; - -const requestResponse = async ( - client: FluenceClient, - name: string, - call: (nodeId: string) => string, - returnValue: string, - data: Map, - handleResponse: (args: any[]) => T, - nodeId?: string, - ttl?: number, -): Promise => { - if (!ttl) { - ttl = 10000; - } - - if (!nodeId) { - nodeId = client.relayPeerId; - } - - let serviceCall = call(nodeId); - - let script = `(seq - ${nodeIdentityCall(client)} - (seq - (seq - ${serviceCall} - ${nodeIdentityCall(client)} - ) - (call "${client.selfPeerId}" ("_callback" "${name}") [${returnValue}]) - ) - ) - `; - - const [request, promise] = new RequestFlowBuilder() - .withRawScript(script) - .withVariables(data) - .withTTL(ttl) - .buildAsFetch('_callback', name); - await client.initiateFlow(request); - const res = await promise; - return handleResponse(res); -}; - -/** - * Get all available modules hosted on a connected relay. @deprecated prefer using raw Particles instead - * @param { FluenceClient } client - The Fluence Client instance. - * @returns { Array } - list of available modules on the connected relay - */ -export const getModules = async (client: FluenceClient, ttl?: number): Promise => { - let callbackFn = 'getModules'; - const [req, promise] = new RequestFlowBuilder() - .withRawScript( - ` - (seq - (call __relay ("dist" "list_modules") [] result) - (call myPeerId ("_callback" "${callbackFn}") [result]) - ) - `, - ) - .withVariables({ - __relay: client.relayPeerId, - myPeerId: client.selfPeerId, - }) - .withTTL(ttl) - .buildAsFetch<[string[]]>('_callback', callbackFn); - client.initiateFlow(req); - - const [res] = await promise; - return res; -}; - -/** - * Get all available interfaces hosted on a connected relay. @deprecated prefer using raw Particles instead - * @param { FluenceClient } client - The Fluence Client instance. - * @returns { Array } - list of available interfaces on the connected relay - */ -export const getInterfaces = async (client: FluenceClient, ttl?: number): Promise => { - let callbackFn = 'getInterfaces'; - const [req, promise] = new RequestFlowBuilder() - .withRawScript( - ` - (seq - (seq - (seq - (call relay ("srv" "list") [] services) - (call relay ("op" "identity") [] $interfaces) - ) - (fold services s - (seq - (call relay ("srv" "get_interface") [s.$.id!] $interfaces) - (next s) - ) - ) - ) - (call myPeerId ("_callback" "${callbackFn}") [$interfaces]) - ) - `, - ) - .withVariables({ - relay: client.relayPeerId, - myPeerId: client.selfPeerId, - }) - .withTTL(ttl) - .buildAsFetch<[string[]]>('_callback', callbackFn); - - client.initiateFlow(req); - - const [res] = await promise; - return res; -}; - -/** - * Send a script to add module to a relay. Waiting for a response from a relay. @deprecated prefer using raw Particles instead - * @param { FluenceClient } client - The Fluence Client instance. - * @param { string } name - Name of the uploaded module - * @param { string } moduleBase64 - Base64 content of the module - * @param { ModuleConfig } config - Module config - */ -export const uploadModule = async ( - client: FluenceClient, - name: string, - moduleBase64: string, - config?: ModuleConfig, - ttl?: number, -): Promise => { - if (!config) { - config = { - name: name, - mem_pages_count: 100, - logger_enabled: true, - wasi: { - envs: {}, - preopened_files: ['/tmp'], - mapped_dirs: {}, - }, - }; - } - - let data = new Map(); - data.set('module_bytes', moduleBase64); - data.set('module_config', config); - data.set('__relay', client.relayPeerId); - data.set('myPeerId', client.selfPeerId); - - const [req, promise] = new RequestFlowBuilder() - .withRawScript( - ` - (seq - (call __relay ("dist" "add_module") [module_bytes module_config] result) - (call myPeerId ("_callback" "getModules") [result]) - - ) - `, - ) - .withVariables(data) - .withTTL(ttl) - .buildAsFetch<[string[]]>('_callback', 'getModules'); - - await client.initiateFlow(req); - await promise; -}; - -/** - * Send a script to add module to a relay. Waiting for a response from a relay. @deprecated prefer using raw Particles instead - * @param { FluenceClient } client - The Fluence Client instance. - * @param { string } name - Name of the blueprint - * @param { Array } dependencies - Array of it's dependencies - * @param {[string]} blueprintId - Optional blueprint ID - * @param {[string]} nodeId - Optional node peer id to deploy blueprint to - * @param {[number]} ttl - Optional ttl for the particle which does the job - * @returns { string } - Created blueprint ID - */ -export const addBlueprint = async ( - client: FluenceClient, - name: string, - dependencies: string[], - blueprintId?: string, - nodeId?: string, - ttl?: number, -): Promise => { - let returnValue = 'blueprint_id'; - let call = (nodeId: string) => `(call "${nodeId}" ("dist" "add_blueprint") [blueprint] ${returnValue})`; - - let data = new Map(); - data.set('blueprint', { name: name, dependencies: dependencies, id: blueprintId }); - - return requestResponse( - client, - 'addBlueprint', - call, - returnValue, - data, - (args: any[]) => args[0] as string, - nodeId, - ttl, - ); -}; - -/** - * Send a script to create a service on the connected relay. Waiting for a response from the relay. @deprecated prefer using raw Particles instead - * @param { FluenceClient } client - The Fluence Client instance. - * @param {string} blueprintId - The blueprint of the service - * @param {[string]} nodeId - Optional node peer id to deploy service to - * @param {[number]} ttl - Optional ttl for the particle which does the job - * @returns { string } - Created service ID - */ -export const createService = async ( - client: FluenceClient, - blueprintId: string, - nodeId?: string, - ttl?: number, -): Promise => { - let returnValue = 'service_id'; - let call = (nodeId: string) => `(call "${nodeId}" ("srv" "create") [blueprint_id] ${returnValue})`; - - let data = new Map(); - data.set('blueprint_id', blueprintId); - - return requestResponse( - client, - 'createService', - call, - returnValue, - data, - (args: any[]) => args[0] as string, - nodeId, - ttl, - ); -}; - -/** - * Get all available blueprints hosted on a connected relay. @deprecated prefer using raw Particles instead - * @param { FluenceClient } client - The Fluence Client instance. - * @param {[string]} nodeId - Optional node peer id to get available blueprints from - * @param {[string]} nodeId - Optional node peer id to deploy service to - * @param {[number]} ttl - Optional ttl for the particle which does the job - * @returns { Array } - List of available blueprints - */ -export const getBlueprints = async ( - client: FluenceClient, - nodeId?: string, - ttl?: number, -): Promise<[{ dependencies; id: string; name: string }]> => { - let returnValue = 'blueprints'; - let call = (nodeId: string) => `(call "${nodeId}" ("dist" "list_blueprints") [] ${returnValue})`; - - return requestResponse( - client, - 'getBlueprints', - call, - returnValue, - new Map(), - (args: any[]) => args[0], - nodeId, - ttl, - ); -}; - -/** - * Get relays neighborhood. @deprecated prefer using raw Particles instead - * @param { FluenceClient } client - The Fluence Client instance. - * @param {[string]} nodeId - Optional node peer id to get neighborhood from - * @param {[number]} ttl - Optional ttl for the particle which does the job - * @returns { Array } - List of peer ids of neighbors of the node - */ -export const neighborhood = async (client: FluenceClient, nodeId?: string, ttl?: number): Promise => { - let returnValue = 'neighborhood'; - let call = (nodeId: string) => `(call "${nodeId}" ("dht" "neighborhood") [node] ${returnValue})`; - - let data = new Map(); - if (nodeId) data.set('node', nodeId); - - return requestResponse(client, 'neighborhood', call, returnValue, data, (args) => args[0] as string[], nodeId, ttl); -}; - -/** - * Upload an AIR script, that will be runned in a loop on a node. @deprecated prefer using raw Particles instead - * @param { FluenceClient } client - The Fluence Client instance. - * @param {[string]} script - script to upload - * @param period how often start script processing, in seconds - * @param {[string]} nodeId - Optional node peer id to get neighborhood from - * @param {[number]} ttl - Optional ttl for the particle which does the job - * @returns {[string]} - script id - */ -export const addScript = async ( - client: FluenceClient, - script: string, - period?: number, - nodeId?: string, - ttl?: number, -): Promise => { - let returnValue = 'id'; - let periodV = ''; - if (period) periodV = period.toString(); - let call = (nodeId: string) => `(call "${nodeId}" ("script" "add") [script ${periodV}] ${returnValue})`; - - let data = new Map(); - data.set('script', script); - if (period) data.set('period', period); - - return requestResponse(client, 'addScript', call, returnValue, data, (args) => args[0] as string, nodeId, ttl); -}; - -/** - * Remove an AIR script from a node. @deprecated prefer using raw Particles instead - * @param { FluenceClient } client - The Fluence Client instance. - * @param {[string]} id - id of a script - * @param {[string]} nodeId - Optional node peer id to get neighborhood from - * @param {[number]} ttl - Optional ttl for the particle which does the job - */ -export const removeScript = async (client: FluenceClient, id: string, nodeId?: string, ttl?: number): Promise => { - let returnValue = 'empty'; - let call = (nodeId: string) => `(call "${nodeId}" ("script" "remove") [script_id] ${returnValue})`; - - let data = new Map(); - data.set('script_id', id); - - return requestResponse(client, 'removeScript', call, returnValue, data, (args) => {}, nodeId, ttl); -}; diff --git a/src/internal/commonTypes.ts b/src/internal/commonTypes.ts index 99501b45..9def08f5 100644 --- a/src/internal/commonTypes.ts +++ b/src/internal/commonTypes.ts @@ -14,4 +14,44 @@ * limitations under the License. */ +import { SecurityTetraplet } from '@fluencelabs/avm'; + +/** + * Peer ID's id as a base58 string (multihash/CIDv0). + */ export type PeerIdB58 = string; + +/** + * Additional information about a service call + */ +export interface CallParams { + /** + * The identifier of particle which triggered the call + */ + particleId: string; + + /** + * The peer id which created the particle + */ + initPeerId: PeerIdB58; + + /** + * Particle's timestamp when it was created + */ + timeStamp: number; + + /** + * Time to live in milliseconds. The time after the particle should be expired + */ + ttl: number; + + /** + * Particle's signature + */ + signature: string; + + /** + * Security tetraplets + */ + tetraplets: { [key in ArgName]: SecurityTetraplet[] }; +} diff --git a/src/internal/compilerSupport/v1.ts b/src/internal/compilerSupport/v1.ts new file mode 100644 index 00000000..42b267ec --- /dev/null +++ b/src/internal/compilerSupport/v1.ts @@ -0,0 +1,5 @@ +export { FluencePeer } from '../FluencePeer'; +export { ResultCodes } from '../../internal/CallServiceHandler'; +export { RequestFlow } from '../../internal/RequestFlow'; +export { RequestFlowBuilder } from '../../internal/RequestFlowBuilder'; +export { CallParams } from '../commonTypes'; diff --git a/src/internal/defaultClientHandler.ts b/src/internal/defaultClientHandler.ts index 2fc7c262..ad3466e2 100644 --- a/src/internal/defaultClientHandler.ts +++ b/src/internal/defaultClientHandler.ts @@ -4,9 +4,9 @@ import { CallServiceHandler, CallServiceResult, CallServiceResultType, - errorHandler, Middleware, } from './CallServiceHandler'; +import { errorHandler } from './defaultMiddlewares'; const makeDefaultClientHandler = (): CallServiceHandler => { const success = (resp: CallServiceResult, result: CallServiceResultType) => { diff --git a/src/internal/defaultMiddlewares.ts b/src/internal/defaultMiddlewares.ts new file mode 100644 index 00000000..643d695e --- /dev/null +++ b/src/internal/defaultMiddlewares.ts @@ -0,0 +1,14 @@ +import { CallServiceArg, CallServiceData, CallServiceResult, Middleware, ResultCodes } from './CallServiceHandler'; + +/** + * Error catching middleware + */ +export const errorHandler: Middleware = (req: CallServiceData, resp: CallServiceResult, next: Function): void => { + try { + next(); + } catch (e) { + resp.retCode = ResultCodes.exceptionInHandler; + resp.result = `Handler failed. fnName="${req.fnName}" serviceId="${req.serviceId}" error: ${e.toString()}`; + } +}; +1; diff --git a/src/internal/peerIdUtils.ts b/src/internal/peerIdUtils.ts deleted file mode 100644 index d4acd750..00000000 --- a/src/internal/peerIdUtils.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020 Fluence Labs Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as PeerId from 'peer-id'; -import { decode, encode } from 'bs58'; -import { keys } from 'libp2p-crypto'; - -/** - * Converts seed string which back to peer id. Seed string can be obtained by using @see {@link peerIdToSeed} function - * @param { string } seed - Seed to convert to peer id - * @returns { PeerId } - Peer id - */ -export const seedToPeerId = async (seed: string): Promise => { - const seedArr = decode(seed); - const privateKey = await keys.generateKeyPairFromSeed('Ed25519', Uint8Array.from(seedArr), 256); - return await PeerId.createFromPrivKey(privateKey.bytes); -}; - -/** - * Converts peer id to a string which can be used to restore back to peer id format with. @see {@link seedToPeerId} - * @param { PeerId } peerId - Peer id to convert to seed - * @returns { string } - Seed string - */ -export const peerIdToSeed = (peerId: PeerId): string => { - const seedBuf = peerId.privKey.marshal().subarray(0, 32); - return encode(seedBuf); -}; - -/** - * Generates a new peer id with random private key - * @returns { Promise } - Promise with the created Peer Id - */ -export const generatePeerId = async (): Promise => { - return await PeerId.create({ keyType: 'Ed25519' }); -}; diff --git a/src/internal/utils.ts b/src/internal/utils.ts new file mode 100644 index 00000000..86e4b322 --- /dev/null +++ b/src/internal/utils.ts @@ -0,0 +1,72 @@ +import { AirInterpreter, LogLevel as AvmLogLevel } from '@fluencelabs/avm'; +import log from 'loglevel'; +import { AvmLoglevel, FluencePeer } from './FluencePeer'; +import { RequestFlowBuilder } from './RequestFlowBuilder'; + +export const createInterpreter = (handler, peerId, logLevel: AvmLoglevel): Promise => { + const logFn = (level: AvmLogLevel, msg: string) => { + switch (level) { + case 'error': + log.error(msg); + break; + + case 'warn': + log.warn(msg); + break; + + case 'info': + log.info(msg); + break; + + case 'debug': + case 'trace': + log.log(msg); + break; + } + }; + return AirInterpreter.create(handler, peerId, logLevel, logFn); +}; + +/** + * Checks the network connection by sending a ping-like request to relat node + * @param { FluenceClient } peer - The Fluence Client instance. + */ +export const checkConnection = async (peer: FluencePeer, ttl?: number): Promise => { + if (!peer.connectionInfo.isConnected) { + return false; + } + + const msg = Math.random().toString(36).substring(7); + const callbackFn = 'checkConnection'; + const callbackService = '_callback'; + + const [request, promise] = new RequestFlowBuilder() + .withRawScript( + `(seq + (call init_relay ("op" "identity") [msg] result) + (call %init_peer_id% ("${callbackService}" "${callbackFn}") [result]) + )`, + ) + .withTTL(ttl) + .withVariables({ + msg, + }) + .buildAsFetch<[string]>(callbackService, callbackFn); + + await peer.internals.initiateFlow(request); + + try { + const [result] = await promise; + if (result != msg) { + log.warn("unexpected behavior. 'identity' must return the passed arguments."); + } + return true; + } catch (e) { + log.error('Error on establishing connection: ', e); + return false; + } +}; + +export const ParticleDataToString = (data: Uint8Array): string => { + return new TextDecoder().decode(Buffer.from(data)); +}; diff --git a/tsconfig.json b/tsconfig.json index fd1098fc..466d9d75 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ ], "outDir": "./dist/", "baseUrl": ".", + "downlevelIteration": true, "sourceMap": true, "inlineSources": true, "strictFunctionTypes": true,