From 863dddacb535e1012095847143f5e67901776f92 Mon Sep 17 00:00:00 2001 From: addie Date: Mon, 4 Sep 2023 16:32:01 +1000 Subject: [PATCH 01/12] chore: setup scaffolding --- .editorconfig | 8 + .env.example | 0 .eslintrc | 179 + .gitignore | 128 + .gitlab-ci.yml | 307 ++ .npmignore | 15 + .npmrc | 2 + .prettierrc | 7 + LICENSE | 201 + README.md | 68 + benches/index.ts | 41 + benches/utils/index.ts | 1 + benches/utils/utils.ts | 61 + jest.config.js | 81 + package-lock.json | 7991 +++++++++++++++++++++++++++++++++++++ package.json | 58 + pkgs.nix | 4 + scripts/brew-install.sh | 14 + scripts/choco-install.ps1 | 30 + shell.nix | 34 + src/index.ts | 0 tests/global.d.ts | 12 + tests/globalSetup.ts | 6 + tests/globalTeardown.ts | 6 + tests/index.test.ts | 1 + tests/setup.ts | 0 tests/setupAfterEnv.ts | 4 + tsconfig.build.json | 13 + tsconfig.json | 36 + 29 files changed, 9308 insertions(+) create mode 100644 .editorconfig create mode 100644 .env.example create mode 100644 .eslintrc create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 .npmignore create mode 100644 .npmrc create mode 100644 .prettierrc create mode 100644 LICENSE create mode 100644 README.md create mode 100644 benches/index.ts create mode 100644 benches/utils/index.ts create mode 100644 benches/utils/utils.ts create mode 100644 jest.config.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 pkgs.nix create mode 100755 scripts/brew-install.sh create mode 100755 scripts/choco-install.ps1 create mode 100644 shell.nix create mode 100644 src/index.ts create mode 100644 tests/global.d.ts create mode 100644 tests/globalSetup.ts create mode 100644 tests/globalTeardown.ts create mode 100644 tests/index.test.ts create mode 100644 tests/setup.ts create mode 100644 tests/setupAfterEnv.ts create mode 100644 tsconfig.build.json create mode 100644 tsconfig.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f3245e7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e69de29 diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..786b7e5 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,179 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es2021": true, + "node": true, + "jest": true + }, + "parser": "@typescript-eslint/parser", + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + "prettier" + ], + "plugins": [ + "import" + ], + "parserOptions": { + "project": "tsconfig.json", + "sourceType": "module" + }, + "rules": { + "linebreak-style": ["error", "unix"], + "no-empty": 1, + "no-useless-catch": 1, + "no-prototype-builtins": 1, + "no-constant-condition": 0, + "no-useless-escape": 0, + "no-console": "error", + "no-restricted-globals": [ + "error", + { + "name": "global", + "message": "Use `globalThis` instead" + }, + { + "name": "window", + "message": "Use `globalThis` instead" + } + ], + "prefer-rest-params": 0, + "require-yield": 0, + "eqeqeq": ["error", "smart"], + "spaced-comment": [ + "warn", + "always", + { + "line": { + "exceptions": ["-"] + }, + "block": { + "exceptions": ["*"] + }, + "markers": ["/"] + } + ], + "capitalized-comments": [ + "warn", + "always", + { + "ignoreInlineComments": true, + "ignoreConsecutiveComments": true + } + ], + "curly": [ + "error", + "multi-line", + "consistent" + ], + "import/order": [ + "error", + { + "groups": [ + "type", + "builtin", + "external", + "internal", + "index", + "sibling", + "parent", + "object" + ], + "pathGroups": [ + { + "pattern": "@", + "group": "internal" + }, + { + "pattern": "@/**", + "group": "internal" + } + ], + "pathGroupsExcludedImportTypes": [ + "type" + ], + "newlines-between": "never" + } + ], + "@typescript-eslint/no-namespace": 0, + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/explicit-module-boundary-types": 0, + "@typescript-eslint/no-unused-vars": [ + "warn", + { + "varsIgnorePattern": "^_", + "argsIgnorePattern": "^_" + } + ], + "@typescript-eslint/no-inferrable-types": 0, + "@typescript-eslint/no-non-null-assertion": 0, + "@typescript-eslint/no-this-alias": 0, + "@typescript-eslint/no-var-requires": 0, + "@typescript-eslint/no-empty-function": 0, + "@typescript-eslint/no-empty-interface": 0, + "@typescript-eslint/consistent-type-imports": ["error"], + "@typescript-eslint/consistent-type-exports": ["error"], + "no-throw-literal": "off", + "@typescript-eslint/no-throw-literal": "off", + "@typescript-eslint/no-floating-promises": ["error", { + "ignoreVoid": true, + "ignoreIIFE": true + }], + "@typescript-eslint/no-misused-promises": ["error", { + "checksVoidReturn": false + }], + "@typescript-eslint/await-thenable": ["error"], + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "default", + "format": ["camelCase"], + "leadingUnderscore": "allow", + "trailingUnderscore": "allowSingleOrDouble" + }, + { + "selector": "function", + "format": ["camelCase", "PascalCase"], + "leadingUnderscore": "allow", + "trailingUnderscore": "allowSingleOrDouble" + }, + { + "selector": "variable", + "format": ["camelCase", "UPPER_CASE", "PascalCase"], + "leadingUnderscore": "allow", + "trailingUnderscore": "allowSingleOrDouble" + }, + { + "selector": "parameter", + "format": ["camelCase"], + "leadingUnderscore": "allow", + "trailingUnderscore": "allowSingleOrDouble" + }, + { + "selector": "typeLike", + "format": ["PascalCase"], + "trailingUnderscore": "allowSingleOrDouble" + }, + { + "selector": "enumMember", + "format": ["PascalCase", "UPPER_CASE"] + }, + { + "selector": "objectLiteralProperty", + "format": null + }, + { + "selector": "typeProperty", + "format": null + } + ], + "@typescript-eslint/ban-ts-comment": [ + "error", + { + "ts-ignore": "allow-with-description" + } + ] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84856b0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,128 @@ +/tmp +/dist +.env* +!.env.example +# nix +/result* +/builds +# node-gyp +/build +# prebuildify +/prebuilds + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..d450e97 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,307 @@ +workflow: + rules: + # Disable merge request pipelines + - if: $CI_MERGE_REQUEST_ID + when: never + - when: always + +variables: + GIT_SUBMODULE_STRATEGY: recursive + GH_PROJECT_PATH: "MatrixAI/${CI_PROJECT_NAME}" + GH_PROJECT_URL: "https://${GITHUB_TOKEN}@github.com/${GH_PROJECT_PATH}.git" + # Cache .npm + npm_config_cache: "${CI_PROJECT_DIR}/tmp/npm" + # Prefer offline node module installation + npm_config_prefer_offline: "true" + # Homebrew cache only used by macos runner + HOMEBREW_CACHE: "${CI_PROJECT_DIR}/tmp/Homebrew" + +default: + interruptible: true + before_script: + # Replace this in windows runners that use powershell + # with `mkdir -Force "$CI_PROJECT_DIR/tmp"` + - mkdir -p "$CI_PROJECT_DIR/tmp" + +# Cached directories shared between jobs & pipelines per-branch per-runner +cache: + key: $CI_COMMIT_REF_SLUG + # Preserve cache even if job fails + when: 'always' + paths: + - ./tmp/npm/ + # Homebrew cache is only used by the macos runner + - ./tmp/Homebrew + # Chocolatey cache is only used by the windows runner + - ./tmp/chocolatey/ + # `jest` cache is configured in jest.config.js + - ./tmp/jest/ + +stages: + - check # Linting, unit tests + - build # Cross-platform library compilation, unit tests + - integration # Cross-platform application bundling, integration tests, and pre-release + - release # Cross-platform distribution and deployment + +image: registry.gitlab.com/matrixai/engineering/maintenance/gitlab-runner + +check:lint: + stage: check + needs: [] + script: + - > + nix-shell --arg ci true --run $' + npm run lint; + npm run lint-shell; + ' + rules: + # Runs on feature and staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH =~ /^(?:feature.*|staging)$/ && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Manually run on commits other than master and ignore version commits + - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != 'master' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + when: manual + +check:test: + stage: check + needs: [] + script: + - > + nix-shell --arg ci true --run $' + npm test -- --ci --coverage; + ' + artifacts: + when: always + reports: + junit: + - ./tmp/junit/junit.xml + coverage_report: + coverage_format: cobertura + path: ./tmp/coverage/cobertura-coverage.xml + coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/' + rules: + # Runs on feature commits and ignores version commits + - if: $CI_COMMIT_BRANCH =~ /^feature.*$/ && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Manually run on commits other than master and staging and ignore version commits + - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH !~ /^(?:master|staging)$/ && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + when: manual + +build:merge: + stage: build + needs: [] + allow_failure: true + script: + # Required for `gh pr create` + - git remote add upstream "$GH_PROJECT_URL" + - > + nix-shell --arg ci true --run $' + gh pr create \ + --head staging \ + --base master \ + --title "ci: merge staging to master" \ + --body "This is an automatic PR generated by the pipeline CI/CD. This will be automatically fast-forward merged if successful." \ + --assignee "@me" \ + --no-maintainer-edit \ + --repo "$GH_PROJECT_PATH" || true; + printf "Pipeline Attempt on ${CI_PIPELINE_ID} for ${CI_COMMIT_SHA}\n\n${CI_PIPELINE_URL}" \ + | gh pr comment staging \ + --body-file - \ + --repo "$GH_PROJECT_PATH"; + ' + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +build:dist: + stage: build + needs: [] + script: + - > + nix-shell --arg ci true --run $' + npm run build --verbose; + ' + artifacts: + when: always + paths: + - ./dist + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +build:linux: + stage: build + needs: [] + script: + - > + nix-shell --arg ci true --run $' + npm test -- --ci --coverage; + npm run bench; + ' + artifacts: + when: always + reports: + junit: + - ./tmp/junit/junit.xml + coverage_report: + coverage_format: cobertura + path: ./tmp/coverage/cobertura-coverage.xml + metrics: ./benches/results/metrics.txt + coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/' + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +build:windows: + stage: build + needs: [] + tags: + - windows + before_script: + - mkdir -Force "$CI_PROJECT_DIR/tmp" + script: + - .\scripts\choco-install.ps1 + - refreshenv + - npm install --ignore-scripts + - $env:Path = "$(npm root)\.bin;" + $env:Path + - npm test -- --ci --coverage + - npm run bench + artifacts: + when: always + reports: + junit: + - ./tmp/junit/junit.xml + coverage_report: + coverage_format: cobertura + path: ./tmp/coverage/cobertura-coverage.xml + metrics: ./benches/results/metrics.txt + coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/' + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +build:macos: + stage: build + needs: [] + tags: + - saas-macos-medium-m1 + image: macos-12-xcode-14 + script: + - eval "$(brew shellenv)" + - ./scripts/brew-install.sh + - hash -r + - npm install --ignore-scripts + - export PATH="$(npm root)/.bin:$PATH" + - npm test -- --ci --coverage + - npm run bench + artifacts: + when: always + reports: + junit: + - ./tmp/junit/junit.xml + coverage_report: + coverage_format: cobertura + path: ./tmp/coverage/cobertura-coverage.xml + metrics: ./benches/results/metrics.txt + coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/' + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +build:prerelease: + stage: build + needs: + - build:dist + - build:linux + - build:windows + - build:macos + # Don't interrupt publishing job + interruptible: false + script: + - echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ./.npmrc + - echo 'Publishing library prerelease' + - > + nix-shell --arg ci true --run $' + npm publish --tag prerelease --access public; + ' + after_script: + - rm -f ./.npmrc + rules: + # Only runs on tag pipeline where the tag is a prerelease version + # This requires dependencies to also run on tag pipeline + # However version tag comes with a version commit + # Dependencies must not run on the version commit + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+-.*[0-9]+$/ + +integration:merge: + stage: integration + needs: + - build:merge + - job: build:linux + optional: true + - job: build:windows + optional: true + - job: build:macos + optional: true + # Requires mutual exclusion + resource_group: integration:merge + allow_failure: true + variables: + # Ensure that CI/CD is fetching all commits + # this is necessary to checkout origin/master + # and to also merge origin/staging + GIT_DEPTH: 0 + script: + - > + nix-shell --arg ci true --run $' + printf "Pipeline Succeeded on ${CI_PIPELINE_ID} for ${CI_COMMIT_SHA}\n\n${CI_PIPELINE_URL}" \ + | gh pr comment staging \ + --body-file - \ + --repo "$GH_PROJECT_PATH"; + ' + - git remote add upstream "$GH_PROJECT_URL" + - git checkout origin/master + # Merge up to the current commit (not the latest commit) + - git merge --ff-only "$CI_COMMIT_SHA" + - git push upstream HEAD:master + rules: + # Runs on staging commits and ignores version commits + - if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + # Runs on tag pipeline where the tag is a prerelease or release version + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/ + +release:distribution: + stage: release + needs: + - build:dist + - build:linux + - build:windows + - build:macos + - integration:merge + # Don't interrupt publishing job + interruptible: false + script: + - echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ./.npmrc + - echo 'Publishing library' + - > + nix-shell --arg ci true --run $' + npm publish --access public; + ' + after_script: + - rm -f ./.npmrc + rules: + # Only runs on tag pipeline where the tag is a release version + # This requires dependencies to also run on tag pipeline + # However version tag comes with a version commit + # Dependencies must not run on the version commit + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/ diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..6e59877 --- /dev/null +++ b/.npmignore @@ -0,0 +1,15 @@ +.* +/*.nix +/nix +/tsconfig.json +/tsconfig.build.json +/jest.config.js +/scripts +/src +/tests +/tmp +/docs +/benches +/build +/builds +/dist/tsbuildinfo diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..7c06da2 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +# Enables npm link +prefix=~/.npm diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..fa9699b --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": true, + "trailingComma": "all", + "singleQuote": true, + "printWidth": 80, + "tabWidth": 2 +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4032c58 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# js-rpc + +staging:[![pipeline status](https://gitlab.com/MatrixAI/open-source/js-rpc/badges/staging/pipeline.svg)](https://gitlab.com/MatrixAI/open-source/js-rpc/commits/staging) +master:[![pipeline status](https://gitlab.com/MatrixAI/open-source/js-rpc/badges/master/pipeline.svg)](https://gitlab.com/MatrixAI/open-source/js-rpc/commits/master) + +## Installation + +```sh +npm install --save @matrixai/rpc +``` + +## Development + +Run `nix-shell`, and once you're inside, you can use: + +```sh +# install (or reinstall packages from package.json) +npm install +# build the dist +npm run build +# run the repl (this allows you to import from ./src) +npm run ts-node +# run the tests +npm run test +# lint the source code +npm run lint +# automatically fix the source +npm run lintfix +``` + +### Docs Generation + +```sh +npm run docs +``` + +See the docs at: https://matrixai.github.io/js-rpc/ + +### Publishing + +Publishing is handled automatically by the staging pipeline. + +Prerelease: + +```sh +# npm login +npm version prepatch --preid alpha # premajor/preminor/prepatch +git push --follow-tags +``` + +Release: + +```sh +# npm login +npm version patch # major/minor/patch +git push --follow-tags +``` + +Manually: + +```sh +# npm login +npm version patch # major/minor/patch +npm run build +npm publish --access public +git push +git push --tags +``` diff --git a/benches/index.ts b/benches/index.ts new file mode 100644 index 0000000..858f216 --- /dev/null +++ b/benches/index.ts @@ -0,0 +1,41 @@ +#!/usr/bin/env ts-node + +import fs from 'fs'; +import path from 'path'; +import si from 'systeminformation'; + +async function main(): Promise { + await fs.promises.mkdir(path.join(__dirname, 'results'), { recursive: true }); + const resultFilenames = await fs.promises.readdir( + path.join(__dirname, 'results'), + ); + const metricsFile = await fs.promises.open( + path.join(__dirname, 'results', 'metrics.txt'), + 'w', + ); + let concatenating = false; + for (const resultFilename of resultFilenames) { + if (/.+_metrics\.txt$/.test(resultFilename)) { + const metricsData = await fs.promises.readFile( + path.join(__dirname, 'results', resultFilename), + ); + if (concatenating) { + await metricsFile.write('\n'); + } + await metricsFile.write(metricsData); + concatenating = true; + } + } + await metricsFile.close(); + const systemData = await si.get({ + cpu: '*', + osInfo: 'platform, distro, release, kernel, arch', + system: 'model, manufacturer', + }); + await fs.promises.writeFile( + path.join(__dirname, 'results', 'system.json'), + JSON.stringify(systemData, null, 2), + ); +} + +void main(); diff --git a/benches/utils/index.ts b/benches/utils/index.ts new file mode 100644 index 0000000..04bca77 --- /dev/null +++ b/benches/utils/index.ts @@ -0,0 +1 @@ +export * from './utils'; diff --git a/benches/utils/utils.ts b/benches/utils/utils.ts new file mode 100644 index 0000000..71c4d10 --- /dev/null +++ b/benches/utils/utils.ts @@ -0,0 +1,61 @@ +import fs from 'fs'; +import path from 'path'; +import b from 'benny'; +import { codeBlock } from 'common-tags'; +import packageJson from '../../package.json'; + +const suiteCommon = [ + b.cycle(), + b.complete(), + b.save({ + file: (summary) => summary.name, + folder: path.join(__dirname, '../results'), + version: packageJson.version, + details: true, + }), + b.save({ + file: (summary) => summary.name, + folder: path.join(__dirname, '../results'), + version: packageJson.version, + format: 'chart.html', + }), + b.complete((summary) => { + const filePath = path.join( + __dirname, + '../results', + summary.name + '_metrics.txt', + ); + fs.writeFileSync( + filePath, + codeBlock` + # TYPE ${summary.name}_ops gauge + ${summary.results + .map( + (result) => + `${summary.name}_ops{name="${result.name}"} ${result.ops}`, + ) + .join('\n')} + + # TYPE ${summary.name}_margin gauge + ${summary.results + .map( + (result) => + `${summary.name}_margin{name="${result.name}"} ${result.margin}`, + ) + .join('\n')} + + # TYPE ${summary.name}_samples counter + ${summary.results + .map( + (result) => + `${summary.name}_samples{name="${result.name}"} ${result.samples}`, + ) + .join('\n')} + ` + '\n', + ); + // eslint-disable-next-line no-console + console.log('\nSaved to:', path.resolve(filePath)); + }), +]; + +export { suiteCommon }; diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..58d32f3 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,81 @@ +const path = require('path'); +const { pathsToModuleNameMapper } = require('ts-jest'); +const { compilerOptions } = require('./tsconfig'); + +const moduleNameMapper = pathsToModuleNameMapper(compilerOptions.paths, { + prefix: '/src/', +}); + +// Global variables that are shared across the jest worker pool +// These variables must be static and serializable +const globals = { + // Absolute directory to the project root + projectDir: __dirname, + // Absolute directory to the test root + testDir: path.join(__dirname, 'tests'), + // Default asynchronous test timeout + defaultTimeout: 20000, + // Timeouts rely on setTimeout which takes 32 bit numbers + maxTimeout: Math.pow(2, 31) - 1, +}; + +// The `globalSetup` and `globalTeardown` cannot access the `globals` +// They run in their own process context +// They can however receive the process environment +// Use `process.env` to set variables + +module.exports = { + testEnvironment: 'node', + verbose: true, + collectCoverage: false, + cacheDirectory: '/tmp/jest', + coverageDirectory: '/tmp/coverage', + roots: ['/tests'], + testMatch: ['**/?(*.)+(spec|test|unit.test).+(ts|tsx|js|jsx)'], + transform: { + "^.+\\.(t|j)sx?$": [ + "@swc/jest", + { + jsc: { + parser: { + syntax: "typescript", + tsx: true, + decorators: compilerOptions.experimentalDecorators, + dynamicImport: true, + }, + target: compilerOptions.target.toLowerCase(), + keepClassNames: true, + }, + } + ], + }, + reporters: [ + 'default', + ['jest-junit', { + outputDirectory: '/tmp/junit', + classNameTemplate: '{classname}', + ancestorSeparator: ' > ', + titleTemplate: '{title}', + addFileAttribute: 'true', + reportTestSuiteErrors: 'true', + }], + ], + collectCoverageFrom: ['src/**/*.{ts,tsx,js,jsx}', '!src/**/*.d.ts'], + coverageReporters: ['text', 'cobertura'], + globals, + // Global setup script executed once before all test files + globalSetup: '/tests/globalSetup.ts', + // Global teardown script executed once after all test files + globalTeardown: '/tests/globalTeardown.ts', + // Setup files are executed before each test file + // Can access globals + setupFiles: ['/tests/setup.ts'], + // Setup files after env are executed before each test file + // after the jest test environment is installed + // Can access globals + setupFilesAfterEnv: [ + 'jest-extended/all', + '/tests/setupAfterEnv.ts' + ], + moduleNameMapper: moduleNameMapper, +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6bdbc1b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,7991 @@ +{ + "name": "@matrixai/rpc", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@matrixai/rpc", + "version": "0.0.1", + "license": "Apache-2.0", + "devDependencies": { + "@swc/core": "^1.3.62", + "@swc/jest": "^0.2.26", + "@types/jest": "^28.1.3", + "@types/node": "^18.15.0", + "@typescript-eslint/eslint-plugin": "^5.45.1", + "@typescript-eslint/parser": "^5.45.1", + "benny": "^3.7.1", + "common-tags": "^1.8.2", + "eslint": "^8.15.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-prettier": "^4.0.0", + "jest": "^28.1.1", + "jest-extended": "^3.0.1", + "jest-junit": "^14.0.0", + "prettier": "^2.6.2", + "shx": "^0.3.4", + "systeminformation": "^5.18.5", + "ts-jest": "^28.0.5", + "ts-node": "^10.9.1", + "tsconfig-paths": "^3.9.0", + "typedoc": "^0.23.21", + "typescript": "^4.9.3" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@arrows/array": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@arrows/array/-/array-1.4.1.tgz", + "integrity": "sha512-MGYS8xi3c4tTy1ivhrVntFvufoNzje0PchjEz6G/SsWRgUKxL4tKwS6iPdO8vsaJYldagAeWMd5KRD0aX3Q39g==", + "dev": true, + "dependencies": { + "@arrows/composition": "^1.2.2" + } + }, + "node_modules/@arrows/composition": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@arrows/composition/-/composition-1.2.2.tgz", + "integrity": "sha512-9fh1yHwrx32lundiB3SlZ/VwuStPB4QakPsSLrGJFH6rCXvdrd060ivAZ7/2vlqPnEjBkPRRXOcG1YOu19p2GQ==", + "dev": true + }, + "node_modules/@arrows/dispatch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@arrows/dispatch/-/dispatch-1.0.3.tgz", + "integrity": "sha512-v/HwvrFonitYZM2PmBlAlCqVqxrkIIoiEuy5bQgn0BdfvlL0ooSBzcPzTMrtzY8eYktPyYcHg8fLbSgyybXEqw==", + "dev": true, + "dependencies": { + "@arrows/composition": "^1.2.2" + } + }, + "node_modules/@arrows/error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@arrows/error/-/error-1.0.2.tgz", + "integrity": "sha512-yvkiv1ay4Z3+Z6oQsUkedsQm5aFdyPpkBUQs8vejazU/RmANABx6bMMcBPPHI4aW43VPQmXFfBzr/4FExwWTEA==", + "dev": true + }, + "node_modules/@arrows/multimethod": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@arrows/multimethod/-/multimethod-1.4.1.tgz", + "integrity": "sha512-AZnAay0dgPnCJxn3We5uKiB88VL+1ZIF2SjZohLj6vqY2UyvB/sKdDnFP+LZNVsTC5lcnGPmLlRRkAh4sXkXsQ==", + "dev": true, + "dependencies": { + "@arrows/array": "^1.4.1", + "@arrows/composition": "^1.2.2", + "@arrows/error": "^1.0.2", + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.11.tgz", + "integrity": "sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.10", + "@babel/generator": "^7.22.10", + "@babel/helper-compilation-targets": "^7.22.10", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.11", + "@babel/parser": "^7.22.11", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.11", + "@babel/types": "^7.22.11", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", + "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.10", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", + "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", + "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.11.tgz", + "integrity": "sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.11", + "@babel/types": "^7.22.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.22.14", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.14.tgz", + "integrity": "sha512-1KucTHgOvaw/LzCVrEOAyXkr9rQlp0A1HiHRYnSUE9dmb8PvPW7o5sscg+5169r54n3vGlbx6GevTE/Iw/P3AQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz", + "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.10", + "@babel/generator": "^7.22.10", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.11", + "@babel/types": "^7.22.11", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz", + "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", + "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", + "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/console/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/console/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", + "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/reporters": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^28.1.3", + "jest-config": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-resolve-dependencies": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "jest-watcher": "^28.1.3", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-snapshot": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/create-cache-key-function": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz", + "integrity": "sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/create-cache-key-function/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/create-cache-key-function/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/reporters": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", + "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", + "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.13", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", + "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/transform/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/types/node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/types/node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@swc/core": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.82.tgz", + "integrity": "sha512-jpC1a18HMH67018Ij2jh+hT7JBFu7ZKcQVfrZ8K6JuEY+kjXmbea07P9MbQUZbAe0FB+xi3CqEVCP73MebodJQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@swc/types": "^0.1.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.82", + "@swc/core-darwin-x64": "1.3.82", + "@swc/core-linux-arm-gnueabihf": "1.3.82", + "@swc/core-linux-arm64-gnu": "1.3.82", + "@swc/core-linux-arm64-musl": "1.3.82", + "@swc/core-linux-x64-gnu": "1.3.82", + "@swc/core-linux-x64-musl": "1.3.82", + "@swc/core-win32-arm64-msvc": "1.3.82", + "@swc/core-win32-ia32-msvc": "1.3.82", + "@swc/core-win32-x64-msvc": "1.3.82" + }, + "peerDependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.82.tgz", + "integrity": "sha512-JfsyDW34gVKD3uE0OUpUqYvAD3yseEaicnFP6pB292THtLJb0IKBBnK50vV/RzEJtc1bR3g1kNfxo2PeurZTrA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.82.tgz", + "integrity": "sha512-ogQWgNMq7qTpITjcP3dnzkFNj7bh6SwMr859GvtOTrE75H7L7jDWxESfH4f8foB/LGxBKiDNmxKhitCuAsZK4A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.82.tgz", + "integrity": "sha512-7TMXG1lXlNhD0kUiEqs+YlGV4irAdBa2quuy+XI3oJf2fBK6dQfEq4xBy65B3khrorzQS3O0oDGQ+cmdpHExHA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.82.tgz", + "integrity": "sha512-26JkOujbzcItPAmIbD5vHJxQVy5ihcSu3YHTKwope1h28sApZdtE7S3e2G3gsZRTIdsCQkXUtAQeqHxGWWR3pw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.82.tgz", + "integrity": "sha512-8Izj9tuuMpoc3cqiPBRtwqpO1BZ/+sfZVsEhLxrbOFlcSb8LnKyMle1g3JMMUwI4EU75RGVIzZMn8A6GOKdJbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.82.tgz", + "integrity": "sha512-0GSrIBScQwTaPv46T2qB7XnDYxndRCpwH4HMjh6FN+I+lfPUhTSJKW8AonqrqT1TbpFIgvzQs7EnTsD7AnSCow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.82.tgz", + "integrity": "sha512-KJUnaaepDKNzrEbwz4jv0iC3/t9x0NSoe06fnkAlhh2+NFKWKKJhVCOBTrpds8n7eylBDIXUlK34XQafjVMUdg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.82.tgz", + "integrity": "sha512-TR3MHKhDYIyGyFcyl2d/p1ftceXcubAhX5wRSOdtOyr5+K/v3jbyCCqN7bbqO5o43wQVCwwR/drHleYyDZvg8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.82.tgz", + "integrity": "sha512-ZX4HzVVt6hs84YUg70UvyBJnBOIspmQQM0iXSzBvOikk3zRoN7BnDwQH4GScvevCEBuou60+i4I6d5kHLOfh8Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.82.tgz", + "integrity": "sha512-4mJMnex21kbQoaHeAmHnVwQN9/XAfPszJ6n9HI7SVH+aAHnbBIR0M59/b50/CJMjTj5niUGk7EwQ3nhVNOG32g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/jest": { + "version": "0.2.29", + "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.29.tgz", + "integrity": "sha512-8reh5RvHBsSikDC3WGCd5ZTd2BXKkyOdK7QwynrCH58jk2cQFhhHhFBg/jvnWZehUQe/EoOImLENc9/DwbBFow==", + "dev": true, + "dependencies": { + "@jest/create-cache-key-function": "^27.4.2", + "jsonc-parser": "^3.2.0" + }, + "engines": { + "npm": ">= 7.0.0" + }, + "peerDependencies": { + "@swc/core": "*" + } + }, + "node_modules/@swc/types": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.4.tgz", + "integrity": "sha512-z/G02d+59gyyUb7KYhKi9jOhicek6QD2oMaotUyG+lUkybpXoV49dY9bj7Ah5Q+y7knK2jU67UTX9FyfGzaxQg==", + "dev": true + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", + "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "28.1.8", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.8.tgz", + "integrity": "sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==", + "dev": true, + "dependencies": { + "expect": "^28.0.0", + "pretty-format": "^28.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@types/jest/node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@types/jest/node_modules/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.17.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.14.tgz", + "integrity": "sha512-ZE/5aB73CyGqgQULkLG87N9GnyGe5TcQjv34pwS8tfBs1IkCh0ASM69mydb2znqd6v0eX+9Ytvk6oQRqu8T1Vw==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", + "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", + "dev": true + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", + "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", + "dev": true, + "dependencies": { + "@jest/transform": "^28.1.3", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^28.1.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", + "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", + "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^28.1.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/benchmark": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", + "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.4", + "platform": "^1.3.3" + } + }, + "node_modules/benny": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/benny/-/benny-3.7.1.tgz", + "integrity": "sha512-USzYxODdVfOS7JuQq/L0naxB788dWCiUgUTxvN+WLPt/JfcDURNNj8kN/N+uK6PDvuR67/9/55cVKGPleFQINA==", + "dev": true, + "dependencies": { + "@arrows/composition": "^1.0.0", + "@arrows/dispatch": "^1.0.2", + "@arrows/multimethod": "^1.1.6", + "benchmark": "^2.1.4", + "common-tags": "^1.8.0", + "fs-extra": "^10.0.0", + "json2csv": "^5.0.6", + "kleur": "^4.1.4", + "log-update": "^4.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/benny/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001525", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001525.tgz", + "integrity": "sha512-/3z+wB4icFt3r0USMwxujAqRvaD/B7rvGTsKhbhSQErVrJvkZCLhgNLJxU8MevahQVH6hCU9FsHdNUFbiwmE7Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.508", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz", + "integrity": "sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", + "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.48.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", + "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.findlastindex": "^1.2.2", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.8.0", + "has": "^1.0.3", + "is-core-module": "^2.13.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.6", + "object.groupby": "^1.0.0", + "object.values": "^1.1.6", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "dev": true, + "dependencies": { + "flatted": "^3.2.7", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", + "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", + "dev": true, + "dependencies": { + "@jest/core": "^28.1.3", + "@jest/types": "^28.1.3", + "import-local": "^3.0.2", + "jest-cli": "^28.1.3" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", + "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", + "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "p-limit": "^3.1.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/environment": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "dev": true, + "dependencies": { + "expect": "^28.1.3", + "jest-snapshot": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/fake-timers": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/jest-circus/node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/jest-circus/node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-mock": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-snapshot": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-cli": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", + "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", + "dev": true, + "dependencies": { + "@jest/core": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-config": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", + "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.3", + "@jest/types": "^28.1.3", + "babel-jest": "^28.1.3", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^28.1.3", + "jest-environment-node": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-config/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-diff": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.4.tgz", + "integrity": "sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", + "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", + "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.3", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", + "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@jest/environment": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@jest/fake-timers": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/jest-environment-node/node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/jest-environment-node/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/jest-mock": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-extended": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/jest-extended/-/jest-extended-3.2.4.tgz", + "integrity": "sha512-lSEYhSmvXZG/7YXI7KO3LpiUiQ90gi5giwCJNDMMsX5a+/NZhdbQF2G4ALOBN+KcXVT3H6FPVPohAuMXooaLTQ==", + "dev": true, + "dependencies": { + "jest-diff": "^29.0.0", + "jest-get-type": "^29.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "jest": ">=27.2.5" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + } + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-haste-map/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-junit": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-14.0.1.tgz", + "integrity": "sha512-h7/wwzPbllgpQhhVcRzRC76/cc89GlazThoV1fDxcALkf26IIlRsu/AcTG64f4nR2WPE3Cbd+i/sVf+NCUHrWQ==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/jest-leak-detector": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", + "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", + "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", + "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-snapshot": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", + "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/environment": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^28.1.1", + "jest-environment-node": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-leak-detector": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-resolve": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-util": "^28.1.3", + "jest-watcher": "^28.1.3", + "jest-worker": "^28.1.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/environment": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/fake-timers": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/jest-runner/node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/jest-runner/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-mock": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", + "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/globals": "^28.1.3", + "@jest/source-map": "^28.1.2", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/environment": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "dev": true, + "dependencies": { + "expect": "^28.1.3", + "jest-snapshot": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/fake-timers": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/globals": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", + "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/types": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/jest-runtime/node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/jest-runtime/node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-mock": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-snapshot": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", + "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "leven": "^3.1.0", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "dev": true, + "dependencies": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watcher/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json2csv": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/json2csv/-/json2csv-5.0.7.tgz", + "integrity": "sha512-YRZbUnyaJZLZUJSRi2G/MqahCyRv9n/ds+4oIetjDF3jWQA7AG7iSeKTiZiCNqtMZM7HDyt0e/W6lEnoGEmMGA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "commander": "^6.1.0", + "jsonparse": "^1.3.1", + "lodash.get": "^4.4.2" + }, + "bin": { + "json2csv": "bin/json2csv.js" + }, + "engines": { + "node": ">= 10", + "npm": ">= 6.13.0" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/pretty-format/node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/pretty-format/node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shiki": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz", + "integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==", + "dev": true, + "dependencies": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, + "node_modules/shx": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", + "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", + "dev": true, + "dependencies": { + "minimist": "^1.2.3", + "shelljs": "^0.8.5" + }, + "bin": { + "shx": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/systeminformation": { + "version": "5.21.4", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.21.4.tgz", + "integrity": "sha512-fLW6j47UoAJDlZPEqykkWTKxubxb8IFuow6pMQlqf4irZ2lBgCrCReavMkH2t8VxxjOcg6wBlZ2EPQcluAT6xg==", + "dev": true, + "os": [ + "darwin", + "linux", + "win32", + "freebsd", + "openbsd", + "netbsd", + "sunos", + "android" + ], + "bin": { + "systeminformation": "lib/cli.js" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "Buy me a coffee", + "url": "https://www.buymeacoffee.com/systeminfo" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-jest": { + "version": "28.0.8", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.8.tgz", + "integrity": "sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^28.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^28.0.0", + "babel-jest": "^28.0.0", + "jest": "^28.0.0", + "typescript": ">=4.3" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedoc": { + "version": "0.23.28", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.28.tgz", + "integrity": "sha512-9x1+hZWTHEQcGoP7qFmlo4unUoVJLB0H/8vfO/7wqTnZxg4kPuji9y3uRzEu0ZKez63OJAUmiGhUrtukC6Uj3w==", + "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.2.12", + "minimatch": "^7.1.3", + "shiki": "^0.14.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 14.14" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..66c6d91 --- /dev/null +++ b/package.json @@ -0,0 +1,58 @@ +{ + "name": "@matrixai/rpc", + "version": "0.0.1", + "author": "Matrix AI", + "contributors": [ + { + "name": "Aditya V" + }, + { + "name": "Roger Qiu" + } + ], + "description": "RPC for TypeScript/JavaScript Applications", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/MatrixAI/js-rpc.git" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "prepare": "tsc -p ./tsconfig.build.json", + "build": "shx rm -rf ./dist && tsc -p ./tsconfig.build.json", + "postversion": "npm install --package-lock-only --ignore-scripts --silent", + "ts-node": "ts-node", + "test": "jest", + "lint": "eslint '{src,tests,scripts,benches}/**/*.{js,ts}'", + "lintfix": "eslint '{src,tests,scripts,benches}/**/*.{js,ts}' --fix", + "lint-shell": "find ./src ./tests ./scripts -type f -regextype posix-extended -regex '.*\\.(sh)' -exec shellcheck {} +", + "docs": "shx rm -rf ./docs && typedoc --gitRevision master --tsconfig ./tsconfig.build.json --out ./docs src", + "bench": "shx rm -rf ./benches/results && ts-node ./benches" + }, + "devDependencies": { + "@swc/core": "^1.3.62", + "@swc/jest": "^0.2.26", + "@types/jest": "^28.1.3", + "@types/node": "^18.15.0", + "@typescript-eslint/eslint-plugin": "^5.45.1", + "@typescript-eslint/parser": "^5.45.1", + "benny": "^3.7.1", + "common-tags": "^1.8.2", + "eslint": "^8.15.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-prettier": "^4.0.0", + "jest": "^28.1.1", + "jest-extended": "^3.0.1", + "jest-junit": "^14.0.0", + "prettier": "^2.6.2", + "shx": "^0.3.4", + "systeminformation": "^5.18.5", + "ts-jest": "^28.0.5", + "ts-node": "^10.9.1", + "tsconfig-paths": "^3.9.0", + "typedoc": "^0.23.21", + "typescript": "^4.9.3" + } +} diff --git a/pkgs.nix b/pkgs.nix new file mode 100644 index 0000000..2997ae2 --- /dev/null +++ b/pkgs.nix @@ -0,0 +1,4 @@ +import ( + let rev = "ea5234e7073d5f44728c499192544a84244bf35a"; in + builtins.fetchTarball "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz" +) diff --git a/scripts/brew-install.sh b/scripts/brew-install.sh new file mode 100755 index 0000000..11215a6 --- /dev/null +++ b/scripts/brew-install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -o errexit # abort on nonzero exitstatus +set -o nounset # abort on unbound variable +set -o pipefail # don't hide errors within pipes + +export HOMEBREW_NO_INSTALL_UPGRADE=1 +export HOMEBREW_NO_INSTALL_CLEANUP=1 +export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 +export HOMEBREW_NO_AUTO_UPDATE=1 +export HOMEBREW_NO_ANALYTICS=1 + +brew install node@18 +brew link --overwrite node@18 diff --git a/scripts/choco-install.ps1 b/scripts/choco-install.ps1 new file mode 100755 index 0000000..dc75d5e --- /dev/null +++ b/scripts/choco-install.ps1 @@ -0,0 +1,30 @@ +function Save-ChocoPackage { + param ( + $PackageName + ) + Rename-Item -Path "$env:ChocolateyInstall\lib\$PackageName\$PackageName.nupkg" -NewName "$PackageName.nupkg.zip" -ErrorAction:SilentlyContinue + Expand-Archive -LiteralPath "$env:ChocolateyInstall\lib\$PackageName\$PackageName.nupkg.zip" -DestinationPath "$env:ChocolateyInstall\lib\$PackageName" -Force + Remove-Item "$env:ChocolateyInstall\lib\$PackageName\_rels" -Recurse + Remove-Item "$env:ChocolateyInstall\lib\$PackageName\package" -Recurse + Remove-Item "$env:ChocolateyInstall\lib\$PackageName\[Content_Types].xml" + New-Item -Path "${PSScriptRoot}\..\tmp\chocolatey\$PackageName" -ItemType "directory" -ErrorAction:SilentlyContinue + choco pack "$env:ChocolateyInstall\lib\$PackageName\$PackageName.nuspec" --outdir "${PSScriptRoot}\..\tmp\chocolatey\$PackageName" +} + +# Check for existence of required environment variables +if ( $null -eq $env:ChocolateyInstall ) { + [Console]::Error.WriteLine('Missing $env:ChocolateyInstall environment variable') + exit 1 +} + +# Add the cached packages with source priority 1 (Chocolatey community is 0) +New-Item -Path "${PSScriptRoot}\..\tmp\chocolatey" -ItemType "directory" -ErrorAction:SilentlyContinue +choco source add --name="cache" --source="${PSScriptRoot}\..\tmp\chocolatey" --priority=1 + +# Install nodejs v18.15.0 (will use cache if exists) +$nodejs = "nodejs.install" +choco install "$nodejs" --version="18.15.0" --require-checksums -y +# Internalise nodejs to cache if doesn't exist +if ( -not (Test-Path -Path "${PSScriptRoot}\..\tmp\chocolatey\$nodejs\$nodejs.18.15.0.nupkg" -PathType Leaf) ) { + Save-ChocoPackage -PackageName $nodejs +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..54ec565 --- /dev/null +++ b/shell.nix @@ -0,0 +1,34 @@ +{ pkgs ? import ./pkgs.nix {}, ci ? false }: + +with pkgs; +mkShell { + nativeBuildInputs = [ + nodejs_20 + shellcheck + gitAndTools.gh + ]; + shellHook = '' + echo "Entering $(npm pkg get name)" + set -o allexport + . ./.env + set +o allexport + set -v + ${ + lib.optionalString ci + '' + set -o errexit + set -o nounset + set -o pipefail + shopt -s inherit_errexit + '' + } + mkdir --parents "$(pwd)/tmp" + + # Built executables and NPM executables + export PATH="$(pwd)/dist/bin:$(npm root)/.bin:$PATH" + + npm install --ignore-scripts + + set +v + ''; +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/tests/global.d.ts b/tests/global.d.ts new file mode 100644 index 0000000..5342a19 --- /dev/null +++ b/tests/global.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable no-var */ + +/// + +/** + * Follows the globals in jest.config.ts + * @module + */ +declare var projectDir: string; +declare var testDir: string; +declare var defaultTimeout: number; +declare var maxTimeout: number; diff --git a/tests/globalSetup.ts b/tests/globalSetup.ts new file mode 100644 index 0000000..2cb0f05 --- /dev/null +++ b/tests/globalSetup.ts @@ -0,0 +1,6 @@ +async function setup() { + // eslint-disable-next-line no-console + console.log('\nGLOBAL SETUP'); +} + +export default setup; diff --git a/tests/globalTeardown.ts b/tests/globalTeardown.ts new file mode 100644 index 0000000..173ae41 --- /dev/null +++ b/tests/globalTeardown.ts @@ -0,0 +1,6 @@ +async function teardown() { + // eslint-disable-next-line no-console + console.log('GLOBAL TEARDOWN'); +} + +export default teardown; diff --git a/tests/index.test.ts b/tests/index.test.ts new file mode 100644 index 0000000..d48a1eb --- /dev/null +++ b/tests/index.test.ts @@ -0,0 +1 @@ +describe('index', () => {}); diff --git a/tests/setup.ts b/tests/setup.ts new file mode 100644 index 0000000..e69de29 diff --git a/tests/setupAfterEnv.ts b/tests/setupAfterEnv.ts new file mode 100644 index 0000000..8ea8279 --- /dev/null +++ b/tests/setupAfterEnv.ts @@ -0,0 +1,4 @@ +// Default timeout per test +// some tests may take longer in which case you should specify the timeout +// explicitly for each test by using the third parameter of test function +jest.setTimeout(globalThis.defaultTimeout); diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..724de44 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "noEmit": false, + "stripInternal": true + }, + "exclude": [ + "./tests/**/*", + "./scripts/**/*", + "./benches/**/*" + ] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..907ed72 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "tsBuildInfoFile": "./dist/tsbuildinfo", + "incremental": true, + "sourceMap": true, + "declaration": true, + "allowJs": true, + "strictNullChecks": true, + "noImplicitAny": false, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "moduleResolution": "node", + "module": "CommonJS", + "target": "ES2022", + "baseUrl": "./src", + "paths": { + "@": ["index"], + "@/*": ["*"] + }, + "noEmit": true + }, + "include": [ + "./src/**/*", + "./src/**/*.json", + "./tests/**/*", + "./scripts/**/*", + "./benches/**/*" + ], + "ts-node": { + "require": ["tsconfig-paths/register"], + "transpileOnly": true, + "swc": true + } +} From 7c54059c5f9884fae7cc4f61ebaa4ea586c7c830 Mon Sep 17 00:00:00 2001 From: Roger Qiu Date: Tue, 5 Sep 2023 13:57:54 +1000 Subject: [PATCH 02/12] ci: updated to node 20 --- scripts/brew-install.sh | 4 ++-- scripts/choco-install.ps1 | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/brew-install.sh b/scripts/brew-install.sh index 11215a6..9981a2d 100755 --- a/scripts/brew-install.sh +++ b/scripts/brew-install.sh @@ -10,5 +10,5 @@ export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 export HOMEBREW_NO_AUTO_UPDATE=1 export HOMEBREW_NO_ANALYTICS=1 -brew install node@18 -brew link --overwrite node@18 +brew reinstall node@20 +brew link --overwrite node@20 diff --git a/scripts/choco-install.ps1 b/scripts/choco-install.ps1 index dc75d5e..afe9ba4 100755 --- a/scripts/choco-install.ps1 +++ b/scripts/choco-install.ps1 @@ -21,10 +21,10 @@ if ( $null -eq $env:ChocolateyInstall ) { New-Item -Path "${PSScriptRoot}\..\tmp\chocolatey" -ItemType "directory" -ErrorAction:SilentlyContinue choco source add --name="cache" --source="${PSScriptRoot}\..\tmp\chocolatey" --priority=1 -# Install nodejs v18.15.0 (will use cache if exists) +# Install nodejs v20.5.1 (will use cache if exists) $nodejs = "nodejs.install" -choco install "$nodejs" --version="18.15.0" --require-checksums -y +choco install "$nodejs" --version="20.5.1" --require-checksums -y # Internalise nodejs to cache if doesn't exist -if ( -not (Test-Path -Path "${PSScriptRoot}\..\tmp\chocolatey\$nodejs\$nodejs.18.15.0.nupkg" -PathType Leaf) ) { +if ( -not (Test-Path -Path "${PSScriptRoot}\..\tmp\chocolatey\$nodejs\$nodejs.20.5.1.nupkg" -PathType Leaf) ) { Save-ChocoPackage -PackageName $nodejs } From c1627883f47bb185b15845a62cd9fee251f39b7c Mon Sep 17 00:00:00 2001 From: Roger Qiu Date: Tue, 5 Sep 2023 13:57:54 +1000 Subject: [PATCH 03/12] ci: updated to node 20 WIPO Adding matrix packages to package.json WIP Changing dir WIP * Errors added new error type and sig dec for RPCServer RPCServer rewritten without PK dependency. * New utils with isObj and promise methods implemented middleware import fix WIP * Apparently fixing RPCServer.ts fixed all of import issues of RPCClient.ts as well, and client has no PK related imports now, so its fixed? #COPE WIP cping tests from pk to js-rpc experimental Decorators and changing logger version experimental Decorators and changing logger version sleep in utils.ts WIP Test resolve wip wip --- package.json | 9 + scripts/brew-install.sh | 4 +- scripts/choco-install.ps1 | 6 +- src/RPCClient.ts | 524 ++++++++++++ src/RPCServer.ts | 634 +++++++++++++++ src/callers.ts | 53 ++ src/errors/errors.ts | 204 +++++ src/errors/index.ts | 2 + src/errors/sysexits.ts | 91 +++ src/events.ts | 13 + src/handlers.ts | 99 +++ src/index.ts | 6 + src/types.ts | 363 +++++++++ src/utils/index.ts | 2 + src/utils/middleware.ts | 203 +++++ src/utils/utils.ts | 523 ++++++++++++ tests/index.test.ts | 1 - tests/rpc/RPC.test.ts | 555 +++++++++++++ tests/rpc/RPCClient.test.ts | 1172 +++++++++++++++++++++++++++ tests/rpc/RPCServer.test.ts | 1215 ++++++++++++++++++++++++++++ tests/rpc/utils.ts | 302 +++++++ tests/rpc/utils/middleware.test.ts | 103 +++ tests/rpc/utils/utils.test.ts | 26 + tsconfig.json | 1 + 24 files changed, 6105 insertions(+), 6 deletions(-) create mode 100644 src/RPCClient.ts create mode 100644 src/RPCServer.ts create mode 100644 src/callers.ts create mode 100644 src/errors/errors.ts create mode 100644 src/errors/index.ts create mode 100644 src/errors/sysexits.ts create mode 100644 src/events.ts create mode 100644 src/handlers.ts create mode 100644 src/types.ts create mode 100644 src/utils/index.ts create mode 100644 src/utils/middleware.ts create mode 100644 src/utils/utils.ts delete mode 100644 tests/index.test.ts create mode 100644 tests/rpc/RPC.test.ts create mode 100644 tests/rpc/RPCClient.test.ts create mode 100644 tests/rpc/RPCServer.test.ts create mode 100644 tests/rpc/utils.ts create mode 100644 tests/rpc/utils/middleware.test.ts create mode 100644 tests/rpc/utils/utils.test.ts diff --git a/package.json b/package.json index 66c6d91..2155365 100644 --- a/package.json +++ b/package.json @@ -54,5 +54,14 @@ "tsconfig-paths": "^3.9.0", "typedoc": "^0.23.21", "typescript": "^4.9.3" + }, + "dependencies": { + "@fast-check/jest": "^1.7.2", + "@matrixai/async-init": "^1.9.1", + "@matrixai/contexts": "^1.2.0", + "@matrixai/id": "^3.3.6", + "@matrixai/logger": "^3.1.0", + "@streamparser/json": "^0.0.17", + "ix": "^5.0.0" } } diff --git a/scripts/brew-install.sh b/scripts/brew-install.sh index 11215a6..9981a2d 100755 --- a/scripts/brew-install.sh +++ b/scripts/brew-install.sh @@ -10,5 +10,5 @@ export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 export HOMEBREW_NO_AUTO_UPDATE=1 export HOMEBREW_NO_ANALYTICS=1 -brew install node@18 -brew link --overwrite node@18 +brew reinstall node@20 +brew link --overwrite node@20 diff --git a/scripts/choco-install.ps1 b/scripts/choco-install.ps1 index dc75d5e..afe9ba4 100755 --- a/scripts/choco-install.ps1 +++ b/scripts/choco-install.ps1 @@ -21,10 +21,10 @@ if ( $null -eq $env:ChocolateyInstall ) { New-Item -Path "${PSScriptRoot}\..\tmp\chocolatey" -ItemType "directory" -ErrorAction:SilentlyContinue choco source add --name="cache" --source="${PSScriptRoot}\..\tmp\chocolatey" --priority=1 -# Install nodejs v18.15.0 (will use cache if exists) +# Install nodejs v20.5.1 (will use cache if exists) $nodejs = "nodejs.install" -choco install "$nodejs" --version="18.15.0" --require-checksums -y +choco install "$nodejs" --version="20.5.1" --require-checksums -y # Internalise nodejs to cache if doesn't exist -if ( -not (Test-Path -Path "${PSScriptRoot}\..\tmp\chocolatey\$nodejs\$nodejs.18.15.0.nupkg" -PathType Leaf) ) { +if ( -not (Test-Path -Path "${PSScriptRoot}\..\tmp\chocolatey\$nodejs\$nodejs.20.5.1.nupkg" -PathType Leaf) ) { Save-ChocoPackage -PackageName $nodejs } diff --git a/src/RPCClient.ts b/src/RPCClient.ts new file mode 100644 index 0000000..6d305aa --- /dev/null +++ b/src/RPCClient.ts @@ -0,0 +1,524 @@ +import type { WritableStream, ReadableStream } from 'stream/web'; +import type { ContextTimedInput } from '@matrixai/contexts'; +import type { + HandlerType, + JSONRPCRequestMessage, + StreamFactory, + ClientManifest, + RPCStream, + JSONRPCResponseResult, +} from './types'; +import type { JSONValue } from './types'; +import type { + JSONRPCRequest, + JSONRPCResponse, + MiddlewareFactory, + MapCallers, +} from './types'; +import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; +import Logger from '@matrixai/logger'; +import { Timer } from '@matrixai/timer'; +import * as rpcUtilsMiddleware from './utils/middleware'; +import * as rpcErrors from './errors'; +import * as rpcUtils from './utils/utils'; +import { promise } from './utils'; +import { never } from './errors'; + +const timerCleanupReasonSymbol = Symbol('timerCleanUpReasonSymbol'); + +// eslint-disable-next-line +interface RPCClient extends CreateDestroy {} +@CreateDestroy() +class RPCClient { + /** + * @param obj + * @param obj.manifest - Client manifest that defines the types for the rpc + * methods. + * @param obj.streamFactory - An arrow function that when called, creates a + * new stream for each rpc method call. + * @param obj.middlewareFactory - Middleware used to process the rpc messages. + * The middlewareFactory needs to be a function that creates a pair of + * transform streams that convert `JSONRPCRequest` to `Uint8Array` on the forward + * path and `Uint8Array` to `JSONRPCResponse` on the reverse path. + * @param obj.streamKeepAliveTimeoutTime - Timeout time used if no timeout timer was provided when making a call. + * Defaults to 60,000 milliseconds. + * for a client call. + * @param obj.logger + */ + static async createRPCClient({ + manifest, + streamFactory, + middlewareFactory = rpcUtilsMiddleware.defaultClientMiddlewareWrapper(), + streamKeepAliveTimeoutTime = 60_000, // 1 minute + logger = new Logger(this.name), + }: { + manifest: M; + streamFactory: StreamFactory; + middlewareFactory?: MiddlewareFactory< + Uint8Array, + JSONRPCRequest, + JSONRPCResponse, + Uint8Array + >; + streamKeepAliveTimeoutTime?: number; + logger?: Logger; + }) { + logger.info(`Creating ${this.name}`); + const rpcClient = new this({ + manifest, + streamFactory, + middlewareFactory, + streamKeepAliveTimeoutTime: streamKeepAliveTimeoutTime, + logger, + }); + logger.info(`Created ${this.name}`); + return rpcClient; + } + + protected logger: Logger; + protected streamFactory: StreamFactory; + protected middlewareFactory: MiddlewareFactory< + Uint8Array, + JSONRPCRequest, + JSONRPCResponse, + Uint8Array + >; + protected callerTypes: Record; + // Method proxies + public readonly streamKeepAliveTimeoutTime: number; + public readonly methodsProxy = new Proxy( + {}, + { + get: (_, method) => { + if (typeof method === 'symbol') return; + switch (this.callerTypes[method]) { + case 'UNARY': + return (params, ctx) => this.unaryCaller(method, params, ctx); + case 'SERVER': + return (params, ctx) => + this.serverStreamCaller(method, params, ctx); + case 'CLIENT': + return (ctx) => this.clientStreamCaller(method, ctx); + case 'DUPLEX': + return (ctx) => this.duplexStreamCaller(method, ctx); + case 'RAW': + return (header, ctx) => this.rawStreamCaller(method, header, ctx); + default: + return; + } + }, + }, + ); + + public constructor({ + manifest, + streamFactory, + middlewareFactory, + streamKeepAliveTimeoutTime, + logger, + }: { + manifest: M; + streamFactory: StreamFactory; + middlewareFactory: MiddlewareFactory< + Uint8Array, + JSONRPCRequest, + JSONRPCResponse, + Uint8Array + >; + streamKeepAliveTimeoutTime: number; + logger: Logger; + }) { + this.callerTypes = rpcUtils.getHandlerTypes(manifest); + this.streamFactory = streamFactory; + this.middlewareFactory = middlewareFactory; + this.streamKeepAliveTimeoutTime = streamKeepAliveTimeoutTime; + this.logger = logger; + } + + public async destroy(): Promise { + this.logger.info(`Destroying ${this.constructor.name}`); + this.logger.info(`Destroyed ${this.constructor.name}`); + } + + @ready(new rpcErrors.ErrorRPCDestroyed()) + public get methods(): MapCallers { + return this.methodsProxy as MapCallers; + } + + /** + * Generic caller for unary RPC calls. + * This returns the response in the provided type. No validation is done so + * make sure the types match the handler types. + * @param method - Method name of the RPC call + * @param parameters - Parameters to be provided with the RPC message. Matches + * the provided I type. + * @param ctx - ContextTimed used for timeouts and cancellation. + */ + @ready(new rpcErrors.ErrorRPCDestroyed()) + public async unaryCaller( + method: string, + parameters: I, + ctx: Partial = {}, + ): Promise { + const callerInterface = await this.duplexStreamCaller(method, ctx); + const reader = callerInterface.readable.getReader(); + const writer = callerInterface.writable.getWriter(); + try { + await writer.write(parameters); + const output = await reader.read(); + if (output.done) { + throw new rpcErrors.ErrorRPCMissingResponse(); + } + await reader.cancel(); + await writer.close(); + return output.value; + } finally { + // Attempt clean up, ignore errors if already cleaned up + await reader.cancel().catch(() => {}); + await writer.close().catch(() => {}); + } + } + + /** + * Generic caller for server streaming RPC calls. + * This returns a ReadableStream of the provided type. When finished, the + * readable needs to be cleaned up, otherwise cleanup happens mostly + * automatically. + * @param method - Method name of the RPC call + * @param parameters - Parameters to be provided with the RPC message. Matches + * the provided I type. + * @param ctx - ContextTimed used for timeouts and cancellation. + */ + @ready(new rpcErrors.ErrorRPCDestroyed()) + public async serverStreamCaller( + method: string, + parameters: I, + ctx: Partial = {}, + ): Promise> { + const callerInterface = await this.duplexStreamCaller(method, ctx); + const writer = callerInterface.writable.getWriter(); + try { + await writer.write(parameters); + await writer.close(); + } catch (e) { + // Clean up if any problems, ignore errors if already closed + await callerInterface.readable.cancel(e); + throw e; + } + return callerInterface.readable; + } + + /** + * Generic caller for Client streaming RPC calls. + * This returns a WritableStream for writing the input to and a Promise that + * resolves when the output is received. + * When finished the writable stream must be ended. Failing to do so will + * hold the connection open and result in a resource leak until the + * call times out. + * @param method - Method name of the RPC call + * @param ctx - ContextTimed used for timeouts and cancellation. + */ + @ready(new rpcErrors.ErrorRPCDestroyed()) + public async clientStreamCaller( + method: string, + ctx: Partial = {}, + ): Promise<{ + output: Promise; + writable: WritableStream; + }> { + const callerInterface = await this.duplexStreamCaller(method, ctx); + const reader = callerInterface.readable.getReader(); + const output = reader.read().then(({ value, done }) => { + if (done) { + throw new rpcErrors.ErrorRPCMissingResponse(); + } + return value; + }); + return { + output, + writable: callerInterface.writable, + }; + } + + /** + * Generic caller for duplex RPC calls. + * This returns a `ReadableWritablePair` of the types specified. No validation + * is applied to these types so make sure they match the types of the handler + * you are calling. + * When finished the streams must be ended manually. Failing to do so will + * hold the connection open and result in a resource leak until the + * call times out. + * @param method - Method name of the RPC call + * @param ctx - ContextTimed used for timeouts and cancellation. + */ + @ready(new rpcErrors.ErrorRPCDestroyed()) + public async duplexStreamCaller( + method: string, + ctx: Partial = {}, + ): Promise> { + // Setting up abort signal and timer + const abortController = new AbortController(); + const signal = abortController.signal; + // A promise that will reject if there is an abort signal or timeout + const abortRaceProm = promise(); + // Prevent unhandled rejection when we're done with the promise + abortRaceProm.p.catch(() => {}); + const abortRacePromHandler = () => { + abortRaceProm.rejectP(signal.reason); + }; + signal.addEventListener('abort', abortRacePromHandler); + + let abortHandler: () => void; + if (ctx.signal != null) { + // Propagate signal events + abortHandler = () => { + abortController.abort(ctx.signal?.reason); + }; + if (ctx.signal.aborted) abortHandler(); + ctx.signal.addEventListener('abort', abortHandler); + } + let timer: Timer; + if (!(ctx.timer instanceof Timer)) { + timer = new Timer({ + delay: ctx.timer ?? this.streamKeepAliveTimeoutTime, + }); + } else { + timer = ctx.timer; + } + const cleanUp = () => { + // Clean up the timer and signal + if (ctx.timer == null) timer.cancel(timerCleanupReasonSymbol); + if (ctx.signal != null) { + ctx.signal.removeEventListener('abort', abortHandler); + } + signal.addEventListener('abort', abortRacePromHandler); + }; + // Setting up abort events for timeout + const timeoutError = new rpcErrors.ErrorRPCTimedOut(); + void timer.then( + () => { + abortController.abort(timeoutError); + }, + () => {}, // Ignore cancellation error + ); + + // Hooking up agnostic stream side + let rpcStream: RPCStream; + const streamFactoryProm = this.streamFactory({ signal, timer }); + try { + rpcStream = await Promise.race([streamFactoryProm, abortRaceProm.p]); + } catch (e) { + cleanUp(); + void streamFactoryProm.then((stream) => + stream.cancel(Error('TMP stream timed out early')), + ); + throw e; + } + void timer.then( + () => { + rpcStream.cancel(new rpcErrors.ErrorRPCTimedOut()); + }, + () => {}, // Ignore cancellation error + ); + // Deciding if we want to allow refreshing + // We want to refresh timer if none was provided + const refreshingTimer: Timer | undefined = + ctx.timer == null ? timer : undefined; + // Composing stream transforms and middleware + const metadata = { + ...(rpcStream.meta ?? {}), + command: method, + }; + const outputMessageTransformStream = + rpcUtils.clientOutputTransformStream(metadata, refreshingTimer); + const inputMessageTransformStream = rpcUtils.clientInputTransformStream( + method, + refreshingTimer, + ); + const middleware = this.middlewareFactory( + { signal, timer }, + rpcStream.cancel, + metadata, + ); + // This `Promise.allSettled` is used to asynchronously track the state + // of the streams. When both have finished we can clean up resources. + void Promise.allSettled([ + rpcStream.readable + .pipeThrough(middleware.reverse) + .pipeTo(outputMessageTransformStream.writable) + // Ignore any errors, we only care about stream ending + .catch(() => {}), + inputMessageTransformStream.readable + .pipeThrough(middleware.forward) + .pipeTo(rpcStream.writable) + // Ignore any errors, we only care about stream ending + .catch(() => {}), + ]).finally(() => { + cleanUp(); + }); + + // Returning interface + return { + readable: outputMessageTransformStream.readable, + writable: inputMessageTransformStream.writable, + cancel: rpcStream.cancel, + meta: metadata, + }; + } + + /** + * Generic caller for raw RPC calls. + * This returns a `ReadableWritablePair` of the raw RPC stream. + * When finished the streams must be ended manually. Failing to do so will + * hold the connection open and result in a resource leak until the + * call times out. + * Raw streams don't support the keep alive timeout. Timeout will only apply\ + * to the creation of the stream. + * @param method - Method name of the RPC call + * @param headerParams - Parameters for the header message. The header is a + * single RPC message that is sent to specify the method for the RPC call. + * Any metadata of extra parameters is provided here. + * @param ctx - ContextTimed used for timeouts and cancellation. + */ + @ready(new rpcErrors.ErrorRPCDestroyed()) + public async rawStreamCaller( + method: string, + headerParams: JSONValue, + ctx: Partial = {}, + ): Promise< + RPCStream< + Uint8Array, + Uint8Array, + Record & { result: JSONValue; command: string } + > + > { + // Setting up abort signal and timer + const abortController = new AbortController(); + const signal = abortController.signal; + // A promise that will reject if there is an abort signal or timeout + const abortRaceProm = promise(); + // Prevent unhandled rejection when we're done with the promise + abortRaceProm.p.catch(() => {}); + const abortRacePromHandler = () => { + abortRaceProm.rejectP(signal.reason); + }; + signal.addEventListener('abort', abortRacePromHandler); + + let abortHandler: () => void; + if (ctx.signal != null) { + // Propagate signal events + abortHandler = () => { + abortController.abort(ctx.signal?.reason); + }; + if (ctx.signal.aborted) abortHandler(); + ctx.signal.addEventListener('abort', abortHandler); + } + let timer: Timer; + if (!(ctx.timer instanceof Timer)) { + timer = new Timer({ + delay: ctx.timer ?? this.streamKeepAliveTimeoutTime, + }); + } else { + timer = ctx.timer; + } + const cleanUp = () => { + // Clean up the timer and signal + if (ctx.timer == null) timer.cancel(timerCleanupReasonSymbol); + if (ctx.signal != null) { + ctx.signal.removeEventListener('abort', abortHandler); + } + signal.addEventListener('abort', abortRacePromHandler); + }; + // Setting up abort events for timeout + const timeoutError = new rpcErrors.ErrorRPCTimedOut(); + void timer.then( + () => { + abortController.abort(timeoutError); + }, + () => {}, // Ignore cancellation error + ); + + const setupStream = async (): Promise< + [JSONValue, RPCStream] + > => { + if (signal.aborted) throw signal.reason; + const abortProm = promise(); + // Ignore error if orphaned + void abortProm.p.catch(() => {}); + signal.addEventListener( + 'abort', + () => { + abortProm.rejectP(signal.reason); + }, + { once: true }, + ); + const rpcStream = await Promise.race([ + this.streamFactory({ signal, timer }), + abortProm.p, + ]); + const tempWriter = rpcStream.writable.getWriter(); + const header: JSONRPCRequestMessage = { + jsonrpc: '2.0', + method, + params: headerParams, + id: null, + }; + await tempWriter.write(Buffer.from(JSON.stringify(header))); + tempWriter.releaseLock(); + const headTransformStream = rpcUtils.parseHeadStream( + rpcUtils.parseJSONRPCResponse, + ); + void rpcStream.readable + // Allow us to re-use the readable after reading the first message + .pipeTo(headTransformStream.writable) + // Ignore any errors here, we only care that it ended + .catch(() => {}); + const tempReader = headTransformStream.readable.getReader(); + let leadingMessage: JSONRPCResponseResult; + try { + const message = await Promise.race([tempReader.read(), abortProm.p]); + const messageValue = message.value as JSONRPCResponse; + if (message.done) never(); + if ('error' in messageValue) { + const metadata = { + ...(rpcStream.meta ?? {}), + command: method, + }; + throw rpcUtils.toError(messageValue.error.data, metadata); + } + leadingMessage = messageValue; + } catch (e) { + rpcStream.cancel(Error('TMP received error in leading response')); + throw e; + } + tempReader.releaseLock(); + const newRpcStream: RPCStream = { + writable: rpcStream.writable, + readable: headTransformStream.readable as ReadableStream, + cancel: rpcStream.cancel, + meta: rpcStream.meta, + }; + return [leadingMessage.result, newRpcStream]; + }; + let streamCreation: [JSONValue, RPCStream]; + try { + streamCreation = await setupStream(); + } finally { + cleanUp(); + } + const [result, rpcStream] = streamCreation; + const metadata = { + ...(rpcStream.meta ?? {}), + result, + command: method, + }; + return { + writable: rpcStream.writable, + readable: rpcStream.readable, + cancel: rpcStream.cancel, + meta: metadata, + }; + } +} + +export default RPCClient; diff --git a/src/RPCServer.ts b/src/RPCServer.ts new file mode 100644 index 0000000..f38b344 --- /dev/null +++ b/src/RPCServer.ts @@ -0,0 +1,634 @@ +import type { ReadableStreamDefaultReadResult } from 'stream/web'; +import type { + ClientHandlerImplementation, + DuplexHandlerImplementation, + JSONRPCError, + JSONRPCRequest, + JSONRPCResponse, + JSONRPCResponseError, + JSONRPCResponseResult, + ServerManifest, + RawHandlerImplementation, + ServerHandlerImplementation, + UnaryHandlerImplementation, + RPCStream, + MiddlewareFactory, +} from './types'; +import type { JSONValue } from './types'; +import { ReadableStream, TransformStream } from 'stream/web'; +import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; +import Logger from '@matrixai/logger'; +import { PromiseCancellable } from '@matrixai/async-cancellable'; +import { Timer } from '@matrixai/timer'; +import { + ClientHandler, + DuplexHandler, + RawHandler, + ServerHandler, + UnaryHandler, +} from './handlers'; +import * as rpcEvents from './events'; +import * as rpcUtils from './utils/utils'; +import * as rpcErrors from './errors'; +import * as rpcUtilsMiddleware from './utils/middleware'; +import sysexits from './errors/sysexits'; +import { never } from './errors'; + +const cleanupReason = Symbol('CleanupReason'); + +/** + * You must provide a error handler `addEventListener('error')`. + * Otherwise errors will just be ignored. + * + * Events: + * - error + */ +interface RPCServer extends CreateDestroy {} +@CreateDestroy() +class RPCServer extends EventTarget { + /** + * Creates RPC server. + + * @param obj + * @param obj.manifest - Server manifest used to define the rpc method + * handlers. + * @param obj.middlewareFactory - Middleware used to process the rpc messages. + * The middlewareFactory needs to be a function that creates a pair of + * transform streams that convert `Uint8Array` to `JSONRPCRequest` on the forward + * path and `JSONRPCResponse` to `Uint8Array` on the reverse path. + * @param obj.sensitive - If true, sanitises any rpc error messages of any + * sensitive information. + * @param obj.streamKeepAliveTimeoutTime - Time before a connection is cleaned up due to no activity. This is the + * value used if the handler doesn't specify its own timeout time. This timeout is advisory and only results in a + * signal sent to the handler. Stream is forced to end after the timeoutForceCloseTime. Defaults to 60,000 + * milliseconds. + * @param obj.timeoutForceCloseTime - Time before the stream is forced to end after the initial timeout time. + * The stream will be forced to close after this amount of time after the initial timeout. This is a grace period for + * the handler to handle timeout before it is forced to end. Defaults to 2,000 milliseconds. + * @param obj.logger + */ + public static async createRPCServer({ + manifest, + middlewareFactory = rpcUtilsMiddleware.defaultServerMiddlewareWrapper(), + sensitive = false, + handlerTimeoutTime = 60_000, // 1 minute + handlerTimeoutGraceTime = 2_000, // 2 seconds + logger = new Logger(this.name), + }: { + manifest: ServerManifest; + middlewareFactory?: MiddlewareFactory< + JSONRPCRequest, + Uint8Array, + Uint8Array, + JSONRPCResponse + >; + sensitive?: boolean; + handlerTimeoutTime?: number; + handlerTimeoutGraceTime?: number; + logger?: Logger; + }): Promise { + logger.info(`Creating ${this.name}`); + const rpcServer = new this({ + manifest, + middlewareFactory, + sensitive, + handlerTimeoutTime, + handlerTimeoutGraceTime, + logger, + }); + logger.info(`Created ${this.name}`); + return rpcServer; + } + + protected logger: Logger; + protected handlerMap: Map = new Map(); + protected defaultTimeoutMap: Map = new Map(); + protected handlerTimeoutTime: number; + protected handlerTimeoutGraceTime: number; + protected activeStreams: Set> = new Set(); + protected sensitive: boolean; + protected middlewareFactory: MiddlewareFactory< + JSONRPCRequest, + Uint8Array, + Uint8Array, + JSONRPCResponseResult + >; + + public constructor({ + manifest, + middlewareFactory, + sensitive, + handlerTimeoutTime = 60_000, // 1 minuet + handlerTimeoutGraceTime = 2_000, // 2 seconds + logger, + }: { + manifest: ServerManifest; + + middlewareFactory: MiddlewareFactory< + JSONRPCRequest, + Uint8Array, + Uint8Array, + JSONRPCResponseResult + >; + handlerTimeoutTime?: number; + handlerTimeoutGraceTime?: number; + sensitive: boolean; + logger: Logger; + }) { + super(); + for (const [key, manifestItem] of Object.entries(manifest)) { + if (manifestItem instanceof RawHandler) { + this.registerRawStreamHandler( + key, + manifestItem.handle.bind(manifestItem), + manifestItem.timeout, + ); + continue; + } + if (manifestItem instanceof DuplexHandler) { + this.registerDuplexStreamHandler( + key, + manifestItem.handle.bind(manifestItem), + manifestItem.timeout, + ); + continue; + } + if (manifestItem instanceof ServerHandler) { + this.registerServerStreamHandler( + key, + manifestItem.handle.bind(manifestItem), + manifestItem.timeout, + ); + continue; + } + if (manifestItem instanceof ClientHandler) { + this.registerClientStreamHandler( + key, + manifestItem.handle.bind(manifestItem), + manifestItem.timeout, + ); + continue; + } + if (manifestItem instanceof ClientHandler) { + this.registerClientStreamHandler( + key, + manifestItem.handle.bind(manifestItem), + manifestItem.timeout, + ); + continue; + } + if (manifestItem instanceof UnaryHandler) { + this.registerUnaryHandler( + key, + manifestItem.handle.bind(manifestItem), + manifestItem.timeout, + ); + continue; + } + never(); + } + this.middlewareFactory = middlewareFactory; + this.sensitive = sensitive; + this.handlerTimeoutTime = handlerTimeoutTime; + this.handlerTimeoutGraceTime = handlerTimeoutGraceTime; + this.logger = logger; + } + + public async destroy(force: boolean = true): Promise { + this.logger.info(`Destroying ${this.constructor.name}`); + // Stopping any active steams + if (force) { + for await (const [activeStream] of this.activeStreams.entries()) { + activeStream.cancel(new rpcErrors.ErrorRPCStopping()); + } + } + for await (const [activeStream] of this.activeStreams.entries()) { + await activeStream; + } + this.logger.info(`Destroyed ${this.constructor.name}`); + } + + /** + * Registers a raw stream handler. This is the basis for all handlers as + * handling the streams is done with raw streams only. + * The raw streams do not automatically refresh the timeout timer when + * messages are sent or received. + */ + protected registerRawStreamHandler( + method: string, + handler: RawHandlerImplementation, + timeout: number | undefined, + ) { + this.handlerMap.set(method, handler); + this.defaultTimeoutMap.set(method, timeout); + } + + /** + * Registers a duplex stream handler. + * This handles all message parsing and conversion from generators + * to raw streams. + * + * @param method - The rpc method name. + * @param handler - The handler takes an input async iterable and returns an output async iterable. + * @param timeout + */ + protected registerDuplexStreamHandler< + I extends JSONValue, + O extends JSONValue, + >( + method: string, + handler: DuplexHandlerImplementation, + timeout: number | undefined, + ): void { + const rawSteamHandler: RawHandlerImplementation = async ( + [header, input], + cancel, + meta, + ctx, + ) => { + // Setting up abort controller + const abortController = new AbortController(); + if (ctx.signal.aborted) abortController.abort(ctx.signal.reason); + ctx.signal.addEventListener('abort', () => { + abortController.abort(ctx.signal.reason); + }); + const signal = abortController.signal; + // Setting up middleware + const middleware = this.middlewareFactory(ctx, cancel, meta); + // Forward from the client to the server + // Transparent TransformStream that re-inserts the header message into the + // stream. + const headerStream = new TransformStream({ + start(controller) { + controller.enqueue(Buffer.from(JSON.stringify(header))); + }, + transform(chunk, controller) { + controller.enqueue(chunk); + }, + }); + const forwardStream = input + .pipeThrough(headerStream) + .pipeThrough(middleware.forward); + // Reverse from the server to the client + const reverseStream = middleware.reverse.writable; + // Generator derived from handler + const outputGen = async function* (): AsyncGenerator { + if (signal.aborted) throw signal.reason; + // Input generator derived from the forward stream + const inputGen = async function* (): AsyncIterable { + for await (const data of forwardStream) { + ctx.timer.refresh(); + yield data.params as I; + } + }; + const handlerG = handler(inputGen(), cancel, meta, { + signal, + timer: ctx.timer, + }); + for await (const response of handlerG) { + ctx.timer.refresh(); + const responseMessage: JSONRPCResponseResult = { + jsonrpc: '2.0', + result: response, + id: null, + }; + yield responseMessage; + } + }; + const outputGenerator = outputGen(); + const reverseMiddlewareStream = new ReadableStream({ + pull: async (controller) => { + try { + const { value, done } = await outputGenerator.next(); + if (done) { + controller.close(); + return; + } + controller.enqueue(value); + } catch (e) { + const rpcError: JSONRPCError = { + code: e.exitCode ?? sysexits.UNKNOWN, + message: e.description ?? '', + data: rpcUtils.fromError(e, this.sensitive), + }; + const rpcErrorMessage: JSONRPCResponseError = { + jsonrpc: '2.0', + error: rpcError, + id: null, + }; + controller.enqueue(rpcErrorMessage); + // Clean up the input stream here, ignore error if already ended + await forwardStream + .cancel( + new rpcErrors.ErrorRPCHandlerFailed('Error clean up', { + cause: e, + }), + ) + .catch(() => {}); + controller.close(); + } + }, + cancel: async (reason) => { + this.dispatchEvent( + new rpcEvents.RPCErrorEvent({ + detail: new rpcErrors.ErrorRPCOutputStreamError( + 'Stream has been cancelled', + { + cause: reason, + }, + ), + }), + ); + // Abort with the reason + abortController.abort(reason); + // If the output stream path fails then we need to end the generator + // early. + await outputGenerator.return(undefined); + }, + }); + // Ignore any errors here, it should propagate to the ends of the stream + void reverseMiddlewareStream.pipeTo(reverseStream).catch(() => {}); + return [undefined, middleware.reverse.readable]; + }; + this.registerRawStreamHandler(method, rawSteamHandler, timeout); + } + + protected registerUnaryHandler( + method: string, + handler: UnaryHandlerImplementation, + timeout: number | undefined, + ) { + const wrapperDuplex: DuplexHandlerImplementation = async function* ( + input, + cancel, + meta, + ctx, + ) { + // The `input` is expected to be an async iterable with only 1 value. + // Unlike generators, there is no `next()` method. + // So we use `break` after the first iteration. + for await (const inputVal of input) { + yield await handler(inputVal, cancel, meta, ctx); + break; + } + }; + this.registerDuplexStreamHandler(method, wrapperDuplex, timeout); + } + + protected registerServerStreamHandler< + I extends JSONValue, + O extends JSONValue, + >( + method: string, + handler: ServerHandlerImplementation, + timeout: number | undefined, + ) { + const wrapperDuplex: DuplexHandlerImplementation = async function* ( + input, + cancel, + meta, + ctx, + ) { + for await (const inputVal of input) { + yield* handler(inputVal, cancel, meta, ctx); + break; + } + }; + this.registerDuplexStreamHandler(method, wrapperDuplex, timeout); + } + + protected registerClientStreamHandler< + I extends JSONValue, + O extends JSONValue, + >( + method: string, + handler: ClientHandlerImplementation, + timeout: number | undefined, + ) { + const wrapperDuplex: DuplexHandlerImplementation = async function* ( + input, + cancel, + meta, + ctx, + ) { + yield await handler(input, cancel, meta, ctx); + }; + this.registerDuplexStreamHandler(method, wrapperDuplex, timeout); + } + + @ready(new rpcErrors.ErrorRPCDestroyed()) + public handleStream(rpcStream: RPCStream) { + // This will take a buffer stream of json messages and set up service + // handling for it. + // Constructing the PromiseCancellable for tracking the active stream + const abortController = new AbortController(); + // Setting up timeout timer logic + const timer = new Timer({ + delay: this.handlerTimeoutTime, + handler: () => { + abortController.abort(new rpcErrors.ErrorRPCTimedOut()); + }, + }); + // Grace timer is triggered with any abort signal. + // If grace timer completes then it will cause the RPCStream to end with + // `RPCStream.cancel(reason)`. + let graceTimer: Timer | undefined; + const handleAbort = () => { + const graceTimer = new Timer({ + delay: this.handlerTimeoutGraceTime, + handler: () => { + rpcStream.cancel(abortController.signal.reason); + }, + }); + void graceTimer + .catch(() => {}) // Ignore cancellation error + .finally(() => { + abortController.signal.removeEventListener('abort', handleAbort); + }); + }; + abortController.signal.addEventListener('abort', handleAbort); + const prom = (async () => { + const headTransformStream = rpcUtilsMiddleware.binaryToJsonMessageStream( + rpcUtils.parseJSONRPCRequest, + ); + // Transparent transform used as a point to cancel the input stream from + const passthroughTransform = new TransformStream< + Uint8Array, + Uint8Array + >(); + const inputStream = passthroughTransform.readable; + const inputStreamEndProm = rpcStream.readable + .pipeTo(passthroughTransform.writable) + // Ignore any errors here, we only care that it ended + .catch(() => {}); + void inputStream + // Allow us to re-use the readable after reading the first message + .pipeTo(headTransformStream.writable, { + preventClose: true, + preventCancel: true, + }) + // Ignore any errors here, we only care that it ended + .catch(() => {}); + const cleanUp = async (reason: any) => { + await inputStream.cancel(reason); + await rpcStream.writable.abort(reason); + await inputStreamEndProm; + timer.cancel(cleanupReason); + graceTimer?.cancel(cleanupReason); + await timer.catch(() => {}); + await graceTimer?.catch(() => {}); + }; + // Read a single empty value to consume the first message + const reader = headTransformStream.readable.getReader(); + // Allows timing out when waiting for the first message + let headerMessage: + | ReadableStreamDefaultReadResult + | undefined + | void; + try { + headerMessage = await Promise.race([ + reader.read(), + timer.then( + () => undefined, + () => {}, + ), + ]); + } catch (e) { + const newErr = new rpcErrors.ErrorRPCHandlerFailed( + 'Stream failed waiting for header', + { cause: e }, + ); + await inputStreamEndProm; + timer.cancel(cleanupReason); + graceTimer?.cancel(cleanupReason); + await timer.catch(() => {}); + await graceTimer?.catch(() => {}); + this.dispatchEvent( + new rpcEvents.RPCErrorEvent({ + detail: new rpcErrors.ErrorRPCOutputStreamError( + 'Stream failed waiting for header', + { + cause: newErr, + }, + ), + }), + ); + return; + } + // Downgrade back to the raw stream + await reader.cancel(); + // There are 2 conditions where we just end here + // 1. The timeout timer resolves before the first message + // 2. the stream ends before the first message + if (headerMessage == null) { + const newErr = new rpcErrors.ErrorRPCHandlerFailed( + 'Timed out waiting for header', + ); + await cleanUp(newErr); + this.dispatchEvent( + new rpcEvents.RPCErrorEvent({ + detail: new rpcErrors.ErrorRPCOutputStreamError( + 'Timed out waiting for header', + { + cause: newErr, + }, + ), + }), + ); + return; + } + if (headerMessage.done) { + const newErr = new rpcErrors.ErrorRPCHandlerFailed('Missing header'); + await cleanUp(newErr); + this.dispatchEvent( + new rpcEvents.RPCErrorEvent({ + detail: new rpcErrors.ErrorRPCOutputStreamError('Missing header', { + cause: newErr, + }), + }), + ); + return; + } + const method = headerMessage.value.method; + const handler = this.handlerMap.get(method); + if (handler == null) { + await cleanUp(new rpcErrors.ErrorRPCHandlerFailed('Missing handler')); + return; + } + if (abortController.signal.aborted) { + await cleanUp(new rpcErrors.ErrorRPCHandlerFailed('Aborted')); + return; + } + // Setting up Timeout logic + const timeout = this.defaultTimeoutMap.get(method); + if (timeout != null && timeout < this.handlerTimeoutTime) { + // Reset timeout with new delay if it is less than the default + timer.reset(timeout); + } else { + // Otherwise refresh + timer.refresh(); + } + this.logger.info(`Handling stream with method (${method})`); + let handlerResult: [JSONValue | undefined, ReadableStream]; + const headerWriter = rpcStream.writable.getWriter(); + try { + handlerResult = await handler( + [headerMessage.value, inputStream], + rpcStream.cancel, + rpcStream.meta, + { signal: abortController.signal, timer }, + ); + } catch (e) { + const rpcError: JSONRPCError = { + code: e.exitCode ?? sysexits.UNKNOWN, + message: e.description ?? '', + data: rpcUtils.fromError(e, this.sensitive), + }; + const rpcErrorMessage: JSONRPCResponseError = { + jsonrpc: '2.0', + error: rpcError, + id: null, + }; + await headerWriter.write(Buffer.from(JSON.stringify(rpcErrorMessage))); + await headerWriter.close(); + // Clean up and return + timer.cancel(cleanupReason); + abortController.signal.removeEventListener('abort', handleAbort); + graceTimer?.cancel(cleanupReason); + abortController.abort(new rpcErrors.ErrorRPCStreamEnded()); + rpcStream.cancel(Error('TMP header message was an error')); + return; + } + const [leadingResult, outputStream] = handlerResult; + + if (leadingResult !== undefined) { + // Writing leading metadata + const leadingMessage: JSONRPCResponseResult = { + jsonrpc: '2.0', + result: leadingResult, + id: null, + }; + await headerWriter.write(Buffer.from(JSON.stringify(leadingMessage))); + } + headerWriter.releaseLock(); + const outputStreamEndProm = outputStream + .pipeTo(rpcStream.writable) + .catch(() => {}); // Ignore any errors, we only care that it finished + await Promise.allSettled([inputStreamEndProm, outputStreamEndProm]); + this.logger.info(`Handled stream with method (${method})`); + // Cleaning up abort and timer + timer.cancel(cleanupReason); + abortController.signal.removeEventListener('abort', handleAbort); + graceTimer?.cancel(cleanupReason); + abortController.abort(new rpcErrors.ErrorRPCStreamEnded()); + })(); + const handlerProm = PromiseCancellable.from(prom, abortController).finally( + () => this.activeStreams.delete(handlerProm), + abortController, + ); + // Putting the PromiseCancellable into the active streams map + this.activeStreams.add(handlerProm); + } +} + +export default RPCServer; diff --git a/src/callers.ts b/src/callers.ts new file mode 100644 index 0000000..4a92988 --- /dev/null +++ b/src/callers.ts @@ -0,0 +1,53 @@ +import type { HandlerType } from './types'; +import type { JSONValue } from './types'; + +abstract class Caller< + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> { + protected _inputType: Input; + protected _outputType: Output; + // Need this to distinguish the classes when inferring types + abstract type: HandlerType; +} + +class RawCaller extends Caller { + public type: 'RAW' = 'RAW' as const; +} + +class DuplexCaller< + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Caller { + public type: 'DUPLEX' = 'DUPLEX' as const; +} + +class ServerCaller< + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Caller { + public type: 'SERVER' = 'SERVER' as const; +} + +class ClientCaller< + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Caller { + public type: 'CLIENT' = 'CLIENT' as const; +} + +class UnaryCaller< + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Caller { + public type: 'UNARY' = 'UNARY' as const; +} + +export { + Caller, + RawCaller, + DuplexCaller, + ServerCaller, + ClientCaller, + UnaryCaller, +}; diff --git a/src/errors/errors.ts b/src/errors/errors.ts new file mode 100644 index 0000000..b0039d5 --- /dev/null +++ b/src/errors/errors.ts @@ -0,0 +1,204 @@ +import type { Class } from '@matrixai/errors'; +import type { JSONValue } from '@/types'; +import sysexits from './sysexits'; + +interface RPCError extends Error { + exitCode?: number; +} + +class ErrorRPC extends Error implements RPCError { + constructor(message?: string) { + super(message); + this.name = 'ErrorRPC'; + this.description = 'Generic Error'; + } + exitCode?: number; + description?: string; + +} + +class ErrorRPCDestroyed extends ErrorRPC { + constructor(message?: string) { + super(message); // Call the parent constructor + this.name = 'ErrorRPCDestroyed'; // Optionally set a specific name + this.description = 'Rpc is destroyed'; // Set the specific description + this.exitCode = sysexits.USAGE; // Set the exit code + } +} + +class ErrorRPCParse extends ErrorRPC { + static description = 'Failed to parse Buffer stream'; + exitCode = sysexits.SOFTWARE; + cause: Error | undefined; // Added this line to hold the cause + + constructor(message?: string, options?: { cause: Error }) { + super(message); // Call the parent constructor + this.name = 'ErrorRPCParse'; // Optionally set a specific name + this.description = 'Failed to parse Buffer stream'; // Set the specific description + this.exitCode = sysexits.SOFTWARE; // Set the exit code + + // Set the cause if provided in options + if (options && options.cause) { + this.cause = options.cause; + } + } +} + +class ErrorRPCStopping extends ErrorRPC { + constructor(message?: string) { + super(message); // Call the parent constructor + this.name = 'ErrorRPCStopping'; // Optionally set a specific name + this.description = 'Rpc is stopping'; // Set the specific description + this.exitCode = sysexits.USAGE; // Set the exit code + } +} + +/** + * This is an internal error, it should not reach the top level. + */ +class ErrorRPCHandlerFailed extends ErrorRPC { + cause: Error | undefined; + + constructor(message?: string, options?: { cause: Error }) { + super(message); // Call the parent constructor + this.name = 'ErrorRPCHandlerFailed'; // Optionally set a specific name + this.description = 'Failed to handle stream'; // Set the specific description + this.exitCode = sysexits.SOFTWARE; // Set the exit code + + // Set the cause if provided in options + if (options && options.cause) { + this.cause = options.cause; + } + } +} + +class ErrorRPCMessageLength extends ErrorRPC { + static description = 'RPC Message exceeds maximum size'; + exitCode = sysexits.DATAERR; +} + +class ErrorRPCMissingResponse extends ErrorRPC { + constructor(message?: string) { + super(message); + this.name = 'ErrorRPCMissingResponse'; + this.description = 'Stream ended before response'; + this.exitCode = sysexits.UNAVAILABLE; + } +} + +interface ErrorRPCOutputStreamErrorOptions { + cause?: Error; + // ... other properties +} +class ErrorRPCOutputStreamError extends ErrorRPC { + cause?: Error; + + constructor(message: string, options: ErrorRPCOutputStreamErrorOptions) { + super(message); + this.name = 'ErrorRPCOutputStreamError'; + this.description = 'Output stream failed, unable to send data'; + this.exitCode = sysexits.UNAVAILABLE; + + // Set the cause if provided in options + if (options && options.cause) { + this.cause = options.cause; + } + } +} + +class ErrorRPCRemote extends ErrorRPC { + static description = 'Remote error from RPC call'; + exitCode: number = sysexits.UNAVAILABLE; + metadata: JSONValue | undefined; + + constructor(metadata?: JSONValue, message?: string, options?) { + super(message); + this.name = 'ErrorRPCRemote'; + this.metadata = metadata; + } + + public static fromJSON>( + this: T, + json: any, + ): InstanceType { + if ( + typeof json !== 'object' || + json.type !== this.name || + typeof json.data !== 'object' || + typeof json.data.message !== 'string' || + isNaN(Date.parse(json.data.timestamp)) || + typeof json.data.metadata !== 'object' || + typeof json.data.data !== 'object' || + typeof json.data.exitCode !== 'number' || + ('stack' in json.data && typeof json.data.stack !== 'string') + ) { + throw new TypeError(`Cannot decode JSON to ${this.name}`); + } + + // Here, you can define your own metadata object, or just use the one from JSON directly. + const parsedMetadata = json.data.metadata; + + const e = new this(parsedMetadata, json.data.message, { + timestamp: new Date(json.data.timestamp), + data: json.data.data, + cause: json.data.cause, + }); + e.exitCode = json.data.exitCode; + e.stack = json.data.stack; + return e; + } + public toJSON(): any { + return { + type: this.name, + data: { + description: this.description, + exitCode: this.exitCode, + }, + }; + } +} + +class ErrorRPCStreamEnded extends ErrorRPC { + constructor(message?: string) { + super(message); + this.name = 'ErrorRPCStreamEnded'; + this.description = 'Handled stream has ended'; + this.exitCode = sysexits.NOINPUT; + } +} + +class ErrorRPCTimedOut extends ErrorRPC { + constructor(message?: string) { + super(message); + this.name = 'ErrorRPCTimedOut'; + this.description = 'RPC handler has timed out'; + this.exitCode = sysexits.UNAVAILABLE; + } +} + +class ErrorUtilsUndefinedBehaviour extends ErrorRPC { + constructor(message?: string) { + super(message); + this.name = 'ErrorUtilsUndefinedBehaviour'; + this.description = 'You should never see this error'; + this.exitCode = sysexits.SOFTWARE; + } +} +export function never(): never { + throw new ErrorRPC('This function should never be called'); +} + +export { + ErrorRPC, + ErrorRPCDestroyed, + ErrorRPCStopping, + ErrorRPCParse, + ErrorRPCHandlerFailed, + ErrorRPCMessageLength, + ErrorRPCMissingResponse, + ErrorRPCOutputStreamError, + ErrorRPCRemote, + ErrorRPCStreamEnded, + ErrorRPCTimedOut, + ErrorUtilsUndefinedBehaviour, +}; diff --git a/src/errors/index.ts b/src/errors/index.ts new file mode 100644 index 0000000..0df2a0a --- /dev/null +++ b/src/errors/index.ts @@ -0,0 +1,2 @@ +export * from './sysexits'; +export * from './errors'; diff --git a/src/errors/sysexits.ts b/src/errors/sysexits.ts new file mode 100644 index 0000000..935c181 --- /dev/null +++ b/src/errors/sysexits.ts @@ -0,0 +1,91 @@ +const sysexits = Object.freeze({ + OK: 0, + GENERAL: 1, + // Sysexit standard starts at 64 to avoid conflicts + /** + * The command was used incorrectly, e.g., with the wrong number of arguments, + * a bad flag, a bad syntax in a parameter, or whatever. + */ + USAGE: 64, + /** + * The input data was incorrect in some way. This should only be used for + * user's data and not system files. + */ + DATAERR: 65, + /** + * An input file (not a system file) did not exist or was not readable. + * This could also include errors like "No message" to a mailer + * (if it cared to catch it). + */ + NOINPUT: 66, + /** + * The user specified did not exist. This might be used for mail addresses + * or remote logins. + */ + NOUSER: 67, + /** + * The host specified did not exist. This is used in mail addresses or + * network requests. + */ + NOHOST: 68, + /** + * A service is unavailable. This can occur if a support program or file + * does not exist. This can also be used as a catchall message when + * something you wanted to do does not work, but you do not know why. + */ + UNAVAILABLE: 69, + /** + * An internal software error has been detected. This should be limited to + * non-operating system related errors as possible. + */ + SOFTWARE: 70, + /** + * An operating system error has been detected. This is intended to be used + * for such things as "cannot fork", "cannot create pipe", or the like. + * It in-cludes things like getuid returning a user that does not exist in + * the passwd file. + */ + OSERR: 71, + /** + * Some system file (e.g., /etc/passwd, /var/run/utx.active, etc.) + * does not exist, cannot be opened, or has some sort of error + * (e.g., syntax error). + */ + OSFILE: 72, + /** + * A (user specified) output file cannot be created. + */ + CANTCREAT: 73, + /** + * An error occurred while doing I/O on some file. + */ + IOERR: 74, + /** + * Temporary failure, indicating something that is not really an error. + * In sendmail, this means that a mailer (e.g.) could not create a connection, + * and the request should be reattempted later. + */ + TEMPFAIL: 75, + /** + * The remote system returned something that was "not possible" during a + * protocol exchange. + */ + PROTOCOL: 76, + /** + * You did not have sufficient permission to perform the operation. This is + * not intended for file system problems, which should use EX_NOINPUT or + * EX_CANTCREAT, but rather for higher level permissions. + */ + NOPERM: 77, + /** + * Something was found in an un-configured or mis-configured state. + */ + CONFIG: 78, + CANNOT_EXEC: 126, + COMMAND_NOT_FOUND: 127, + INVALID_EXIT_ARG: 128, + // 128+ are reserved for signal exits + UNKNOWN: 255, +}); + +export default sysexits; diff --git a/src/events.ts b/src/events.ts new file mode 100644 index 0000000..210d676 --- /dev/null +++ b/src/events.ts @@ -0,0 +1,13 @@ +class RPCErrorEvent extends Event { + public detail: Error; + constructor( + options: EventInit & { + detail: Error; + }, + ) { + super('error', options); + this.detail = options.detail; + } +} + +export { RPCErrorEvent }; diff --git a/src/handlers.ts b/src/handlers.ts new file mode 100644 index 0000000..aa3e7eb --- /dev/null +++ b/src/handlers.ts @@ -0,0 +1,99 @@ +import type { ReadableStream } from 'stream/web'; +import type { ContextTimed } from '@matrixai/contexts'; +import type { ContainerType, JSONRPCRequest } from './types'; +import type { JSONValue } from './types'; + +abstract class Handler< + Container extends ContainerType = ContainerType, + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> { + // These are used to distinguish the handlers in the type system. + // Without these the map types can't tell the types of handlers apart. + protected _inputType: Input; + protected _outputType: Output; + /** + * This is the timeout used for the handler. + * If it is not set then the default timeout time for the `RPCServer` is used. + */ + public timeout?: number; + + constructor(protected container: Container) {} +} + +abstract class RawHandler< + Container extends ContainerType = ContainerType, +> extends Handler { + abstract handle( + input: [JSONRPCRequest, ReadableStream], + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): Promise<[JSONValue, ReadableStream]>; +} + +abstract class DuplexHandler< + Container extends ContainerType = ContainerType, + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Handler { + /** + * Note that if the output has an error, the handler will not see this as an + * error. If you need to handle any clean up it should be handled in a + * `finally` block and check the abort signal for potential errors. + */ + abstract handle( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): AsyncIterableIterator; +} + +abstract class ServerHandler< + Container extends ContainerType = ContainerType, + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Handler { + abstract handle( + input: Input, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): AsyncIterableIterator; +} + +abstract class ClientHandler< + Container extends ContainerType = ContainerType, + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Handler { + abstract handle( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): Promise; +} + +abstract class UnaryHandler< + Container extends ContainerType = ContainerType, + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Handler { + abstract handle( + input: Input, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): Promise; +} + +export { + Handler, + RawHandler, + DuplexHandler, + ServerHandler, + ClientHandler, + UnaryHandler, +}; diff --git a/src/index.ts b/src/index.ts index e69de29..9961e29 100644 --- a/src/index.ts +++ b/src/index.ts @@ -0,0 +1,6 @@ +export { default as RPCClient } from './RPCClient'; +export { default as RPCServer } from './RPCServer'; +export * as utils from './utils'; +export * as types from './types'; +export * as errors from './errors/errors'; +export * as events from './events'; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..b563bba --- /dev/null +++ b/src/types.ts @@ -0,0 +1,363 @@ +import type { ReadableStream, ReadableWritablePair } from 'stream/web'; +import type { ContextTimed, ContextTimedInput } from '@matrixai/contexts'; +import type { Handler } from './handlers'; +import type { + Caller, + RawCaller, + DuplexCaller, + ServerCaller, + ClientCaller, + UnaryCaller, +} from './callers'; +import type { Id } from '@matrixai/id'; + +/** + * This is the JSON RPC request object. this is the generic message type used for the RPC. + */ +type JSONRPCRequestMessage = { + /** + * A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0" + */ + jsonrpc: '2.0'; + /** + * A String containing the name of the method to be invoked. Method names that begin with the word rpc followed by a + * period character (U+002E or ASCII 46) are reserved for rpc-internal methods and extensions and MUST NOT be used + * for anything else. + */ + method: string; + /** + * A Structured value that holds the parameter values to be used during the invocation of the method. + * This member MAY be omitted. + */ + params?: T; + /** + * An identifier established by the Client that MUST contain a String, Number, or NULL value if included. + * If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers + * SHOULD NOT contain fractional parts [2] + */ + id: string | number | null; +}; + +/** + * This is the JSON RPC notification object. this is used for a request that + * doesn't expect a response. + */ +type JSONRPCRequestNotification = { + /** + * A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0" + */ + jsonrpc: '2.0'; + /** + * A String containing the name of the method to be invoked. Method names that begin with the word rpc followed by a + * period character (U+002E or ASCII 46) are reserved for rpc-internal methods and extensions and MUST NOT be used + * for anything else. + */ + method: string; + /** + * A Structured value that holds the parameter values to be used during the invocation of the method. + * This member MAY be omitted. + */ + params?: T; +}; + +/** + * This is the JSON RPC response result object. It contains the response data for a + * corresponding request. + */ +type JSONRPCResponseResult = { + /** + * A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0". + */ + jsonrpc: '2.0'; + /** + * This member is REQUIRED on success. + * This member MUST NOT exist if there was an error invoking the method. + * The value of this member is determined by the method invoked on the Server. + */ + result: T; + /** + * This member is REQUIRED. + * It MUST be the same as the value of the id member in the Request Object. + * If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request), + * it MUST be Null. + */ + id: string | number | null; +}; + +/** + * This is the JSON RPC response Error object. It contains any errors that have + * occurred when responding to a request. + */ +type JSONRPCResponseError = { + /** + * A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0". + */ + jsonrpc: '2.0'; + /** + * This member is REQUIRED on error. + * This member MUST NOT exist if there was no error triggered during invocation. + * The value for this member MUST be an Object as defined in section 5.1. + */ + error: JSONRPCError; + /** + * This member is REQUIRED. + * It MUST be the same as the value of the id member in the Request Object. + * If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request), + * it MUST be Null. + */ + id: string | number | null; +}; + +/** + * This is a JSON RPC error object, it encodes the error data for the JSONRPCResponseError object. + */ +type JSONRPCError = { + /** + * A Number that indicates the error type that occurred. + * This MUST be an integer. + */ + code: number; + /** + * A String providing a short description of the error. + * The message SHOULD be limited to a concise single sentence. + */ + message: string; + /** + * A Primitive or Structured value that contains additional information about the error. + * This may be omitted. + * The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.). + */ + data?: JSONValue; +}; + +/** + * This is the JSON RPC Request object. It can be a request message or + * notification. + */ +type JSONRPCRequest = + | JSONRPCRequestMessage + | JSONRPCRequestNotification; + +/** + * This is a JSON RPC response object. It can be a response result or error. + */ +type JSONRPCResponse = + | JSONRPCResponseResult + | JSONRPCResponseError; + +/** + * This is a JSON RPC Message object. This is top level and can be any kind of + * message. + */ +type JSONRPCMessage = + | JSONRPCRequest + | JSONRPCResponse; + +// Handler types +type HandlerImplementation = ( + input: I, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, +) => O; + +type RawHandlerImplementation = HandlerImplementation< + [JSONRPCRequest, ReadableStream], + Promise<[JSONValue | undefined, ReadableStream]> +>; + +type DuplexHandlerImplementation< + I extends JSONValue = JSONValue, + O extends JSONValue = JSONValue, +> = HandlerImplementation, AsyncIterable>; + +type ServerHandlerImplementation< + I extends JSONValue = JSONValue, + O extends JSONValue = JSONValue, +> = HandlerImplementation>; + +type ClientHandlerImplementation< + I extends JSONValue = JSONValue, + O extends JSONValue = JSONValue, +> = HandlerImplementation, Promise>; + +type UnaryHandlerImplementation< + I extends JSONValue = JSONValue, + O extends JSONValue = JSONValue, +> = HandlerImplementation>; + +type ContainerType = Record; + +/** + * This interface extends the `ReadableWritablePair` with a method to cancel + * the connection. It also includes some optional generic metadata. This is + * mainly used as the return type for the `StreamFactory`. But the interface + * can be propagated across the RPC system. + */ +interface RPCStream< + R, + W, + M extends Record = Record, +> extends ReadableWritablePair { + cancel: (reason?: any) => void; + meta?: M; +} + +/** + * This is a factory for creating a `RPCStream` when making a RPC call. + * The transport mechanism is a black box to the RPC system. So long as it is + * provided as a RPCStream the RPC system should function. It is assumed that + * the RPCStream communicates with an `RPCServer`. + */ +type StreamFactory = ( + ctx: ContextTimed, +) => PromiseLike>; + +/** + * Middleware factory creates middlewares. + * Each middleware is a pair of forward and reverse. + * Each forward and reverse is a `ReadableWritablePair`. + * The forward pair is used transform input from client to server. + * The reverse pair is used to transform output from server to client. + * FR, FW is the readable and writable types of the forward pair. + * RR, RW is the readable and writable types of the reverse pair. + * FW -> FR is the direction of data flow from client to server. + * RW -> RR is the direction of data flow from server to client. + */ +type MiddlewareFactory = ( + ctx: ContextTimed, + cancel: (reason?: any) => void, + meta: Record | undefined, +) => { + forward: ReadableWritablePair; + reverse: ReadableWritablePair; +}; + +// Convenience callers + +type UnaryCallerImplementation< + I extends JSONValue = JSONValue, + O extends JSONValue = JSONValue, +> = (parameters: I, ctx?: Partial) => Promise; + +type ServerCallerImplementation< + I extends JSONValue = JSONValue, + O extends JSONValue = JSONValue, +> = ( + parameters: I, + ctx?: Partial, +) => Promise>; + +type ClientCallerImplementation< + I extends JSONValue = JSONValue, + O extends JSONValue = JSONValue, +> = ( + ctx?: Partial, +) => Promise<{ output: Promise; writable: WritableStream }>; + +type DuplexCallerImplementation< + I extends JSONValue = JSONValue, + O extends JSONValue = JSONValue, +> = (ctx?: Partial) => Promise>; + +type RawCallerImplementation = ( + headerParams: JSONValue, + ctx?: Partial, +) => Promise< + RPCStream< + Uint8Array, + Uint8Array, + Record & { result: JSONValue; command: string } + > +>; + +type ConvertDuplexCaller = T extends DuplexCaller + ? DuplexCallerImplementation + : never; + +type ConvertServerCaller = T extends ServerCaller + ? ServerCallerImplementation + : never; + +type ConvertClientCaller = T extends ClientCaller + ? ClientCallerImplementation + : never; + +type ConvertUnaryCaller = T extends UnaryCaller + ? UnaryCallerImplementation + : never; + +type ConvertCaller = T extends DuplexCaller + ? ConvertDuplexCaller + : T extends ServerCaller + ? ConvertServerCaller + : T extends ClientCaller + ? ConvertClientCaller + : T extends UnaryCaller + ? ConvertUnaryCaller + : T extends RawCaller + ? RawCallerImplementation + : never; + +/** + * Contains the handler Classes that defines the handling logic and types for the server handlers. + */ +type ServerManifest = Record; + +/** + * Contains the Caller classes that defines the types for the client callers. + */ +type ClientManifest = Record; + +type HandlerType = 'DUPLEX' | 'SERVER' | 'CLIENT' | 'UNARY' | 'RAW'; + +type MapCallers = { + [K in keyof T]: ConvertCaller; +}; + +declare const brand: unique symbol; + +type Opaque = T & { readonly [brand]: K }; + +type JSONValue = + | { [key: string]: JSONValue } + | Array + | string + | number + | boolean + | null; + +type POJO = { [key: string]: any }; +type PromiseDeconstructed = { + p: Promise; + resolveP: (value: T | PromiseLike) => void; + rejectP: (reason?: any) => void; +}; + +export type { + JSONRPCRequestMessage, + JSONRPCRequestNotification, + JSONRPCResponseResult, + JSONRPCResponseError, + JSONRPCError, + JSONRPCRequest, + JSONRPCResponse, + JSONRPCMessage, + HandlerImplementation, + RawHandlerImplementation, + DuplexHandlerImplementation, + ServerHandlerImplementation, + ClientHandlerImplementation, + UnaryHandlerImplementation, + ContainerType, + RPCStream, + StreamFactory, + MiddlewareFactory, + ServerManifest, + ClientManifest, + HandlerType, + MapCallers, + JSONValue, + POJO, + PromiseDeconstructed, +}; diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..d799db4 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,2 @@ +export * from './middleware'; +export * from './utils'; diff --git a/src/utils/middleware.ts b/src/utils/middleware.ts new file mode 100644 index 0000000..138e04d --- /dev/null +++ b/src/utils/middleware.ts @@ -0,0 +1,203 @@ +import type { + JSONRPCMessage, + JSONRPCRequest, + JSONRPCResponse, + JSONRPCResponseResult, + MiddlewareFactory, +} from '../types'; +import { TransformStream } from 'stream/web'; +import { JSONParser } from '@streamparser/json'; +import * as rpcUtils from './utils'; +import { promise } from './utils'; +import * as rpcErrors from '../errors/errors'; + +/** + * This function is a factory to create a TransformStream that will + * transform a `Uint8Array` stream to a JSONRPC message stream. + * The parsed messages will be validated with the provided messageParser, this + * also infers the type of the stream output. + * @param messageParser - Validates the JSONRPC messages, so you can select for a + * specific type of message + * @param bufferByteLimit - sets the number of bytes buffered before throwing an + * error. This is used to avoid infinitely buffering the input. + */ +function binaryToJsonMessageStream( + messageParser: (message: unknown) => T, + bufferByteLimit: number = 1024 * 1024, +): TransformStream { + const parser = new JSONParser({ + separator: '', + paths: ['$'], + }); + let bytesWritten: number = 0; + + return new TransformStream({ + flush: async () => { + // Avoid potential race conditions by allowing parser to end first + const waitP = promise(); + parser.onEnd = () => waitP.resolveP(); + parser.end(); + await waitP.p; + }, + start: (controller) => { + parser.onValue = (value) => { + const jsonMessage = messageParser(value.value); + controller.enqueue(jsonMessage); + bytesWritten = 0; + }; + }, + transform: (chunk) => { + try { + bytesWritten += chunk.byteLength; + parser.write(chunk); + } catch (e) { + throw new rpcErrors.ErrorRPCParse(undefined, { cause: e }); + } + if (bytesWritten > bufferByteLimit) { + throw new rpcErrors.ErrorRPCMessageLength(); + } + }, + }); +} + +/** + * This function is a factory for a TransformStream that will transform + * JsonRPCMessages into the `Uint8Array` form. This is used for the stream + * output. + */ +function jsonMessageToBinaryStream(): TransformStream< + JSONRPCMessage, + Uint8Array +> { + return new TransformStream({ + transform: (chunk, controller) => { + controller.enqueue(Buffer.from(JSON.stringify(chunk))); + }, + }); +} + +/** + * This function is a factory for creating a pass-through streamPair. It is used + * as the default middleware for the middleware wrappers. + */ +function defaultMiddleware() { + return { + forward: new TransformStream(), + reverse: new TransformStream(), + }; +} + +/** + * This convenience factory for creating wrapping middleware with the basic + * message processing and parsing for the server middleware. + * In the forward path, it will transform the binary stream into the validated + * JsonRPCMessages and pipe it through the provided middleware. + * The reverse path will pipe the output stream through the provided middleware + * and then transform it back to a binary stream. + * @param middlewareFactory - The provided middleware + * @param parserBufferByteLimit + */ +function defaultServerMiddlewareWrapper( + middlewareFactory: MiddlewareFactory< + JSONRPCRequest, + JSONRPCRequest, + JSONRPCResponse, + JSONRPCResponse + > = defaultMiddleware, + parserBufferByteLimit: number = 1024 * 1024, +): MiddlewareFactory { + return (ctx, cancel, meta) => { + const inputTransformStream = binaryToJsonMessageStream( + rpcUtils.parseJSONRPCRequest, + parserBufferByteLimit, + ); + const outputTransformStream = new TransformStream< + JSONRPCResponseResult, + JSONRPCResponseResult + >(); + + const middleMiddleware = middlewareFactory(ctx, cancel, meta); + + const forwardReadable = inputTransformStream.readable.pipeThrough( + middleMiddleware.forward, + ); // Usual middleware here + const reverseReadable = outputTransformStream.readable + .pipeThrough(middleMiddleware.reverse) // Usual middleware here + .pipeThrough(jsonMessageToBinaryStream()); + + return { + forward: { + readable: forwardReadable, + writable: inputTransformStream.writable, + }, + reverse: { + readable: reverseReadable, + writable: outputTransformStream.writable, + }, + }; + }; +} + +/** + * This convenience factory for creating wrapping middleware with the basic + * message processing and parsing for the server middleware. + * The forward path will pipe the input through the provided middleware and then + * transform it to the binary stream. + * The reverse path will parse and validate the output and pipe it through the + * provided middleware. + * @param middleware - the provided middleware + * @param parserBufferByteLimit - Max number of bytes to buffer when parsing the stream. Exceeding this results in an + * `ErrorRPCMessageLength` error. + */ +const defaultClientMiddlewareWrapper = ( + middleware: MiddlewareFactory< + JSONRPCRequest, + JSONRPCRequest, + JSONRPCResponse, + JSONRPCResponse + > = defaultMiddleware, + parserBufferByteLimit?: number, +): MiddlewareFactory< + Uint8Array, + JSONRPCRequest, + JSONRPCResponse, + Uint8Array +> => { + return (ctx, cancel, meta) => { + const outputTransformStream = binaryToJsonMessageStream( + rpcUtils.parseJSONRPCResponse, + parserBufferByteLimit, + ); + const inputTransformStream = new TransformStream< + JSONRPCRequest, + JSONRPCRequest + >(); + + const middleMiddleware = middleware(ctx, cancel, meta); + const forwardReadable = inputTransformStream.readable + .pipeThrough(middleMiddleware.forward) // Usual middleware here + .pipeThrough(jsonMessageToBinaryStream()); + const reverseReadable = outputTransformStream.readable.pipeThrough( + middleMiddleware.reverse, + ); // Usual middleware here + + return { + forward: { + readable: forwardReadable, + writable: inputTransformStream.writable, + }, + reverse: { + readable: reverseReadable, + writable: outputTransformStream.writable, + }, + }; + }; +}; + +export { + binaryToJsonMessageStream, + jsonMessageToBinaryStream, + defaultMiddleware, + defaultServerMiddlewareWrapper, + defaultClientMiddlewareWrapper, +}; diff --git a/src/utils/utils.ts b/src/utils/utils.ts new file mode 100644 index 0000000..4aafdd4 --- /dev/null +++ b/src/utils/utils.ts @@ -0,0 +1,523 @@ +import type { + ClientManifest, + HandlerType, + JSONRPCError, + JSONRPCMessage, + JSONRPCRequest, + JSONRPCRequestMessage, + JSONRPCRequestNotification, + JSONRPCResponse, + JSONRPCResponseError, + JSONRPCResponseResult, + PromiseDeconstructed, +} from '../types'; +import type { JSONValue } from '../types'; +import type { Timer } from '@matrixai/timer'; +import { TransformStream } from 'stream/web'; +import { JSONParser } from '@streamparser/json'; +import { AbstractError } from '@matrixai/errors'; +import * as rpcErrors from '../errors/errors'; +import * as errors from '../errors/errors'; +import { ErrorRPCRemote } from '../errors/errors'; +import { ErrorRPC } from '../errors/errors'; + +// Importing PK funcs and utils which are essential for RPC +function isObject(o: unknown): o is object { + return o !== null && typeof o === 'object'; +} +function promise(): PromiseDeconstructed { + let resolveP, rejectP; + const p = new Promise((resolve, reject) => { + resolveP = resolve; + rejectP = reject; + }); + return { + p, + resolveP, + rejectP, + }; +} + +async function sleep(ms: number): Promise { + return await new Promise((r) => setTimeout(r, ms)); +} + +function parseJSONRPCRequest( + message: unknown, +): JSONRPCRequest { + if (!isObject(message)) { + throw new rpcErrors.ErrorRPCParse('must be a JSON POJO'); + } + if (!('method' in message)) { + throw new rpcErrors.ErrorRPCParse('`method` property must be defined'); + } + if (typeof message.method !== 'string') { + throw new rpcErrors.ErrorRPCParse('`method` property must be a string'); + } + // If ('params' in message && !utils.isObject(message.params)) { + // throw new rpcErrors.ErrorRPCParse('`params` property must be a POJO'); + // } + return message as JSONRPCRequest; +} + +function parseJSONRPCRequestMessage( + message: unknown, +): JSONRPCRequestMessage { + const jsonRequest = parseJSONRPCRequest(message); + if (!('id' in jsonRequest)) { + throw new rpcErrors.ErrorRPCParse('`id` property must be defined'); + } + if ( + typeof jsonRequest.id !== 'string' && + typeof jsonRequest.id !== 'number' && + jsonRequest.id !== null + ) { + throw new rpcErrors.ErrorRPCParse( + '`id` property must be a string, number or null', + ); + } + return jsonRequest as JSONRPCRequestMessage; +} + +function parseJSONRPCRequestNotification( + message: unknown, +): JSONRPCRequestNotification { + const jsonRequest = parseJSONRPCRequest(message); + if ('id' in jsonRequest) { + throw new rpcErrors.ErrorRPCParse('`id` property must not be defined'); + } + return jsonRequest as JSONRPCRequestNotification; +} + +function parseJSONRPCResponseResult( + message: unknown, +): JSONRPCResponseResult { + if (!isObject(message)) { + throw new rpcErrors.ErrorRPCParse('must be a JSON POJO'); + } + if (!('result' in message)) { + throw new rpcErrors.ErrorRPCParse('`result` property must be defined'); + } + if ('error' in message) { + throw new rpcErrors.ErrorRPCParse('`error` property must not be defined'); + } + // If (!utils.isObject(message.result)) { + // throw new rpcErrors.ErrorRPCParse('`result` property must be a POJO'); + // } + if (!('id' in message)) { + throw new rpcErrors.ErrorRPCParse('`id` property must be defined'); + } + if ( + typeof message.id !== 'string' && + typeof message.id !== 'number' && + message.id !== null + ) { + throw new rpcErrors.ErrorRPCParse( + '`id` property must be a string, number or null', + ); + } + return message as JSONRPCResponseResult; +} + +function parseJSONRPCResponseError(message: unknown): JSONRPCResponseError { + if (!isObject(message)) { + throw new rpcErrors.ErrorRPCParse('must be a JSON POJO'); + } + if ('result' in message) { + throw new rpcErrors.ErrorRPCParse('`result` property must not be defined'); + } + if (!('error' in message)) { + throw new rpcErrors.ErrorRPCParse('`error` property must be defined'); + } + parseJSONRPCError(message.error); + if (!('id' in message)) { + throw new rpcErrors.ErrorRPCParse('`id` property must be defined'); + } + if ( + typeof message.id !== 'string' && + typeof message.id !== 'number' && + message.id !== null + ) { + throw new rpcErrors.ErrorRPCParse( + '`id` property must be a string, number or null', + ); + } + return message as JSONRPCResponseError; +} + +function parseJSONRPCError(message: unknown): JSONRPCError { + if (!isObject(message)) { + throw new rpcErrors.ErrorRPCParse('must be a JSON POJO'); + } + if (!('code' in message)) { + throw new rpcErrors.ErrorRPCParse('`code` property must be defined'); + } + if (typeof message.code !== 'number') { + throw new rpcErrors.ErrorRPCParse('`code` property must be a number'); + } + if (!('message' in message)) { + throw new rpcErrors.ErrorRPCParse('`message` property must be defined'); + } + if (typeof message.message !== 'string') { + throw new rpcErrors.ErrorRPCParse('`message` property must be a string'); + } + // If ('data' in message && !utils.isObject(message.data)) { + // throw new rpcErrors.ErrorRPCParse('`data` property must be a POJO'); + // } + return message as JSONRPCError; +} + +function parseJSONRPCResponse( + message: unknown, +): JSONRPCResponse { + if (!isObject(message)) { + throw new rpcErrors.ErrorRPCParse('must be a JSON POJO'); + } + try { + return parseJSONRPCResponseResult(message); + } catch (e) { + // Do nothing + } + try { + return parseJSONRPCResponseError(message); + } catch (e) { + // Do nothing + } + throw new rpcErrors.ErrorRPCParse( + 'structure did not match a `JSONRPCResponse`', + ); +} + +function parseJSONRPCMessage( + message: unknown, +): JSONRPCMessage { + if (!isObject(message)) { + throw new rpcErrors.ErrorRPCParse('must be a JSON POJO'); + } + if (!('jsonrpc' in message)) { + throw new rpcErrors.ErrorRPCParse('`jsonrpc` property must be defined'); + } + if (message.jsonrpc !== '2.0') { + throw new rpcErrors.ErrorRPCParse( + '`jsonrpc` property must be a string of "2.0"', + ); + } + try { + return parseJSONRPCRequest(message); + } catch { + // Do nothing + } + try { + return parseJSONRPCResponse(message); + } catch { + // Do nothing + } + throw new rpcErrors.ErrorRPCParse( + 'Message structure did not match a `JSONRPCMessage`', + ); +} + +/** + * Replacer function for serialising errors over RPC (used by `JSON.stringify` + * in `fromError`) + * Polykey errors are handled by their inbuilt `toJSON` method , so this only + * serialises other errors + */ +function replacer(key: string, value: any): any { + if (value instanceof AggregateError) { + // AggregateError has an `errors` property + return { + type: value.constructor.name, + data: { + errors: value.errors, + message: value.message, + stack: value.stack, + }, + }; + } else if (value instanceof Error) { + // If it's some other type of error then only serialise the message and + // stack (and the type of the error) + return { + type: value.name, + data: { + message: value.message, + stack: value.stack, + }, + }; + } else { + // If it's not an error then just leave as is + return value; + } +} + +/** + * The same as `replacer`, however this will additionally filter out any + * sensitive data that should not be sent over the network when sending to an + * agent (as opposed to a client) + */ +function sensitiveReplacer(key: string, value: any) { + if (key === 'stack') { + return; + } else { + return replacer(key, value); + } +} + +/** + * Serializes Error instances into RPC errors + * Use this on the sending side to send exceptions + * Do not send exceptions to clients you do not trust + * If sending to an agent (rather than a client), set sensitive to true to + * prevent sensitive information from being sent over the network + */ +function fromError(error: Error, sensitive: boolean = false) { + if (sensitive) { + return JSON.stringify(error, sensitiveReplacer); + } else { + return JSON.stringify(error, replacer); + } +} + +/** + * Error constructors for non-Polykey errors + * Allows these errors to be reconstructed from RPC metadata + */ +const standardErrors = { + Error, + TypeError, + SyntaxError, + ReferenceError, + EvalError, + RangeError, + URIError, + AggregateError, + AbstractError, +}; + +/** + * Reviver function for deserialising errors sent over RPC (used by + * `JSON.parse` in `toError`) + * The final result returned will always be an error - if the deserialised + * data is of an unknown type then this will be wrapped as an + * `ErrorPolykeyUnknown` + */ +function reviver(key: string, value: any): any { + // If the value is an error then reconstruct it + if ( + typeof value === 'object' && + typeof value.type === 'string' && + typeof value.data === 'object' + ) { + try { + let eClass = errors[value.type]; + if (eClass != null) return eClass.fromJSON(value); + eClass = standardErrors[value.type]; + if (eClass != null) { + let e; + switch (eClass) { + case AbstractError: + return eClass.fromJSON(); + case AggregateError: + if ( + !Array.isArray(value.data.errors) || + typeof value.data.message !== 'string' || + ('stack' in value.data && typeof value.data.stack !== 'string') + ) { + throw new TypeError(`cannot decode JSON to ${value.type}`); + } + e = new eClass(value.data.errors, value.data.message); + e.stack = value.data.stack; + break; + default: + if ( + typeof value.data.message !== 'string' || + ('stack' in value.data && typeof value.data.stack !== 'string') + ) { + throw new TypeError(`Cannot decode JSON to ${value.type}`); + } + e = new eClass(value.data.message); + e.stack = value.data.stack; + break; + } + return e; + } + } catch (e) { + // If `TypeError` which represents decoding failure + // then return value as-is + // Any other exception is a bug + if (!(e instanceof TypeError)) { + throw e; + } + } + // Other values are returned as-is + return value; + } else if (key === '') { + // Root key will be '' + // Reaching here means the root JSON value is not a valid exception + // Therefore ErrorPolykeyUnknown is only ever returned at the top-level + return new rpcErrors.ErrorRPC('Unknown error JSON'); + } else { + return value; + } +} + +function toError(errorData, metadata?: JSONValue): ErrorRPCRemote { + if (errorData == null) { + return new ErrorRPCRemote(metadata); + } + const error: Error = JSON.parse(errorData, reviver); + const remoteError = new ErrorRPCRemote(metadata, error.message, { + cause: error, + }); + if (error instanceof ErrorRPC) { + remoteError.exitCode = error.exitCode as number; + } + return remoteError; +} + +/** + * This constructs a transformation stream that converts any input into a + * JSONRCPRequest message. It also refreshes a timer each time a message is processed if + * one is provided. + * @param method - Name of the method that was called, used to select the + * server side. + * @param timer - Timer that gets refreshed each time a message is provided. + */ +function clientInputTransformStream( + method: string, + timer?: Timer, +): TransformStream { + return new TransformStream({ + transform: (chunk, controller) => { + timer?.refresh(); + const message: JSONRPCRequest = { + method, + jsonrpc: '2.0', + id: null, + params: chunk, + }; + controller.enqueue(message); + }, + }); +} + +/** + * This constructs a transformation stream that converts any error messages + * into errors. It also refreshes a timer each time a message is processed if + * one is provided. + * @param clientMetadata - Metadata that is attached to an error when one is + * created. + * @param timer - Timer that gets refreshed each time a message is provided. + */ +function clientOutputTransformStream( + clientMetadata?: JSONValue, + timer?: Timer, +): TransformStream, O> { + return new TransformStream, O>({ + transform: (chunk, controller) => { + timer?.refresh(); + // `error` indicates it's an error message + if ('error' in chunk) { + throw toError(chunk.error.data, clientMetadata); + } + controller.enqueue(chunk.result); + }, + }); +} + +function getHandlerTypes( + manifest: ClientManifest, +): Record { + const out: Record = {}; + for (const [k, v] of Object.entries(manifest)) { + out[k] = v.type; + } + return out; +} + +/** + * This function is a factory to create a TransformStream that will + * transform a `Uint8Array` stream to a JSONRPC message stream. + * The parsed messages will be validated with the provided messageParser, this + * also infers the type of the stream output. + * @param messageParser - Validates the JSONRPC messages, so you can select for a + * specific type of message + * @param bufferByteLimit - sets the number of bytes buffered before throwing an + * error. This is used to avoid infinitely buffering the input. + */ +function parseHeadStream( + messageParser: (message: unknown) => T, + bufferByteLimit: number = 1024 * 1024, +): TransformStream { + const parser = new JSONParser({ + separator: '', + paths: ['$'], + }); + let bytesWritten: number = 0; + let parsing = true; + let ended = false; + + const endP = promise(); + parser.onEnd = () => endP.resolveP(); + + return new TransformStream( + { + flush: async () => { + if (!parser.isEnded) parser.end(); + await endP.p; + }, + start: (controller) => { + parser.onValue = async (value) => { + const jsonMessage = messageParser(value.value); + controller.enqueue(jsonMessage); + bytesWritten = 0; + parsing = false; + }; + }, + transform: async (chunk, controller) => { + if (parsing) { + try { + bytesWritten += chunk.byteLength; + parser.write(chunk); + } catch (e) { + throw new rpcErrors.ErrorRPCParse(undefined, { + cause: e, + }); + } + if (bytesWritten > bufferByteLimit) { + throw new rpcErrors.ErrorRPCMessageLength(); + } + } else { + // Wait for parser to end + if (!ended) { + parser.end(); + await endP.p; + ended = true; + } + // Pass through normal chunks + controller.enqueue(chunk); + } + }, + }, + { highWaterMark: 1 }, + ); +} + +export { + parseJSONRPCRequest, + parseJSONRPCRequestMessage, + parseJSONRPCRequestNotification, + parseJSONRPCResponseResult, + parseJSONRPCResponseError, + parseJSONRPCResponse, + parseJSONRPCMessage, + fromError, + toError, + clientInputTransformStream, + clientOutputTransformStream, + getHandlerTypes, + parseHeadStream, + promise, + isObject, + sleep, +}; diff --git a/tests/index.test.ts b/tests/index.test.ts deleted file mode 100644 index d48a1eb..0000000 --- a/tests/index.test.ts +++ /dev/null @@ -1 +0,0 @@ -describe('index', () => {}); diff --git a/tests/rpc/RPC.test.ts b/tests/rpc/RPC.test.ts new file mode 100644 index 0000000..df37bce --- /dev/null +++ b/tests/rpc/RPC.test.ts @@ -0,0 +1,555 @@ +import type { ContainerType, JSONRPCRequest } from '../../src/types'; +import type { ReadableStream } from 'stream/web'; +import type { JSONValue } from '../../src/types'; +import { TransformStream } from 'stream/web'; +import { fc, testProp } from '@fast-check/jest'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import * as rpcTestUtils from './utils'; +import * as utils from '../../src/utils'; +import RPCServer from '../../src/RPCServer'; +import RPCClient from '../../src/RPCClient'; +import { + ClientHandler, + DuplexHandler, + RawHandler, + ServerHandler, + UnaryHandler, +} from '../../src/handlers'; +import { + ClientCaller, + DuplexCaller, + RawCaller, + ServerCaller, + UnaryCaller, +} from '../../src/callers'; +import * as rpcErrors from '../../src/errors'; +import { ErrorRPC } from '../../src/errors'; +import * as rpcUtilsMiddleware from '../../src/utils/middleware'; + +describe('RPC', () => { + const logger = new Logger(`RPC Test`, LogLevel.WARN, [new StreamHandler()]); + + testProp( + 'RPC communication with raw stream', + [rpcTestUtils.rawDataArb], + async (inputData) => { + const [outputResult, outputWriterStream] = + rpcTestUtils.streamToArray(); + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + let header: JSONRPCRequest | undefined; + + class TestMethod extends RawHandler { + public async handle( + input: [JSONRPCRequest, ReadableStream], + _cancel: (reason?: any) => void, + _meta: Record | undefined, + ): Promise<[JSONValue, ReadableStream]> { + return new Promise((resolve) => { + const [header_, stream] = input; + header = header_; + resolve(['some leading data', stream]); + }); + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new RawCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + }); + + const callerInterface = await rpcClient.methods.testMethod({ + hello: 'world', + }); + const writer = callerInterface.writable.getWriter(); + const pipeProm = callerInterface.readable.pipeTo(outputWriterStream); + for (const value of inputData) { + await writer.write(value); + } + await writer.close(); + const expectedHeader: JSONRPCRequest = { + jsonrpc: '2.0', + method: 'testMethod', + params: { hello: 'world' }, + id: null, + }; + expect(header).toStrictEqual(expectedHeader); + expect(callerInterface.meta?.result).toBe('some leading data'); + expect(await outputResult).toStrictEqual(inputData); + await pipeProm; + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + test('RPC communication with raw stream times out waiting for leading message', async () => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + void (async () => { + for await (const _ of serverPair.readable) { + // Just consume + } + })(); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new RawCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + }); + + await expect( + rpcClient.methods.testMethod( + { + hello: 'world', + }, + { timer: 100 }, + ), + ).rejects.toThrow(rpcErrors.ErrorRPCTimedOut); + await rpcClient.destroy(); + }); + test('RPC communication with raw stream, raw handler throws', async () => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends RawHandler { + public async handle(): Promise< + [JSONRPCRequest, ReadableStream] + > { + throw Error('some error'); + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new RawCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + }); + + await expect( + rpcClient.methods.testMethod({ + hello: 'world', + }), + ).rejects.toThrow(rpcErrors.ErrorRPCRemote); + + await rpcServer.destroy(); + await rpcClient.destroy(); + }); + testProp( + 'RPC communication with duplex stream', + [fc.array(rpcTestUtils.safeJsonValueArb, { minLength: 1 })], + async (values) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + class TestMethod extends DuplexHandler { + public async *handle( + input: AsyncGenerator, + ): AsyncGenerator { + yield* input; + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new DuplexCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + }); + + const callerInterface = await rpcClient.methods.testMethod(); + const writer = callerInterface.writable.getWriter(); + const reader = callerInterface.readable.getReader(); + for (const value of values) { + await writer.write(value); + expect((await reader.read()).value).toStrictEqual(value); + } + await writer.close(); + const result = await reader.read(); + expect(result.value).toBeUndefined(); + expect(result.done).toBeTrue(); + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + testProp( + 'RPC communication with server stream', + [fc.integer({ min: 1, max: 100 })], + async (value) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends ServerHandler { + public async *handle(input: number): AsyncGenerator { + for (let i = 0; i < input; i++) { + yield i; + } + } + } + + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new ServerCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + }); + + const callerInterface = await rpcClient.methods.testMethod(value); + + const outputs: Array = []; + for await (const num of callerInterface) { + outputs.push(num); + } + expect(outputs.length).toEqual(value); + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + testProp( + 'RPC communication with client stream', + [fc.array(fc.integer(), { minLength: 1 }).noShrink()], + async (values) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends ClientHandler { + public async handle(input: AsyncIterable): Promise { + let acc = 0; + for await (const number of input) { + acc += number; + } + return acc; + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new ClientCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + }); + + const { output, writable } = await rpcClient.methods.testMethod(); + const writer = writable.getWriter(); + for (const value of values) { + await writer.write(value); + } + await writer.close(); + const expectedResult = values.reduce((p, c) => p + c); + await expect(output).resolves.toEqual(expectedResult); + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + testProp( + 'RPC communication with unary call', + [rpcTestUtils.safeJsonValueArb], + async (value) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends UnaryHandler { + public async handle(input: JSONValue): Promise { + return input; + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new UnaryCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + }); + + const result = await rpcClient.methods.testMethod(value); + expect(result).toStrictEqual(value); + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + testProp( + 'RPC handles and sends errors', + [ + rpcTestUtils.safeJsonValueArb, + rpcTestUtils.errorArb(rpcTestUtils.errorArb()), + ], + async (value, error) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends UnaryHandler { + public async handle(): Promise { + throw error; + } + } + + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + rpcServer.handleStream({ ...serverPair, cancel: () => {} }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new UnaryCaller(), + }, + streamFactory: async () => { + return { ...clientPair, cancel: () => {} }; + }, + logger, + }); + + // Create a new promise so we can await it multiple times for assertions + const callProm = rpcClient.methods.testMethod(value).catch((e) => e); + + // The promise should be rejected + const rejection = await callProm; + expect(rejection).toBeInstanceOf(rpcErrors.ErrorRPCRemote); + + // The error should have specific properties + expect(rejection).toMatchObject({ exitCode: 69 }); + + // Cleanup + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + + testProp( + 'RPC handles and sends sensitive errors', + [ + rpcTestUtils.safeJsonValueArb, + rpcTestUtils.errorArb(rpcTestUtils.errorArb()), + ], + async (value, error) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends UnaryHandler { + public async handle(): Promise { + throw error; + } + } + + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + sensitive: true, + logger, + }); + rpcServer.handleStream({ ...serverPair, cancel: () => {} }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new UnaryCaller(), + }, + streamFactory: async () => { + return { ...clientPair, cancel: () => {} }; + }, + logger, + }); + + const callProm = rpcClient.methods.testMethod(value); + + // Use Jest's `.rejects` to handle the promise rejection + await expect(callProm).rejects.toBeInstanceOf(rpcErrors.ErrorRPCRemote); + await expect(callProm).rejects.toHaveProperty('cause', error); + await expect(callProm).rejects.not.toHaveProperty('cause.stack'); + + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + + test('middleware can end stream early', async () => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + class TestMethod extends DuplexHandler { + public async *handle( + input: AsyncIterableIterator, + ): AsyncIterableIterator { + yield* input; + } + } + const middleware = rpcUtilsMiddleware.defaultServerMiddlewareWrapper(() => { + return { + forward: new TransformStream({ + start: (controller) => { + // Controller.terminate(); + controller.error(Error('SOME ERROR')); + }, + }), + reverse: new TransformStream({ + start: (controller) => { + controller.error(Error('SOME ERROR')); + }, + }), + }; + }); + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + middlewareFactory: middleware, + logger, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new DuplexCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + }); + + const callerInterface = await rpcClient.methods.testMethod(); + const writer = callerInterface.writable.getWriter(); + await writer.write({}); + // Allow time to process buffer + await utils.sleep(0); + await expect(writer.write({})).toReject(); + const reader = callerInterface.readable.getReader(); + await expect(reader.read()).toReject(); + await expect(writer.closed).toReject(); + await expect(reader.closed).toReject(); + await expect(rpcServer.destroy(false)).toResolve(); + await rpcClient.destroy(); + }); +}); diff --git a/tests/rpc/RPCClient.test.ts b/tests/rpc/RPCClient.test.ts new file mode 100644 index 0000000..589cd2c --- /dev/null +++ b/tests/rpc/RPCClient.test.ts @@ -0,0 +1,1172 @@ +import type { ContextTimed } from '@matrixai/contexts'; +import type { JSONValue } from '../../src/types'; +import type { + JSONRPCRequest, + JSONRPCRequestMessage, + JSONRPCResponse, + JSONRPCResponseResult, + RPCStream, +} from '../../src/types'; +import { TransformStream, ReadableStream } from 'stream/web'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { testProp, fc } from '@fast-check/jest'; +import * as rpcTestUtils from './utils'; +import RPCClient from '../../src/RPCClient'; +import RPCServer from '../../src/RPCServer'; +import * as rpcErrors from '../../src/errors'; +import { + ClientCaller, + DuplexCaller, + RawCaller, + ServerCaller, + UnaryCaller, +} from '../../src/callers'; +import * as rpcUtilsMiddleware from '../../src/utils/middleware'; +import { promise, sleep } from '../../src/utils'; +import { ErrorRPCRemote } from '../../src/errors'; + +describe(`${RPCClient.name}`, () => { + const logger = new Logger(`${RPCServer.name} Test`, LogLevel.WARN, [ + new StreamHandler(), + ]); + + const methodName = 'testMethod'; + const specificMessageArb = fc + .array(rpcTestUtils.jsonRpcResponseResultArb(), { + minLength: 5, + }) + .noShrink(); + + testProp( + 'raw caller', + [ + rpcTestUtils.safeJsonValueArb, + rpcTestUtils.rawDataArb, + rpcTestUtils.rawDataArb, + ], + async (headerParams, inputData, outputData) => { + const [inputResult, inputWritableStream] = + rpcTestUtils.streamToArray(); + const [outputResult, outputWritableStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: new ReadableStream({ + start: (controller) => { + const leadingResponse: JSONRPCResponseResult = { + jsonrpc: '2.0', + result: null, + id: null, + }; + controller.enqueue(Buffer.from(JSON.stringify(leadingResponse))); + for (const datum of outputData) { + controller.enqueue(datum); + } + controller.close(); + }, + }), + writable: inputWritableStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async () => streamPair, + logger, + }); + const callerInterface = await rpcClient.rawStreamCaller( + 'testMethod', + headerParams, + ); + await callerInterface.readable.pipeTo(outputWritableStream); + const writer = callerInterface.writable.getWriter(); + for (const inputDatum of inputData) { + await writer.write(inputDatum); + } + await writer.close(); + + const expectedHeader: JSONRPCRequest = { + jsonrpc: '2.0', + method: methodName, + params: headerParams, + id: null, + }; + expect(await inputResult).toStrictEqual([ + Buffer.from(JSON.stringify(expectedHeader)), + ...inputData, + ]); + expect(await outputResult).toStrictEqual(outputData); + }, + ); + testProp('generic duplex caller', [specificMessageArb], async (messages) => { + const inputStream = rpcTestUtils.messagesToReadableStream(messages); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async () => streamPair, + logger, + }); + const callerInterface = await rpcClient.duplexStreamCaller< + JSONValue, + JSONValue + >(methodName); + const writable = callerInterface.writable.getWriter(); + for await (const value of callerInterface.readable) { + await writable.write(value); + } + await writable.close(); + + const expectedMessages: Array = messages.map((v) => { + const request: JSONRPCRequestMessage = { + jsonrpc: '2.0', + method: methodName, + id: null, + ...(v.result === undefined ? {} : { params: v.result }), + }; + return request; + }); + const outputMessages = (await outputResult).map((v) => + JSON.parse(v.toString()), + ); + expect(outputMessages).toStrictEqual(expectedMessages); + await rpcClient.destroy(); + }); + testProp( + 'generic server stream caller', + [specificMessageArb, rpcTestUtils.safeJsonValueArb], + async (messages, params) => { + const inputStream = rpcTestUtils.messagesToReadableStream(messages); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async () => streamPair, + logger, + }); + const callerInterface = await rpcClient.serverStreamCaller< + JSONValue, + JSONValue + >(methodName, params as JSONValue); + const values: Array = []; + for await (const value of callerInterface) { + values.push(value); + } + const expectedValues = messages.map((v) => v.result); + expect(values).toStrictEqual(expectedValues); + expect((await outputResult)[0]?.toString()).toStrictEqual( + JSON.stringify({ + method: methodName, + jsonrpc: '2.0', + id: null, + params, + }), + ); + await rpcClient.destroy(); + }, + ); + testProp( + 'generic client stream caller', + [ + rpcTestUtils.jsonRpcResponseResultArb(), + fc.array(rpcTestUtils.safeJsonValueArb), + ], + async (message, params) => { + const inputStream = rpcTestUtils.messagesToReadableStream([message]); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async () => streamPair, + logger, + }); + const { output, writable } = await rpcClient.clientStreamCaller< + JSONValue, + JSONValue + >(methodName); + const writer = writable.getWriter(); + for (const param of params) { + await writer.write(param); + } + await writer.close(); + expect(await output).toStrictEqual(message.result); + const expectedOutput = params.map((v) => + JSON.stringify({ + method: methodName, + jsonrpc: '2.0', + id: null, + params: v, + }), + ); + expect((await outputResult).map((v) => v.toString())).toStrictEqual( + expectedOutput, + ); + await rpcClient.destroy(); + }, + ); + testProp( + 'generic unary caller', + [rpcTestUtils.jsonRpcResponseResultArb(), rpcTestUtils.safeJsonValueArb], + async (message, params) => { + const inputStream = rpcTestUtils.messagesToReadableStream([message]); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async () => streamPair, + logger, + }); + const result = await rpcClient.unaryCaller( + methodName, + params as JSONValue, + ); + expect(result).toStrictEqual(message.result); + expect((await outputResult)[0]?.toString()).toStrictEqual( + JSON.stringify({ + method: methodName, + jsonrpc: '2.0', + id: null, + params: params, + }), + ); + await rpcClient.destroy(); + }, + ); + testProp( + 'generic duplex caller can throw received error message', + [ + fc.array(rpcTestUtils.jsonRpcResponseResultArb()), + rpcTestUtils.jsonRpcResponseErrorArb(rpcTestUtils.errorArb()), + ], + async (messages, errorMessage) => { + const inputStream = rpcTestUtils.messagesToReadableStream([ + ...messages, + errorMessage, + ]); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async () => streamPair, + logger, + }); + const callerInterface = await rpcClient.duplexStreamCaller< + JSONValue, + JSONValue + >(methodName); + await callerInterface.writable.close(); + const callProm = (async () => { + for await (const _ of callerInterface.readable) { + // Only consume + } + })(); + await expect(callProm).rejects.toThrow(rpcErrors.ErrorRPCRemote); + await outputResult; + await rpcClient.destroy(); + }, + ); + testProp( + 'generic duplex caller can throw received error message with sensitive', + [ + fc.array(rpcTestUtils.jsonRpcResponseResultArb()), + rpcTestUtils.jsonRpcResponseErrorArb(rpcTestUtils.errorArb(), true), + ], + async (messages, errorMessage) => { + const inputStream = rpcTestUtils.messagesToReadableStream([ + ...messages, + errorMessage, + ]); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async () => streamPair, + logger, + }); + const callerInterface = await rpcClient.duplexStreamCaller< + JSONValue, + JSONValue + >(methodName); + await callerInterface.writable.close(); + const callProm = (async () => { + for await (const _ of callerInterface.readable) { + // Only consume + } + })(); + await expect(callProm).rejects.toThrow(rpcErrors.ErrorRPCRemote); + await outputResult; + await rpcClient.destroy(); + }, + ); + testProp( + 'generic duplex caller can throw received error message with causes', + [ + fc.array(rpcTestUtils.jsonRpcResponseResultArb()), + rpcTestUtils.jsonRpcResponseErrorArb( + rpcTestUtils.errorArb(rpcTestUtils.errorArb()), + true, + ), + ], + async (messages, errorMessage) => { + const inputStream = rpcTestUtils.messagesToReadableStream([ + ...messages, + errorMessage, + ]); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async () => streamPair, + logger, + }); + const callerInterface = await rpcClient.duplexStreamCaller< + JSONValue, + JSONValue + >(methodName); + await callerInterface.writable.close(); + const callProm = (async () => { + for await (const _ of callerInterface.readable) { + // Only consume + } + })(); + await expect(callProm).rejects.toThrow(rpcErrors.ErrorRPCRemote); + await outputResult; + await rpcClient.destroy(); + }, + ); + testProp( + 'generic duplex caller with forward Middleware', + [specificMessageArb], + async (messages) => { + const inputStream = rpcTestUtils.messagesToReadableStream(messages); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async () => streamPair, + middlewareFactory: rpcUtilsMiddleware.defaultClientMiddlewareWrapper( + () => { + return { + forward: new TransformStream({ + transform: (chunk, controller) => { + controller.enqueue({ + ...chunk, + params: 'one', + }); + }, + }), + reverse: new TransformStream(), + }; + }, + ), + logger, + }); + + const callerInterface = await rpcClient.duplexStreamCaller< + JSONValue, + JSONValue + >(methodName); + const reader = callerInterface.readable.getReader(); + const writer = callerInterface.writable.getWriter(); + while (true) { + const { value, done } = await reader.read(); + if (done) { + // We have to end the writer otherwise the stream never closes + await writer.close(); + break; + } + await writer.write(value); + } + + const expectedMessages: Array = messages.map( + () => { + const request: JSONRPCRequestMessage = { + jsonrpc: '2.0', + method: methodName, + id: null, + params: 'one', + }; + return request; + }, + ); + const outputMessages = (await outputResult).map((v) => + JSON.parse(v.toString()), + ); + expect(outputMessages).toStrictEqual(expectedMessages); + await rpcClient.destroy(); + }, + ); + testProp( + 'generic duplex caller with reverse Middleware', + [specificMessageArb], + async (messages) => { + const inputStream = rpcTestUtils.messagesToReadableStream(messages); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async () => streamPair, + middlewareFactory: rpcUtilsMiddleware.defaultClientMiddlewareWrapper( + () => { + return { + forward: new TransformStream(), + reverse: new TransformStream({ + transform: (chunk, controller) => { + controller.enqueue({ + ...chunk, + result: 'one', + }); + }, + }), + }; + }, + ), + logger, + }); + + const callerInterface = await rpcClient.duplexStreamCaller< + JSONValue, + JSONValue + >(methodName); + const reader = callerInterface.readable.getReader(); + const writer = callerInterface.writable.getWriter(); + while (true) { + const { value, done } = await reader.read(); + if (done) { + // We have to end the writer otherwise the stream never closes + await writer.close(); + break; + } + expect(value).toBe('one'); + await writer.write(value); + } + await outputResult; + await rpcClient.destroy(); + }, + ); + testProp( + 'manifest server call', + [specificMessageArb, fc.string()], + async (messages, params) => { + const inputStream = rpcTestUtils.messagesToReadableStream(messages); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + server: new ServerCaller(), + }, + streamFactory: async () => streamPair, + logger, + }); + const callerInterface = await rpcClient.methods.server(params); + const values: Array = []; + for await (const value of callerInterface) { + values.push(value); + } + const expectedValues = messages.map((v) => v.result); + expect(values).toStrictEqual(expectedValues); + expect((await outputResult)[0]?.toString()).toStrictEqual( + JSON.stringify({ + method: 'server', + jsonrpc: '2.0', + id: null, + params, + }), + ); + await rpcClient.destroy(); + }, + ); + testProp( + 'manifest client call', + [ + rpcTestUtils.jsonRpcResponseResultArb(fc.string()), + fc.array(fc.string(), { minLength: 5 }), + ], + async (message, params) => { + const inputStream = rpcTestUtils.messagesToReadableStream([message]); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + client: new ClientCaller(), + }, + streamFactory: async () => streamPair, + logger, + }); + const { output, writable } = await rpcClient.methods.client(); + const writer = writable.getWriter(); + for (const param of params) { + await writer.write(param); + } + expect(await output).toStrictEqual(message.result); + await writer.close(); + const expectedOutput = params.map((v) => + JSON.stringify({ + method: 'client', + jsonrpc: '2.0', + id: null, + params: v, + }), + ); + expect((await outputResult).map((v) => v.toString())).toStrictEqual( + expectedOutput, + ); + await rpcClient.destroy(); + }, + ); + testProp( + 'manifest unary call', + [rpcTestUtils.jsonRpcResponseResultArb().noShrink(), fc.string()], + async (message, params) => { + const inputStream = rpcTestUtils.messagesToReadableStream([message]); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + unary: new UnaryCaller(), + }, + streamFactory: async () => streamPair, + logger, + }); + const result = await rpcClient.methods.unary(params); + expect(result).toStrictEqual(message.result); + expect((await outputResult)[0]?.toString()).toStrictEqual( + JSON.stringify({ + method: 'unary', + jsonrpc: '2.0', + id: null, + params: params, + }), + ); + await rpcClient.destroy(); + }, + ); + testProp( + 'manifest raw caller', + [ + rpcTestUtils.safeJsonValueArb, + rpcTestUtils.rawDataArb, + rpcTestUtils.rawDataArb, + ], + async (headerParams, inputData, outputData) => { + const [inputResult, inputWritableStream] = + rpcTestUtils.streamToArray(); + const [outputResult, outputWritableStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: new ReadableStream({ + start: (controller) => { + const leadingResponse: JSONRPCResponseResult = { + jsonrpc: '2.0', + result: null, + id: null, + }; + controller.enqueue(Buffer.from(JSON.stringify(leadingResponse))); + for (const datum of outputData) { + controller.enqueue(datum); + } + controller.close(); + }, + }), + writable: inputWritableStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + raw: new RawCaller(), + }, + streamFactory: async () => streamPair, + logger, + }); + const callerInterface = await rpcClient.methods.raw(headerParams); + await callerInterface.readable.pipeTo(outputWritableStream); + const writer = callerInterface.writable.getWriter(); + for (const inputDatum of inputData) { + await writer.write(inputDatum); + } + await writer.close(); + + const expectedHeader: JSONRPCRequest = { + jsonrpc: '2.0', + method: 'raw', + params: headerParams, + id: null, + }; + expect(await inputResult).toStrictEqual([ + Buffer.from(JSON.stringify(expectedHeader)), + ...inputData, + ]); + expect(await outputResult).toStrictEqual(outputData); + }, + { seed: -783452149, path: '0:0:0:0:0:0:0', endOnFailure: true }, + ); + testProp( + 'manifest duplex caller', + [ + fc.array(rpcTestUtils.jsonRpcResponseResultArb(fc.string()), { + minLength: 1, + }), + ], + async (messages) => { + const inputStream = rpcTestUtils.messagesToReadableStream(messages); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + duplex: new DuplexCaller(), + }, + streamFactory: async () => streamPair, + logger, + }); + let count = 0; + const callerInterface = await rpcClient.methods.duplex(); + const writer = callerInterface.writable.getWriter(); + for await (const value of callerInterface.readable) { + count += 1; + await writer.write(value); + } + await writer.close(); + const result = await outputResult; + // We're just checking that it's consuming the messages as expected + expect(result.length).toEqual(messages.length); + expect(count).toEqual(messages.length); + await rpcClient.destroy(); + }, + ); + test('manifest without handler errors', async () => { + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async () => { + return {} as RPCStream; + }, + logger, + }); + // @ts-ignore: ignoring type safety here + expect(() => rpcClient.methods.someMethod()).toThrow(); + // @ts-ignore: ignoring type safety here + expect(() => rpcClient.withMethods.someMethod()).toThrow(); + await rpcClient.destroy(); + }); + describe('raw caller', () => { + test('raw caller uses default timeout when creating stream', async () => { + const holdProm = promise(); + let ctx: ContextTimed | undefined; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx_) => { + ctx = ctx_; + await holdProm.p; + // Should never reach this when testing + return {} as RPCStream; + }, + streamKeepAliveTimeoutTime: 100, + logger, + }); + // Timing out on stream creation + const callerInterfaceProm = rpcClient.rawStreamCaller('testMethod', {}); + await expect(callerInterfaceProm).toReject(); + await expect(callerInterfaceProm).rejects.toThrow( + rpcErrors.ErrorRPCTimedOut, + ); + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCTimedOut); + }); + test('raw caller times out when creating stream', async () => { + const holdProm = promise(); + let ctx: ContextTimed | undefined; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx_) => { + ctx = ctx_; + await holdProm.p; + // Should never reach this when testing + return {} as RPCStream; + }, + logger, + }); + // Timing out on stream creation + const callerInterfaceProm = rpcClient.rawStreamCaller( + 'testMethod', + {}, + { timer: 100 }, + ); + await expect(callerInterfaceProm).toReject(); + await expect(callerInterfaceProm).rejects.toThrow( + rpcErrors.ErrorRPCTimedOut, + ); + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCTimedOut); + }); + test('raw caller handles abort when creating stream', async () => { + const holdProm = promise(); + const ctxProm = promise(); + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx_) => { + ctxProm.resolveP(ctx_); + await holdProm.p; + // Should never reach this when testing + return {} as RPCStream; + }, + logger, + }); + const abortController = new AbortController(); + const rejectReason = Symbol('rejectReason'); + + // Timing out on stream creation + const callerInterfaceProm = rpcClient.rawStreamCaller( + 'testMethod', + {}, + { signal: abortController.signal }, + ); + abortController.abort(rejectReason); + const ctx = await ctxProm.p; + await expect(callerInterfaceProm).toReject(); + await expect(callerInterfaceProm).rejects.toBe(rejectReason); + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBe(rejectReason); + }); + test('raw caller times out awaiting stream', async () => { + const forwardPassThroughStream = new TransformStream< + Uint8Array, + Uint8Array + >(); + const reversePassThroughStream = new TransformStream< + Uint8Array, + Uint8Array + >(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + writable: forwardPassThroughStream.writable, + readable: reversePassThroughStream.readable, + }; + const ctxProm = promise(); + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx_) => { + ctxProm.resolveP(ctx_); + return streamPair; + }, + logger, + }); + // Timing out on stream + await expect( + Promise.all([ + rpcClient.rawStreamCaller('testMethod', {}, { timer: 100 }), + forwardPassThroughStream.readable.getReader().read(), + ]), + ).rejects.toThrow(rpcErrors.ErrorRPCTimedOut); + const ctx = await ctxProm.p; + await ctx?.timer; + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCTimedOut); + }); + test('raw caller handles abort awaiting stream', async () => { + const forwardPassThroughStream = new TransformStream< + Uint8Array, + Uint8Array + >(); + const reversePassThroughStream = new TransformStream< + Uint8Array, + Uint8Array + >(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + writable: forwardPassThroughStream.writable, + readable: reversePassThroughStream.readable, + }; + const ctxProm = promise(); + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx) => { + ctxProm.resolveP(ctx); + return streamPair; + }, + logger, + }); + const abortController = new AbortController(); + const rejectReason = Symbol('rejectReason'); + // Timing out on stream + const reader = forwardPassThroughStream.readable.getReader(); + const abortProm = promise(); + const ctxWaitProm = ctxProm.p.then((ctx) => { + if (ctx.signal.aborted) abortProm.resolveP(); + ctx.signal.addEventListener('abort', () => { + abortProm.resolveP(); + }); + abortController.abort(rejectReason); + }); + const rawStreamProm = rpcClient.rawStreamCaller( + 'testMethod', + {}, + { signal: abortController.signal }, + ); + await Promise.allSettled([rawStreamProm, reader.read(), ctxWaitProm]); + await expect(rawStreamProm).rejects.toBe(rejectReason); + const ctx = await ctxProm.p; + await abortProm.p; + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBe(rejectReason); + }); + }); + describe('duplex caller', () => { + test('duplex caller uses default timeout when creating stream', async () => { + const holdProm = promise(); + let ctx: ContextTimed | undefined; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx_) => { + ctx = ctx_; + await holdProm.p; + // Should never reach this when testing + return {} as RPCStream; + }, + streamKeepAliveTimeoutTime: 100, + logger, + }); + // Timing out on stream creation + const callerInterfaceProm = rpcClient.duplexStreamCaller('testMethod'); + await expect(callerInterfaceProm).toReject(); + await expect(callerInterfaceProm).rejects.toThrow( + rpcErrors.ErrorRPCTimedOut, + ); + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCTimedOut); + }); + test('duplex caller times out when creating stream', async () => { + const holdProm = promise(); + let ctx: ContextTimed | undefined; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx_) => { + ctx = ctx_; + await holdProm.p; + // Should never reach this when testing + return {} as RPCStream; + }, + logger, + }); + // Timing out on stream creation + const callerInterfaceProm = rpcClient.duplexStreamCaller('testMethod', { + timer: 100, + }); + await expect(callerInterfaceProm).toReject(); + await expect(callerInterfaceProm).rejects.toThrow( + rpcErrors.ErrorRPCTimedOut, + ); + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCTimedOut); + }); + test('duplex caller handles abort when creating stream', async () => { + const holdProm = promise(); + let ctx: ContextTimed | undefined; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx_) => { + ctx = ctx_; + await holdProm.p; + // Should never reach this when testing + return {} as RPCStream; + }, + logger, + }); + const abortController = new AbortController(); + const rejectReason = Symbol('rejectReason'); + abortController.abort(rejectReason); + + // Timing out on stream creation + const callerInterfaceProm = rpcClient.duplexStreamCaller('testMethod', { + signal: abortController.signal, + }); + await expect(callerInterfaceProm).toReject(); + await expect(callerInterfaceProm).rejects.toBe(rejectReason); + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBe(rejectReason); + }); + test('duplex caller uses default timeout awaiting stream', async () => { + const forwardPassThroughStream = new TransformStream< + Uint8Array, + Uint8Array + >(); + const reversePassThroughStream = new TransformStream< + Uint8Array, + Uint8Array + >(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + writable: forwardPassThroughStream.writable, + readable: reversePassThroughStream.readable, + }; + let ctx: ContextTimed | undefined; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx_) => { + ctx = ctx_; + return streamPair; + }, + streamKeepAliveTimeoutTime: 100, + logger, + }); + + // Timing out on stream + await rpcClient.duplexStreamCaller('testMethod'); + await ctx?.timer; + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCTimedOut); + }); + test('duplex caller times out awaiting stream', async () => { + const forwardPassThroughStream = new TransformStream< + Uint8Array, + Uint8Array + >(); + const reversePassThroughStream = new TransformStream< + Uint8Array, + Uint8Array + >(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + writable: forwardPassThroughStream.writable, + readable: reversePassThroughStream.readable, + }; + let ctx: ContextTimed | undefined; + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx_) => { + ctx = ctx_; + return streamPair; + }, + logger, + }); + + // Timing out on stream + await rpcClient.duplexStreamCaller('testMethod', { + timer: 100, + }); + await ctx?.timer; + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCTimedOut); + }); + test('duplex caller handles abort awaiting stream', async () => { + const forwardPassThroughStream = new TransformStream< + Uint8Array, + Uint8Array + >(); + const reversePassThroughStream = new TransformStream< + Uint8Array, + Uint8Array + >(); + const streamPair: RPCStream = { + cancel: async (reason) => { + await forwardPassThroughStream.readable.cancel(reason); + await reversePassThroughStream.writable.abort(reason); + }, + meta: undefined, + writable: forwardPassThroughStream.writable, + readable: reversePassThroughStream.readable, + }; + const ctxProm = promise(); + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx) => { + ctxProm.resolveP(ctx); + return streamPair; + }, + logger, + }); + const abortController = new AbortController(); + const rejectReason = Symbol('rejectReason'); + abortController.abort(rejectReason); + // Timing out on stream + const stream = await rpcClient.duplexStreamCaller('testMethod', { + signal: abortController.signal, + }); + const ctx = await ctxProm.p; + const abortProm = promise(); + if (ctx.signal.aborted) abortProm.resolveP(); + ctx.signal.addEventListener('abort', () => { + abortProm.resolveP(); + }); + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBe(rejectReason); + stream.cancel(Error('asd')); + }); + testProp( + 'duplex caller timeout is refreshed when sending message', + [specificMessageArb], + async (messages) => { + const inputStream = rpcTestUtils.messagesToReadableStream(messages); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const ctxProm = promise(); + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx) => { + ctxProm.resolveP(ctx); + return streamPair; + }, + logger, + }); + const callerInterface = await rpcClient.duplexStreamCaller< + JSONValue, + JSONValue + >(methodName); + + const ctx = await ctxProm.p; + // Reading refreshes timer + const reader = callerInterface.readable.getReader(); + await sleep(50); + let timeLeft = ctx.timer.getTimeout(); + const message = await reader.read(); + expect(ctx.timer.getTimeout()).toBeGreaterThan(timeLeft); + reader.releaseLock(); + for await (const _ of callerInterface.readable) { + // Do nothing + } + + // Writing should refresh timer + const writer = callerInterface.writable.getWriter(); + await sleep(50); + timeLeft = ctx.timer.getTimeout(); + await writer.write(message.value); + expect(ctx.timer.getTimeout()).toBeGreaterThan(timeLeft); + await writer.close(); + + await outputResult; + await rpcClient.destroy(); + }, + { numRuns: 5 }, + ); + testProp( + 'Check that ctx is provided to the middleWare and that the middleware can reset the timer', + [specificMessageArb], + async (messages) => { + const inputStream = rpcTestUtils.messagesToReadableStream(messages); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + const streamPair: RPCStream = { + cancel: () => {}, + meta: undefined, + readable: inputStream, + writable: outputStream, + }; + const ctxProm = promise(); + const rpcClient = await RPCClient.createRPCClient({ + manifest: {}, + streamFactory: async (ctx) => { + ctxProm.resolveP(ctx); + return streamPair; + }, + middlewareFactory: rpcUtilsMiddleware.defaultClientMiddlewareWrapper( + (ctx) => { + ctx.timer.reset(123); + return { + forward: new TransformStream(), + reverse: new TransformStream(), + }; + }, + ), + logger, + }); + const callerInterface = await rpcClient.duplexStreamCaller< + JSONValue, + JSONValue + >(methodName); + + const ctx = await ctxProm.p; + // Writing should refresh timer engage the middleware + const writer = callerInterface.writable.getWriter(); + await writer.write({}); + expect(ctx.timer.delay).toBe(123); + await writer.close(); + + await outputResult; + await rpcClient.destroy(); + }, + { numRuns: 1 }, + ); + }); +}); diff --git a/tests/rpc/RPCServer.test.ts b/tests/rpc/RPCServer.test.ts new file mode 100644 index 0000000..a695102 --- /dev/null +++ b/tests/rpc/RPCServer.test.ts @@ -0,0 +1,1215 @@ +import type { ContextTimed } from '@matrixai/contexts'; +import type { + ContainerType, + JSONRPCRequest, + JSONRPCResponse, + JSONRPCResponseError, + JSONValue, + RPCStream, +} from '../../src/types'; +import type { RPCErrorEvent } from '../../src/events'; +import { ReadableStream, TransformStream, WritableStream } from 'stream/web'; +import { fc, testProp } from '@fast-check/jest'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import * as rpcTestUtils from './utils'; +import RPCServer from '../../src/RPCServer'; +import * as rpcErrors from '../../src/errors/errors'; +import * as rpcUtils from '../../src/utils'; +import { promise, sleep } from '../../src/utils'; +import { + ClientHandler, + DuplexHandler, + RawHandler, + ServerHandler, + UnaryHandler, +} from '../../src/handlers'; +import * as rpcUtilsMiddleware from '../../src/utils/middleware'; + +describe(`${RPCServer.name}`, () => { + const logger = new Logger(`${RPCServer.name} Test`, LogLevel.WARN, [ + new StreamHandler(), + ]); + const methodName = 'testMethod'; + const specificMessageArb = fc + .array(rpcTestUtils.jsonRpcRequestMessageArb(fc.constant(methodName)), { + minLength: 5, + }) + .noShrink(); + const singleNumberMessageArb = fc.array( + rpcTestUtils.jsonRpcRequestMessageArb( + fc.constant(methodName), + fc.integer({ min: 1, max: 20 }), + ), + { + minLength: 2, + maxLength: 10, + }, + ); + const validToken = 'VALIDTOKEN'; + const invalidTokenMessageArb = rpcTestUtils.jsonRpcRequestMessageArb( + fc.constant('testMethod'), + fc.record({ + metadata: fc.record({ + token: fc.string().filter((v) => v !== validToken), + }), + data: rpcTestUtils.safeJsonValueArb, + }), + ); + + testProp( + 'can stream data with raw duplex stream handler', + [specificMessageArb], + async (messages) => { + const stream = rpcTestUtils + .messagesToReadableStream(messages) + .pipeThrough( + rpcTestUtils.binaryStreamToSnippedStream([4, 7, 13, 2, 6]), + ); + class TestHandler extends RawHandler { + public async handle( + input: [JSONRPCRequest, ReadableStream], + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): Promise<[JSONValue, ReadableStream]> { + for await (const _ of input[1]) { + // No touch, only consume + } + const readableStream = new ReadableStream({ + start: (controller) => { + controller.enqueue(Buffer.from('hello world!')); + controller.close(); + }, + }); + return Promise.resolve([null, readableStream]); + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestHandler({}), + }, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + await outputResult; + await rpcServer.destroy(); + }, + { numRuns: 1 }, + ); + testProp( + 'can stream data with duplex stream handler', + [specificMessageArb], + async (messages) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + class TestMethod extends DuplexHandler { + public async *handle( + input: AsyncGenerator, + ): AsyncGenerator { + for await (const val of input) { + yield val; + break; + } + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + await outputResult; + await rpcServer.destroy(); + }, + ); + testProp( + 'can stream data with client stream handler', + [specificMessageArb], + async (messages) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + class TestMethod extends ClientHandler { + public async handle( + input: AsyncGenerator, + ): Promise { + let count = 0; + for await (const _ of input) { + count += 1; + } + return count; + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + await outputResult; + await rpcServer.destroy(); + }, + ); + testProp( + 'can stream data with server stream handler', + [singleNumberMessageArb], + async (messages) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + class TestMethod extends ServerHandler { + public async *handle(input: number): AsyncGenerator { + for (let i = 0; i < input; i++) { + yield i; + } + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + await outputResult; + await rpcServer.destroy(); + }, + ); + testProp( + 'can stream data with server stream handler', + [specificMessageArb], + async (messages) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + class TestMethod extends UnaryHandler { + public async handle(input: JSONValue): Promise { + return input; + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + await outputResult; + await rpcServer.destroy(); + }, + ); + testProp( + 'handler is provided with container', + [specificMessageArb], + async (messages) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + const container = { + a: Symbol('a'), + B: Symbol('b'), + C: Symbol('c'), + }; + class TestMethod extends DuplexHandler { + public async *handle( + input: AsyncGenerator, + ): AsyncGenerator { + expect(this.container).toBe(container); + for await (const val of input) { + yield val; + } + } + } + + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod(container), + }, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + await outputResult; + await rpcServer.destroy(); + }, + ); + testProp( + 'handler is provided with connectionInfo', + [specificMessageArb], + async (messages) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + const meta = { + localHost: 'hostA', + localPort: 12341, + remoteCertificates: [], + remoteHost: 'hostA', + remotePort: 12341, + }; + let handledMeta; + class TestMethod extends DuplexHandler { + public async *handle( + input: AsyncGenerator, + _cancel, + meta, + ): AsyncGenerator { + handledMeta = meta; + for await (const val of input) { + yield val; + } + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + meta, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + await outputResult; + await rpcServer.destroy(); + expect(handledMeta).toBe(meta); + }, + ); + testProp('handler can be aborted', [specificMessageArb], async (messages) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + class TestMethod extends DuplexHandler { + public async *handle( + input: AsyncGenerator, + _cancel, + _meta, + ctx: ContextTimed, + ): AsyncGenerator { + for await (const val of input) { + if (ctx.signal.aborted) throw ctx.signal.reason; + yield val; + } + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + const [outputResult, outputStream] = + rpcTestUtils.streamToArray(); + let thing; + const tapStream = rpcTestUtils.tapTransformStream( + async (_, iteration) => { + if (iteration === 2) { + // @ts-ignore: kidnap private property + const activeStreams = rpcServer.activeStreams.values(); + // @ts-ignore: kidnap private property + for (const activeStream of activeStreams) { + thing = activeStream; + activeStream.cancel(new rpcErrors.ErrorRPCStopping()); + } + } + }, + ); + void tapStream.readable.pipeTo(outputStream).catch(() => {}); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: tapStream.writable, + }; + rpcServer.handleStream(readWriteStream); + const result = await outputResult; + const lastMessage = result[result.length - 1]; + await expect(thing).toResolve(); + expect(lastMessage).toBeDefined(); + expect(() => + rpcUtils.parseJSONRPCResponseError(JSON.parse(lastMessage.toString())), + ).not.toThrow(); + await rpcServer.destroy(); + }); + testProp('handler yields nothing', [specificMessageArb], async (messages) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + class TestMethod extends DuplexHandler { + public async *handle( + input: AsyncGenerator, + ): AsyncGenerator { + for await (const _ of input) { + // Do nothing, just consume + } + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + await outputResult; + // We're just expecting no errors + await rpcServer.destroy(); + }); + testProp( + 'should send error message', + [specificMessageArb, rpcTestUtils.errorArb(rpcTestUtils.errorArb())], + async (messages, error) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + class TestMethod extends DuplexHandler { + public async *handle(): AsyncGenerator { + throw error; + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + let resolve, reject; + const errorProm = new Promise((resolve_, reject_) => { + resolve = resolve_; + reject = reject_; + }); + rpcServer.addEventListener('error', (thing: RPCErrorEvent) => { + resolve(thing); + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + const rawErrorMessage = (await outputResult)[0]!.toString(); + expect(rawErrorMessage).toInclude('stack'); + const errorMessage = JSON.parse(rawErrorMessage); + expect(errorMessage.error.code).toEqual(error.exitCode); + expect(errorMessage.error.message).toEqual(error.description); + reject(); + await expect(errorProm).toReject(); + await rpcServer.destroy(); + }, + ); + testProp( + 'should send error message with sensitive', + [specificMessageArb, rpcTestUtils.errorArb(rpcTestUtils.errorArb())], + async (messages, error) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + class TestMethod extends DuplexHandler { + public async *handle(): AsyncGenerator { + throw error; + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + sensitive: true, + logger, + }); + let resolve, reject; + const errorProm = new Promise((resolve_, reject_) => { + resolve = resolve_; + reject = reject_; + }); + rpcServer.addEventListener('error', (thing: RPCErrorEvent) => { + resolve(thing); + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + const rawErrorMessage = (await outputResult)[0]!.toString(); + expect(rawErrorMessage).not.toInclude('stack'); + const errorMessage = JSON.parse(rawErrorMessage); + expect(errorMessage.error.code).toEqual(error.exitCode); + expect(errorMessage.error.message).toEqual(error.description); + reject(); + await expect(errorProm).toReject(); + await rpcServer.destroy(); + }, + ); + testProp( + 'should emit stream error if input stream fails', + [specificMessageArb], + async (messages) => { + const handlerEndedProm = promise(); + class TestMethod extends DuplexHandler { + public async *handle(input): AsyncGenerator { + try { + for await (const _ of input) { + // Consume but don't yield anything + } + } finally { + handlerEndedProm.resolveP(); + } + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + let resolve; + rpcServer.addEventListener('error', (thing: RPCErrorEvent) => { + resolve(thing); + }); + const passThroughStreamIn = new TransformStream(); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: passThroughStreamIn.readable, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + const writer = passThroughStreamIn.writable.getWriter(); + // Write messages + for (const message of messages) { + await writer.write(Buffer.from(JSON.stringify(message))); + } + // Abort stream + const writerReason = Symbol('writerAbort'); + await writer.abort(writerReason); + // We should get an error RPC message + await expect(outputResult).toResolve(); + const errorMessage = JSON.parse((await outputResult)[0].toString()); + // Parse without error + rpcUtils.parseJSONRPCResponseError(errorMessage); + // Check that the handler was cleaned up. + await expect(handlerEndedProm.p).toResolve(); + await rpcServer.destroy(); + }, + { numRuns: 1 }, + ); + testProp( + 'should emit stream error if output stream fails', + [specificMessageArb], + async (messages) => { + const handlerEndedProm = promise(); + let ctx: ContextTimed | undefined; + class TestMethod extends DuplexHandler { + public async *handle( + input, + _cancel, + _meta, + ctx_, + ): AsyncGenerator { + ctx = ctx_; + // Echo input + try { + yield* input; + } finally { + handlerEndedProm.resolveP(); + } + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + }); + let resolve; + const errorProm = new Promise((resolve_) => { + resolve = resolve_; + }); + rpcServer.addEventListener('error', (thing: RPCErrorEvent) => { + resolve(thing); + }); + const passThroughStreamIn = new TransformStream(); + const passThroughStreamOut = new TransformStream< + Uint8Array, + Uint8Array + >(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: passThroughStreamIn.readable, + writable: passThroughStreamOut.writable, + }; + rpcServer.handleStream(readWriteStream); + const writer = passThroughStreamIn.writable.getWriter(); + const reader = passThroughStreamOut.readable.getReader(); + // Write messages + for (const message of messages) { + await writer.write(Buffer.from(JSON.stringify(message))); + await reader.read(); + } + // Abort stream + // const writerReason = Symbol('writerAbort'); + const readerReason = Symbol('readerAbort'); + // Await writer.abort(writerReason); + await reader.cancel(readerReason); + // We should get an error event + const event = await errorProm; + await writer.close(); + // Expect(event.detail.cause).toContain(writerReason); + expect(event.detail).toBeInstanceOf(rpcErrors.ErrorRPCOutputStreamError); + expect(event.detail.cause).toBe(readerReason); + // Check that the handler was cleaned up. + await expect(handlerEndedProm.p).toResolve(); + // Check that an abort signal happened + expect(ctx).toBeDefined(); + expect(ctx?.signal.aborted).toBeTrue(); + expect(ctx?.signal.reason).toBe(readerReason); + await rpcServer.destroy(); + }, + { numRuns: 1 }, + ); + testProp('forward middlewares', [specificMessageArb], async (messages) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + class TestMethod extends DuplexHandler { + public async *handle( + input: AsyncGenerator, + ): AsyncGenerator { + yield* input; + } + } + const middlewareFactory = rpcUtilsMiddleware.defaultServerMiddlewareWrapper( + () => { + return { + forward: new TransformStream({ + transform: (chunk, controller) => { + chunk.params = 1; + controller.enqueue(chunk); + }, + }), + reverse: new TransformStream(), + }; + }, + ); + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + middlewareFactory: middlewareFactory, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + const out = await outputResult; + expect(out.map((v) => v!.toString())).toStrictEqual( + messages.map(() => { + return JSON.stringify({ + jsonrpc: '2.0', + result: 1, + id: null, + }); + }), + ); + await rpcServer.destroy(); + }); + testProp('reverse middlewares', [specificMessageArb], async (messages) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + class TestMethod extends DuplexHandler { + public async *handle( + input: AsyncGenerator, + ): AsyncGenerator { + yield* input; + } + } + const middleware = rpcUtilsMiddleware.defaultServerMiddlewareWrapper(() => { + return { + forward: new TransformStream(), + reverse: new TransformStream({ + transform: (chunk, controller) => { + if ('result' in chunk) chunk.result = 1; + controller.enqueue(chunk); + }, + }), + }; + }); + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + middlewareFactory: middleware, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + const out = await outputResult; + expect(out.map((v) => v!.toString())).toStrictEqual( + messages.map(() => { + return JSON.stringify({ + jsonrpc: '2.0', + result: 1, + id: null, + }); + }), + ); + await rpcServer.destroy(); + }); + testProp( + 'forward middleware authentication', + [invalidTokenMessageArb], + async (message) => { + const stream = rpcTestUtils.messagesToReadableStream([message]); + class TestMethod extends DuplexHandler { + public async *handle( + input: AsyncGenerator, + ): AsyncGenerator { + yield* input; + } + } + const middleware = rpcUtilsMiddleware.defaultServerMiddlewareWrapper( + () => { + let first = true; + let reverseController: TransformStreamDefaultController; + return { + forward: new TransformStream< + JSONRPCRequest, + JSONRPCRequest + >({ + transform: (chunk, controller) => { + if (first && chunk.params?.metadata.token !== validToken) { + reverseController.enqueue(failureMessage); + // Closing streams early + controller.terminate(); + reverseController.terminate(); + } + first = false; + controller.enqueue(chunk); + }, + }), + reverse: new TransformStream({ + start: (controller) => { + // Kidnapping reverse controller + reverseController = controller; + }, + transform: (chunk, controller) => { + controller.enqueue(chunk); + }, + }), + }; + }, + ); + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + middlewareFactory: middleware, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + type TestType = { + metadata: { + token: string; + }; + data: JSONValue; + }; + const failureMessage: JSONRPCResponseError = { + jsonrpc: '2.0', + id: null, + error: { + code: 1, + message: 'failure of some kind', + }, + }; + rpcServer.handleStream(readWriteStream); + expect((await outputResult).toString()).toEqual( + JSON.stringify(failureMessage), + ); + await rpcServer.destroy(); + }, + ); + + test('timeout with default time after handler selected', async () => { + const ctxProm = promise(); + + // Diagnostic log to indicate the start of the test + + class TestHandler extends RawHandler { + public async handle( + _input: [JSONRPCRequest, ReadableStream], + _cancel: (reason?: any) => void, + _meta: Record | undefined, + ctx_: ContextTimed, + ): Promise<[JSONValue, ReadableStream]> { + return new Promise((resolve, reject) => { + ctxProm.resolveP(ctx_); + + let controller: ReadableStreamController; + const stream = new ReadableStream({ + start: (controller_) => { + controller = controller_; + }, + }); + + ctx_.signal.addEventListener('abort', () => { + controller!.error(Error('ending')); + }); + + // Return something to fulfill the Promise type expectation. + resolve([null, stream]); + }); + } + } + + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestHandler({}), + }, + handlerTimeoutTime: 100, + logger, + }); + + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const stream = rpcTestUtils.messagesToReadableStream([ + { + jsonrpc: '2.0', + method: 'testMethod', + params: null, + }, + { + jsonrpc: '2.0', + method: 'testMethod', + params: null, + }, + ]); + + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + + rpcServer.handleStream(readWriteStream); + + const ctx = await ctxProm.p; + + expect(ctx.timer.delay).toEqual(100); + + await ctx.timer; + + expect(ctx.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCTimedOut); + + await expect(outputResult).toReject(); + + await rpcServer.destroy(); + }); + test('timeout with default time before handler selected', async () => { + const rpcServer = await RPCServer.createRPCServer({ + manifest: {}, + handlerTimeoutTime: 100, + logger, + }); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: new ReadableStream({ + // Ignore + cancel: () => {}, + }), + writable: new WritableStream({ + // Ignore + abort: () => {}, + }), + }; + rpcServer.handleStream(readWriteStream); + // With no handler we can only check alive connections through the server + // @ts-ignore: kidnap protected property + const activeStreams = rpcServer.activeStreams; + for await (const [prom] of activeStreams.entries()) { + await prom; + } + await rpcServer.destroy(); + }); + test('handler overrides timeout', async () => { + { + const waitProm = promise(); + const ctxShortProm = promise(); + class TestMethodShortTimeout extends UnaryHandler { + timeout = 25; + public async handle( + input: JSONValue, + _cancel, + _meta, + ctx_, + ): Promise { + ctxShortProm.resolveP(ctx_); + await waitProm.p; + return input; + } + } + const ctxLongProm = promise(); + class TestMethodLongTimeout extends UnaryHandler { + timeout = 100; + public async handle( + input: JSONValue, + _cancel, + _meta, + ctx_, + ): Promise { + ctxLongProm.resolveP(ctx_); + await waitProm.p; + return input; + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testShort: new TestMethodShortTimeout({}), + testLong: new TestMethodLongTimeout({}), + }, + handlerTimeoutTime: 50, + logger, + }); + const streamShort = rpcTestUtils.messagesToReadableStream([ + { + jsonrpc: '2.0', + method: 'testShort', + params: null, + }, + ]); + const readWriteStreamShort: RPCStream = { + cancel: () => {}, + readable: streamShort, + writable: new WritableStream(), + }; + rpcServer.handleStream(readWriteStreamShort); + // Shorter timeout is updated + const ctxShort = await ctxShortProm.p; + expect(ctxShort.timer.delay).toEqual(25); + const streamLong = rpcTestUtils.messagesToReadableStream([ + { + jsonrpc: '2.0', + method: 'testLong', + params: null, + }, + ]); + const readWriteStreamLong: RPCStream = { + cancel: () => {}, + readable: streamLong, + writable: new WritableStream(), + }; + rpcServer.handleStream(readWriteStreamLong); + + // Longer timeout is set to server's default + const ctxLong = await ctxLongProm.p; + expect(ctxLong.timer.delay).toEqual(50); + waitProm.resolveP(); + await rpcServer.destroy(); + } + }); + test('duplex handler refreshes timeout when messages are sent', async () => { + const contextProm = promise(); + const stepProm1 = promise(); + const stepProm2 = promise(); + const passthroughStream = new TransformStream(); + class TestHandler extends DuplexHandler { + public async *handle( + input: AsyncGenerator, + _cancel, + _meta, + ctx, + ): AsyncGenerator { + contextProm.resolveP(ctx); + for await (const _ of input) { + // Do nothing, just consume + } + await stepProm1.p; + yield 1; + await stepProm2.p; + yield 2; + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestHandler({}), + }, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const requestMessage = Buffer.from( + JSON.stringify({ + jsonrpc: '2.0', + method: 'testMethod', + params: 1, + }), + ); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: passthroughStream.readable, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + const writer = passthroughStream.writable.getWriter(); + await writer.write(requestMessage); + const ctx = await contextProm.p; + const scheduled: Date | undefined = ctx.timer.scheduled; + // Checking writing refreshes timer + await sleep(25); + await writer.write(requestMessage); + expect(ctx.timer.scheduled).toBeAfter(scheduled!); + expect( + ctx.timer.scheduled!.getTime() - scheduled!.getTime(), + ).toBeGreaterThanOrEqual(25); + await writer.close(); + // Checking reading refreshes timer + await sleep(25); + stepProm1.resolveP(); + expect(ctx.timer.scheduled).toBeAfter(scheduled!); + expect( + ctx.timer.scheduled!.getTime() - scheduled!.getTime(), + ).toBeGreaterThanOrEqual(25); + stepProm2.resolveP(); + await outputResult; + await rpcServer.destroy(); + }); + test('stream ending cleans up timer and abortSignal', async () => { + const ctxProm = promise(); + class TestHandler extends RawHandler { + public async handle( + input: [JSONRPCRequest, ReadableStream], + _cancel: (reason?: any) => void, + _meta: Record | undefined, + ctx_: ContextTimed, + ): Promise<[JSONValue, ReadableStream]> { + return new Promise((resolve) => { + ctxProm.resolveP(ctx_); + void (async () => { + for await (const _ of input[1]) { + // Do nothing, just consume + } + })(); + const readableStream = new ReadableStream({ + start: (controller) => { + controller.close(); + }, + }); + resolve([null, readableStream]); + }); + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestHandler({}), + }, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const stream = rpcTestUtils.messagesToReadableStream([ + { + jsonrpc: '2.0', + method: 'testMethod', + params: null, + }, + ]); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + const ctx = await ctxProm.p; + await outputResult; + await rpcServer.destroy(false); + expect(ctx.signal.aborted).toBeTrue(); + expect(ctx.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCStreamEnded); + // If the timer has already resolved then it was cancelled + await expect(ctx.timer).toReject(); + await rpcServer.destroy(); + }); + test('Timeout has a grace period before forcing the streams closed', async () => { + const ctxProm = promise(); + class TestHandler extends RawHandler { + public async handle( + input: [JSONRPCRequest, ReadableStream], + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): Promise<[JSONValue, ReadableStream]> { + ctxProm.resolveP(ctx); + + return Promise.resolve([null, new ReadableStream()]); + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestHandler({}), + }, + handlerTimeoutTime: 50, + handlerTimeoutGraceTime: 100, + logger, + }); + const [, outputStream] = rpcTestUtils.streamToArray(); + const stream = rpcTestUtils.messagesToReadableStream([ + { + jsonrpc: '2.0', + method: 'testMethod', + params: null, + }, + { + jsonrpc: '2.0', + method: 'testMethod', + params: null, + }, + ]); + const cancelProm = promise(); + const readWriteStream: RPCStream = { + cancel: (reason) => cancelProm.resolveP(reason), + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + const ctx = await ctxProm.p; + await ctx.timer; + const then = Date.now(); + expect(ctx.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCTimedOut); + // Should end after grace period + await expect(cancelProm.p).resolves.toBeInstanceOf( + rpcErrors.ErrorRPCTimedOut, + ); + expect(Date.now() - then).toBeGreaterThanOrEqual(90); + }); + testProp( + 'middleware can update timeout timer', + [specificMessageArb], + async (messages) => { + const stream = rpcTestUtils.messagesToReadableStream(messages); + const ctxProm = promise(); + class TestMethod extends DuplexHandler { + public async *handle( + input: AsyncGenerator, + _cancel, + _meta, + ctx, + ): AsyncGenerator { + ctxProm.resolveP(ctx); + yield* input; + } + } + const middlewareFactory = + rpcUtilsMiddleware.defaultServerMiddlewareWrapper((ctx) => { + ctx.timer.reset(12345); + return { + forward: new TransformStream(), + reverse: new TransformStream(), + }; + }); + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + middlewareFactory: middlewareFactory, + logger, + }); + const [outputResult, outputStream] = rpcTestUtils.streamToArray(); + const readWriteStream: RPCStream = { + cancel: () => {}, + readable: stream, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + await outputResult; + const ctx = await ctxProm.p; + expect(ctx.timer.delay).toBe(12345); + }, + ); + test('destroying the `RPCServer` sends an abort signal and closes connection', async () => { + const ctxProm = promise(); + class TestHandler extends RawHandler { + public async handle( + input: [JSONRPCRequest, ReadableStream], + _cancel: (reason?: any) => void, + _meta: Record | undefined, + ctx_: ContextTimed, + ): Promise<[JSONValue, ReadableStream]> { + return new Promise((resolve) => { + ctxProm.resolveP(ctx_); + // Echo messages + return [null, input[1]]; + }); + } + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestHandler({}), + }, + handlerTimeoutGraceTime: 0, + logger, + }); + const [, outputStream] = rpcTestUtils.streamToArray(); + const message = Buffer.from( + JSON.stringify({ + jsonrpc: '2.0', + method: 'testMethod', + params: null, + }), + ); + const forwardStream = new TransformStream(); + const cancelProm = promise(); + const readWriteStream: RPCStream = { + cancel: (reason) => cancelProm.resolveP(reason), + readable: forwardStream.readable, + writable: outputStream, + }; + rpcServer.handleStream(readWriteStream); + const writer = forwardStream.writable.getWriter(); + await writer.write(message); + const ctx = await ctxProm.p; + void rpcServer.destroy(true).then( + () => {}, + () => {}, + ); + await expect(cancelProm.p).resolves.toBeInstanceOf( + rpcErrors.ErrorRPCStopping, + ); + expect(ctx.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCStopping); + await writer.close(); + }); +}); diff --git a/tests/rpc/utils.ts b/tests/rpc/utils.ts new file mode 100644 index 0000000..4c779ee --- /dev/null +++ b/tests/rpc/utils.ts @@ -0,0 +1,302 @@ +import type { ReadableWritablePair } from 'stream/web'; +import type { JSONValue } from '../../src/types'; +import type { + JSONRPCError, + JSONRPCMessage, + JSONRPCRequestNotification, + JSONRPCRequestMessage, + JSONRPCResponseError, + JSONRPCResponseResult, + JSONRPCResponse, + JSONRPCRequest, +} from '../../src/types'; +import { ReadableStream, WritableStream, TransformStream } from 'stream/web'; +import { fc } from '@fast-check/jest'; +import { IdInternal } from '@matrixai/id'; +import * as utils from '../../src/utils'; +import { fromError } from '../../src/utils'; +import * as rpcErrors from '../../src/errors'; + +/** + * This is used to convert regular chunks into randomly sized chunks based on + * a provided pattern. This is to replicate randomness introduced by packets + * splitting up the data. + */ +function binaryStreamToSnippedStream(snippingPattern: Array) { + let buffer = Buffer.alloc(0); + let iteration = 0; + return new TransformStream({ + transform: (chunk, controller) => { + buffer = Buffer.concat([buffer, chunk]); + while (true) { + const snipAmount = snippingPattern[iteration % snippingPattern.length]; + if (snipAmount > buffer.length) break; + iteration += 1; + const returnBuffer = buffer.subarray(0, snipAmount); + controller.enqueue(returnBuffer); + buffer = buffer.subarray(snipAmount); + } + }, + flush: (controller) => { + controller.enqueue(buffer); + }, + }); +} + +/** + * This is used to convert regular chunks into randomly sized chunks based on + * a provided pattern. This is to replicate randomness introduced by packets + * splitting up the data. + */ +function binaryStreamToNoisyStream(noise: Array) { + let iteration: number = 0; + return new TransformStream({ + transform: (chunk, controller) => { + const noiseBuffer = noise[iteration % noise.length]; + const newBuffer = Buffer.from(Buffer.concat([chunk, noiseBuffer])); + controller.enqueue(newBuffer); + iteration += 1; + }, + }); +} + +/** + * This takes an array of JSONRPCMessages and converts it to a readable stream. + * Used to seed input for handlers and output for callers. + */ +const messagesToReadableStream = (messages: Array) => { + return new ReadableStream({ + async start(controller) { + for (const arrayElement of messages) { + controller.enqueue(Buffer.from(JSON.stringify(arrayElement), 'utf-8')); + } + controller.close(); + }, + }); +}; + +/** + * Out RPC data is in form of JSON objects. + * This creates a JSON object of the type `JSONValue` and will be unchanged by + * a json stringify and parse cycle. + */ +const safeJsonValueArb = fc + .json() + .map((value) => JSON.parse(value.replace('__proto__', 'proto')) as JSONValue); + +const idArb = fc.oneof(fc.string(), fc.integer(), fc.constant(null)); + +const jsonRpcRequestMessageArb = ( + method: fc.Arbitrary = fc.string(), + params: fc.Arbitrary = safeJsonValueArb, +) => + fc + .record( + { + jsonrpc: fc.constant('2.0'), + method: method, + params: params, + id: idArb, + }, + { + requiredKeys: ['jsonrpc', 'method', 'id'], + }, + ) + .noShrink() as fc.Arbitrary; + +const jsonRpcRequestNotificationArb = ( + method: fc.Arbitrary = fc.string(), + params: fc.Arbitrary = safeJsonValueArb, +) => + fc + .record( + { + jsonrpc: fc.constant('2.0'), + method: method, + params: params, + }, + { + requiredKeys: ['jsonrpc', 'method'], + }, + ) + .noShrink() as fc.Arbitrary; + +const jsonRpcRequestArb = ( + method: fc.Arbitrary = fc.string(), + params: fc.Arbitrary = safeJsonValueArb, +) => + fc + .oneof( + jsonRpcRequestMessageArb(method, params), + jsonRpcRequestNotificationArb(method, params), + ) + .noShrink() as fc.Arbitrary; + +const jsonRpcResponseResultArb = ( + result: fc.Arbitrary = safeJsonValueArb, +) => + fc + .record({ + jsonrpc: fc.constant('2.0'), + result: result, + id: idArb, + }) + .noShrink() as fc.Arbitrary; +const jsonRpcErrorArb = ( + error: fc.Arbitrary = fc.constant(new Error('test error')), + sensitive: boolean = false, +) => + fc + .record( + { + code: fc.integer(), + message: fc.string(), + data: error.map((e) => fromError(e, sensitive)), + }, + { + requiredKeys: ['code', 'message'], + }, + ) + .noShrink() as fc.Arbitrary; + +const jsonRpcResponseErrorArb = ( + error?: fc.Arbitrary, + sensitive: boolean = false, +) => + fc + .record({ + jsonrpc: fc.constant('2.0'), + error: jsonRpcErrorArb(error, sensitive), + id: idArb, + }) + .noShrink() as fc.Arbitrary; + +const jsonRpcResponseArb = ( + result: fc.Arbitrary = safeJsonValueArb, +) => + fc + .oneof(jsonRpcResponseResultArb(result), jsonRpcResponseErrorArb()) + .noShrink() as fc.Arbitrary; + +const jsonRpcMessageArb = ( + method: fc.Arbitrary = fc.string(), + params: fc.Arbitrary = safeJsonValueArb, + result: fc.Arbitrary = safeJsonValueArb, +) => + fc + .oneof(jsonRpcRequestArb(method, params), jsonRpcResponseArb(result)) + .noShrink() as fc.Arbitrary; + +const snippingPatternArb = fc + .array(fc.integer({ min: 1, max: 32 }), { minLength: 100, size: 'medium' }) + .noShrink(); + +const jsonMessagesArb = fc + .array(jsonRpcRequestMessageArb(), { minLength: 2 }) + .noShrink(); + +const rawDataArb = fc.array(fc.uint8Array({ minLength: 1 }), { minLength: 1 }); + +function streamToArray(): [Promise>, WritableStream] { + const outputArray: Array = []; + const result = utils.promise>(); + const outputStream = new WritableStream({ + write: (chunk) => { + outputArray.push(chunk); + }, + close: () => { + result.resolveP(outputArray); + }, + abort: (reason) => { + result.rejectP(reason); + }, + }); + return [result.p, outputStream]; +} + +type TapCallback = (chunk: T, iteration: number) => Promise; + +/** + * This is used to convert regular chunks into randomly sized chunks based on + * a provided pattern. This is to replicate randomness introduced by packets + * splitting up the data. + */ +function tapTransformStream(tapCallback: TapCallback = async () => {}) { + let iteration: number = 0; + return new TransformStream({ + transform: async (chunk, controller) => { + try { + await tapCallback(chunk, iteration); + } catch (e) { + // Ignore errors here + } + controller.enqueue(chunk); + iteration += 1; + }, + }); +} + +function createTapPairs( + forwardTapCallback: TapCallback = async () => {}, + reverseTapCallback: TapCallback = async () => {}, +) { + const forwardTap = tapTransformStream(forwardTapCallback); + const reverseTap = tapTransformStream(reverseTapCallback); + const clientPair: ReadableWritablePair = { + readable: reverseTap.readable, + writable: forwardTap.writable, + }; + const serverPair: ReadableWritablePair = { + readable: forwardTap.readable, + writable: reverseTap.writable, + }; + return { + clientPair, + serverPair, + }; +} + +const errorArb = ( + cause: fc.Arbitrary = fc.constant(undefined), +) => + cause.chain((cause) => + fc.oneof( + fc.constant(new rpcErrors.ErrorRPCRemote(undefined)), + fc.constant(new rpcErrors.ErrorRPCMessageLength(undefined)), + fc.constant( + new rpcErrors.ErrorRPCRemote( + { + command: 'someCommand', + host: `someHost`, + port: 0, + }, + undefined, + { + cause, + }, + ), + ), + ), + ); + +export { + binaryStreamToSnippedStream, + binaryStreamToNoisyStream, + messagesToReadableStream, + safeJsonValueArb, + jsonRpcRequestMessageArb, + jsonRpcRequestNotificationArb, + jsonRpcRequestArb, + jsonRpcResponseResultArb, + jsonRpcErrorArb, + jsonRpcResponseErrorArb, + jsonRpcResponseArb, + jsonRpcMessageArb, + snippingPatternArb, + jsonMessagesArb, + rawDataArb, + streamToArray, + tapTransformStream, + createTapPairs, + errorArb, +}; diff --git a/tests/rpc/utils/middleware.test.ts b/tests/rpc/utils/middleware.test.ts new file mode 100644 index 0000000..a995b8c --- /dev/null +++ b/tests/rpc/utils/middleware.test.ts @@ -0,0 +1,103 @@ +import { fc, testProp } from '@fast-check/jest'; +import { JSONParser } from '@streamparser/json'; +import { AsyncIterableX as AsyncIterable } from 'ix/asynciterable'; +import * as rpcUtils from '../../../src/utils'; +import 'ix/add/asynciterable-operators/toarray'; +import * as rpcErrors from '../../../src/errors'; +import * as rpcUtilsMiddleware from '../../../src/utils/middleware'; +import * as rpcTestUtils from '../utils'; + +describe('Middleware tests', () => { + const noiseArb = fc + .array( + fc.uint8Array({ minLength: 5 }).map((array) => Buffer.from(array)), + { minLength: 5 }, + ) + .noShrink(); + + testProp( + 'can parse json stream', + [rpcTestUtils.jsonMessagesArb], + async (messages) => { + const parsedStream = rpcTestUtils + .messagesToReadableStream(messages) + .pipeThrough( + rpcUtilsMiddleware.binaryToJsonMessageStream( + rpcUtils.parseJSONRPCMessage, + ), + ); // Converting back. + + const asd = await AsyncIterable.as(parsedStream).toArray(); + expect(asd).toEqual(messages); + }, + { numRuns: 1000 }, + ); + testProp( + 'Message size limit is enforced when parsing', + [ + fc.array( + rpcTestUtils.jsonRpcRequestMessageArb(fc.string({ minLength: 100 })), + { + minLength: 1, + }, + ), + ], + async (messages) => { + const parsedStream = rpcTestUtils + .messagesToReadableStream(messages) + .pipeThrough(rpcTestUtils.binaryStreamToSnippedStream([10])) + .pipeThrough( + rpcUtilsMiddleware.binaryToJsonMessageStream( + rpcUtils.parseJSONRPCMessage, + 50, + ), + ); + + const doThing = async () => { + for await (const _ of parsedStream) { + // No touch, only consume + } + }; + await expect(doThing()).rejects.toThrow(rpcErrors.ErrorRPCMessageLength); + }, + { numRuns: 1000 }, + ); + testProp( + 'can parse json stream with random chunk sizes', + [rpcTestUtils.jsonMessagesArb, rpcTestUtils.snippingPatternArb], + async (messages, snippattern) => { + const parsedStream = rpcTestUtils + .messagesToReadableStream(messages) + .pipeThrough(rpcTestUtils.binaryStreamToSnippedStream(snippattern)) // Imaginary internet here + .pipeThrough( + rpcUtilsMiddleware.binaryToJsonMessageStream( + rpcUtils.parseJSONRPCMessage, + ), + ); // Converting back. + + const asd = await AsyncIterable.as(parsedStream).toArray(); + expect(asd).toStrictEqual(messages); + }, + { numRuns: 1000 }, + ); + testProp( + 'Will error on bad data', + [rpcTestUtils.jsonMessagesArb, rpcTestUtils.snippingPatternArb, noiseArb], + async (messages, snippattern, noise) => { + const parsedStream = rpcTestUtils + .messagesToReadableStream(messages) + .pipeThrough(rpcTestUtils.binaryStreamToSnippedStream(snippattern)) // Imaginary internet here + .pipeThrough(rpcTestUtils.binaryStreamToNoisyStream(noise)) // Adding bad data to the stream + .pipeThrough( + rpcUtilsMiddleware.binaryToJsonMessageStream( + rpcUtils.parseJSONRPCMessage, + ), + ); // Converting back. + + await expect(AsyncIterable.as(parsedStream).toArray()).rejects.toThrow( + rpcErrors.ErrorRPCParse, + ); + }, + { numRuns: 1000 }, + ); +}); diff --git a/tests/rpc/utils/utils.test.ts b/tests/rpc/utils/utils.test.ts new file mode 100644 index 0000000..c5b1645 --- /dev/null +++ b/tests/rpc/utils/utils.test.ts @@ -0,0 +1,26 @@ +import { testProp, fc } from '@fast-check/jest'; +import { JSONParser } from '@streamparser/json'; +import * as rpcUtils from '../../../src/utils'; +import 'ix/add/asynciterable-operators/toarray'; +import * as rpcTestUtils from '../utils'; + +describe('utils tests', () => { + testProp( + 'can parse messages', + [rpcTestUtils.jsonRpcMessageArb()], + async (message) => { + rpcUtils.parseJSONRPCMessage(message); + }, + { numRuns: 1000 }, + ); + testProp( + 'malformed data cases parsing errors', + [fc.json()], + async (message) => { + expect(() => + rpcUtils.parseJSONRPCMessage(Buffer.from(JSON.stringify(message))), + ).toThrow(); + }, + { numRuns: 1000 }, + ); +}); diff --git a/tsconfig.json b/tsconfig.json index 907ed72..030dd67 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "experimentalDecorators": true, "outDir": "./dist", "tsBuildInfoFile": "./dist/tsbuildinfo", "incremental": true, From f30da253c503b7df81f62561c3dab1e1f1b12e08 Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 7 Sep 2023 17:00:07 +1000 Subject: [PATCH 04/12] Works as a standalone library now. Pending review to merge to staging. callers and handlers are now refactored * WIP - Newline now works, refers issue #1 node v20 fix feat: handlers implementations are now abstract arrow functions * Fixes #5 [ci skip] * resolves issue 5, makes RPC handlers abstract arrow function properties feat: rename to uppercase [ci skip] fix: handler export fix [ci skip] fix: tsconf from quic [ci skip] fix: dependencies (js quic), events and errors versions, changing to relative imports, jest dev dependency, js-quic tsconfig [ci skip] fix: tests imports, using @ [ci skip] chore: removed sysexits chore: fix default exports for callers and handlers Fixed index for handlers fix: remove @matrixai/id fix: remove @matrixai/id and ix chore : diagram [ci skip] chore : lintfix fix: errors now extend AbstractError [ci skip] fix: undoing fix #1 [ci skip] replacd errorCode with just code, references std error codes from rpc spec feat: events based createDestroy [ci skip] chore: img format fix [ci skip] chore: img in README.md [ci skip] feat: allows the user to pass in a generator function if the user wishes to specify a particular id [ci skip] fix: fixes #7 * Removes graceTimer and related jests chore: idGen name change. idGen parameter in creation and constructor. No longer optional. Only defaulted in one place. wip: added idgen to jests, was missing. [ci skip] wip: reimported ix, since a few tests rely on it. removed, matrixai/id wip: jests for #4 removed, matrixai/id wip: * Implements custom RPC Error codes. * Fixed jest for concurrent timeouts * All errors now have a cause * All errors now use custom error codes. wip: *Client uses ctx timer now wip: *Jests to test concurrency wip: *custom RPC based errors for RPC Client, now all errors have a cause and an error message WIP: * Refactor out sensitiveReplacer WIP: * Refactor out sensitiveReplacer WIP: * Update to latest async init and events * set default timeout to Infinity * jest to check server and client with infinite timeout * fixing jests which broke after changing default timeout to infinity WIP: f1x #4 WIP: f1x #11 f1x: parameterize toError, fromError and replacer wip: tofrom fix: parameterize toError, fromError and replacer fix: Makes concurrent jests non deterministic * Related #4 fix: parameterize replacer toError and fromError, change fromError to return JSONValue, stringify fromError usages * Related #10 fix: Converted global state for fromError to handle it internally. *Related: #10 Reviewed-by: @tegefaulkes [ci skip] chore: Jests for fromError and toError, and using a custom replacer. related: #10 [ci skip] --- README.md | 3 + images/diagram_encapuslated.svg | 17 + package.json | 9 +- src/RPCClient.ts | 114 ++- src/RPCServer.ts | 172 ++-- src/callers.ts | 53 -- src/callers/Caller.ts | 13 + src/callers/ClientCaller.ts | 11 + src/callers/DuplexCaller.ts | 11 + src/callers/RawCaller.ts | 7 + src/callers/ServerCaller.ts | 11 + src/callers/UnaryCaller.ts | 11 + src/callers/index.ts | 6 + src/errors/errors.ts | 174 ++-- src/errors/index.ts | 1 - src/errors/sysexits.ts | 91 -- src/events.ts | 74 +- src/handlers.ts | 99 -- src/handlers/ClientHandler.ts | 21 + src/handlers/DuplexHandler.ts | 26 + src/handlers/Handler.ts | 19 + src/handlers/RawHandler.ts | 20 + src/handlers/ServerHandler.ts | 21 + src/handlers/UnaryHandler.ts | 21 + src/handlers/index.ts | 6 + src/index.ts | 4 +- src/types.ts | 28 +- src/utils/middleware.ts | 2 +- src/utils/utils.ts | 137 +-- tests/RPC.test.ts | 1046 ++++++++++++++++++++++ tests/{rpc => }/RPCClient.test.ts | 65 +- tests/{rpc => }/RPCServer.test.ts | 308 +++---- tests/rpc/RPC.test.ts | 555 ------------ tests/{rpc => }/utils.ts | 23 +- tests/{rpc => }/utils/middleware.test.ts | 8 +- tests/{rpc => }/utils/utils.test.ts | 2 +- tsconfig.json | 2 +- 37 files changed, 1944 insertions(+), 1247 deletions(-) create mode 100644 images/diagram_encapuslated.svg delete mode 100644 src/callers.ts create mode 100644 src/callers/Caller.ts create mode 100644 src/callers/ClientCaller.ts create mode 100644 src/callers/DuplexCaller.ts create mode 100644 src/callers/RawCaller.ts create mode 100644 src/callers/ServerCaller.ts create mode 100644 src/callers/UnaryCaller.ts create mode 100644 src/callers/index.ts delete mode 100644 src/errors/sysexits.ts delete mode 100644 src/handlers.ts create mode 100644 src/handlers/ClientHandler.ts create mode 100644 src/handlers/DuplexHandler.ts create mode 100644 src/handlers/Handler.ts create mode 100644 src/handlers/RawHandler.ts create mode 100644 src/handlers/ServerHandler.ts create mode 100644 src/handlers/UnaryHandler.ts create mode 100644 src/handlers/index.ts create mode 100644 tests/RPC.test.ts rename tests/{rpc => }/RPCClient.test.ts (96%) rename tests/{rpc => }/RPCServer.test.ts (85%) delete mode 100644 tests/rpc/RPC.test.ts rename tests/{rpc => }/utils.ts (93%) rename tests/{rpc => }/utils/middleware.test.ts (93%) rename tests/{rpc => }/utils/utils.test.ts (93%) diff --git a/README.md b/README.md index 4032c58..5706852 100644 --- a/README.md +++ b/README.md @@ -66,3 +66,6 @@ npm publish --access public git push git push --tags ``` + +Domains Diagram: +![diagram_encapuslated.svg](images%2Fdiagram_encapuslated.svg) diff --git a/images/diagram_encapuslated.svg b/images/diagram_encapuslated.svg new file mode 100644 index 0000000..bad2f68 --- /dev/null +++ b/images/diagram_encapuslated.svg @@ -0,0 +1,17 @@ + + + + + + + + RPCCLientHandlers1treamCallerMiddlwarerequestdata transformationstreamFactoryJsonRPCRequestUint8ArraymethodsProxyCall TypeTimer attachedRPCCLienthandleStreamHandlerAbortController Timerdata transformationResponseMiddlware \ No newline at end of file diff --git a/package.json b/package.json index 2155365..f9303d9 100644 --- a/package.json +++ b/package.json @@ -53,14 +53,15 @@ "ts-node": "^10.9.1", "tsconfig-paths": "^3.9.0", "typedoc": "^0.23.21", - "typescript": "^4.9.3" + "typescript": "^4.9.3", + "@fast-check/jest": "^1.1.0" }, "dependencies": { - "@fast-check/jest": "^1.7.2", - "@matrixai/async-init": "^1.9.1", + "@matrixai/async-init": "^1.9.4", "@matrixai/contexts": "^1.2.0", - "@matrixai/id": "^3.3.6", "@matrixai/logger": "^3.1.0", + "@matrixai/errors": "^1.2.0", + "@matrixai/events": "^3.2.0", "@streamparser/json": "^0.0.17", "ix": "^5.0.0" } diff --git a/src/RPCClient.ts b/src/RPCClient.ts index 6d305aa..6d19363 100644 --- a/src/RPCClient.ts +++ b/src/RPCClient.ts @@ -8,27 +8,45 @@ import type { RPCStream, JSONRPCResponseResult, } from './types'; -import type { JSONValue } from './types'; +import type { JSONValue, IdGen } from './types'; import type { JSONRPCRequest, JSONRPCResponse, MiddlewareFactory, MapCallers, } from './types'; +import type { ErrorRPCRemote } from './errors'; import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; import Logger from '@matrixai/logger'; import { Timer } from '@matrixai/timer'; +import { createDestroy } from '@matrixai/async-init'; import * as rpcUtilsMiddleware from './utils/middleware'; import * as rpcErrors from './errors'; import * as rpcUtils from './utils/utils'; import { promise } from './utils'; -import { never } from './errors'; +import { ErrorRPCStreamEnded, never } from './errors'; +import * as events from './events'; const timerCleanupReasonSymbol = Symbol('timerCleanUpReasonSymbol'); -// eslint-disable-next-line -interface RPCClient extends CreateDestroy {} -@CreateDestroy() +/** + * Events: + * - {@link events.Event} + */ +interface RPCClient + extends createDestroy.CreateDestroy {} +/** + * You must provide an error handler `addEventListener('error')`. + * Otherwise, errors will just be ignored. + * + * Events: + * - {@link events.EventRPCClientDestroy} + * - {@link events.EventRPCClientDestroyed} + */ +@createDestroy.CreateDestroy({ + eventDestroy: events.EventRPCClientDestroy, + eventDestroyed: events.EventRPCClientDestroyed, +}) class RPCClient { /** * @param obj @@ -49,8 +67,9 @@ class RPCClient { manifest, streamFactory, middlewareFactory = rpcUtilsMiddleware.defaultClientMiddlewareWrapper(), - streamKeepAliveTimeoutTime = 60_000, // 1 minute + streamKeepAliveTimeoutTime = Infinity, // 1 minute logger = new Logger(this.name), + idGen = () => Promise.resolve(null), }: { manifest: M; streamFactory: StreamFactory; @@ -62,6 +81,8 @@ class RPCClient { >; streamKeepAliveTimeoutTime?: number; logger?: Logger; + idGen: IdGen; + toError?: (errorData, metadata?: JSONValue) => ErrorRPCRemote; }) { logger.info(`Creating ${this.name}`); const rpcClient = new this({ @@ -70,11 +91,13 @@ class RPCClient { middlewareFactory, streamKeepAliveTimeoutTime: streamKeepAliveTimeoutTime, logger, + idGen, }); logger.info(`Created ${this.name}`); return rpcClient; } - + protected onTimeoutCallback?: () => void; + protected idGen: IdGen; protected logger: Logger; protected streamFactory: StreamFactory; protected middlewareFactory: MiddlewareFactory< @@ -84,6 +107,10 @@ class RPCClient { Uint8Array >; protected callerTypes: Record; + toError: (errorData: any, metadata?: JSONValue) => Error; + public registerOnTimeoutCallback(callback: () => void) { + this.onTimeoutCallback = callback; + } // Method proxies public readonly streamKeepAliveTimeoutTime: number; public readonly methodsProxy = new Proxy( @@ -116,6 +143,8 @@ class RPCClient { middlewareFactory, streamKeepAliveTimeoutTime, logger, + idGen = () => Promise.resolve(null), + toError, }: { manifest: M; streamFactory: StreamFactory; @@ -127,20 +156,39 @@ class RPCClient { >; streamKeepAliveTimeoutTime: number; logger: Logger; + idGen: IdGen; + toError?: (errorData, metadata?: JSONValue) => ErrorRPCRemote; }) { + this.idGen = idGen; this.callerTypes = rpcUtils.getHandlerTypes(manifest); this.streamFactory = streamFactory; this.middlewareFactory = middlewareFactory; this.streamKeepAliveTimeoutTime = streamKeepAliveTimeoutTime; this.logger = logger; + this.toError = toError || rpcUtils.toError; } - public async destroy(): Promise { + public async destroy({ + errorCode = rpcErrors.JSONRPCErrorCode.RPCStopping, + errorMessage = '', + force = true, + }: { + errorCode?: number; + errorMessage?: string; + force?: boolean; + } = {}): Promise { this.logger.info(`Destroying ${this.constructor.name}`); + + // You can dispatch an event before the actual destruction starts + this.dispatchEvent(new events.EventRPCClientDestroy()); + + // Dispatch an event after the client has been destroyed + this.dispatchEvent(new events.EventRPCClientDestroyed()); + this.logger.info(`Destroyed ${this.constructor.name}`); } - @ready(new rpcErrors.ErrorRPCDestroyed()) + @ready(new rpcErrors.ErrorRPCCallerFailed()) public get methods(): MapCallers { return this.methodsProxy as MapCallers; } @@ -154,7 +202,7 @@ class RPCClient { * the provided I type. * @param ctx - ContextTimed used for timeouts and cancellation. */ - @ready(new rpcErrors.ErrorRPCDestroyed()) + @ready(new rpcErrors.ErrorMissingCaller()) public async unaryCaller( method: string, parameters: I, @@ -167,7 +215,9 @@ class RPCClient { await writer.write(parameters); const output = await reader.read(); if (output.done) { - throw new rpcErrors.ErrorRPCMissingResponse(); + throw new rpcErrors.ErrorMissingCaller('Missing response', { + cause: ctx.signal?.reason, + }); } await reader.cancel(); await writer.close(); @@ -189,7 +239,7 @@ class RPCClient { * the provided I type. * @param ctx - ContextTimed used for timeouts and cancellation. */ - @ready(new rpcErrors.ErrorRPCDestroyed()) + @ready(new rpcErrors.ErrorRPCCallerFailed()) public async serverStreamCaller( method: string, parameters: I, @@ -218,7 +268,7 @@ class RPCClient { * @param method - Method name of the RPC call * @param ctx - ContextTimed used for timeouts and cancellation. */ - @ready(new rpcErrors.ErrorRPCDestroyed()) + @ready(new rpcErrors.ErrorRPCCallerFailed()) public async clientStreamCaller( method: string, ctx: Partial = {}, @@ -230,7 +280,9 @@ class RPCClient { const reader = callerInterface.readable.getReader(); const output = reader.read().then(({ value, done }) => { if (done) { - throw new rpcErrors.ErrorRPCMissingResponse(); + throw new rpcErrors.ErrorMissingCaller('Missing response', { + cause: ctx.signal?.reason, + }); } return value; }); @@ -251,7 +303,7 @@ class RPCClient { * @param method - Method name of the RPC call * @param ctx - ContextTimed used for timeouts and cancellation. */ - @ready(new rpcErrors.ErrorRPCDestroyed()) + @ready(new rpcErrors.ErrorRPCCallerFailed()) public async duplexStreamCaller( method: string, ctx: Partial = {}, @@ -294,10 +346,16 @@ class RPCClient { signal.addEventListener('abort', abortRacePromHandler); }; // Setting up abort events for timeout - const timeoutError = new rpcErrors.ErrorRPCTimedOut(); + const timeoutError = new rpcErrors.ErrorRPCTimedOut( + 'Error RPC has timed out', + { cause: ctx.signal?.reason }, + ); void timer.then( () => { abortController.abort(timeoutError); + if (this.onTimeoutCallback) { + this.onTimeoutCallback(); + } }, () => {}, // Ignore cancellation error ); @@ -310,13 +368,17 @@ class RPCClient { } catch (e) { cleanUp(); void streamFactoryProm.then((stream) => - stream.cancel(Error('TMP stream timed out early')), + stream.cancel(ErrorRPCStreamEnded), ); throw e; } void timer.then( () => { - rpcStream.cancel(new rpcErrors.ErrorRPCTimedOut()); + rpcStream.cancel( + new rpcErrors.ErrorRPCTimedOut('RPC has timed out', { + cause: ctx.signal?.reason, + }), + ); }, () => {}, // Ignore cancellation error ); @@ -379,8 +441,9 @@ class RPCClient { * single RPC message that is sent to specify the method for the RPC call. * Any metadata of extra parameters is provided here. * @param ctx - ContextTimed used for timeouts and cancellation. + * @param id - Id is generated only once, and used throughout the stream for the rest of the communication */ - @ready(new rpcErrors.ErrorRPCDestroyed()) + @ready(new rpcErrors.ErrorRPCCallerFailed()) public async rawStreamCaller( method: string, headerParams: JSONValue, @@ -430,7 +493,9 @@ class RPCClient { signal.addEventListener('abort', abortRacePromHandler); }; // Setting up abort events for timeout - const timeoutError = new rpcErrors.ErrorRPCTimedOut(); + const timeoutError = new rpcErrors.ErrorRPCTimedOut('RPC has timed out', { + cause: ctx.signal?.reason, + }); void timer.then( () => { abortController.abort(timeoutError); @@ -457,11 +522,12 @@ class RPCClient { abortProm.p, ]); const tempWriter = rpcStream.writable.getWriter(); + const id = await this.idGen(); const header: JSONRPCRequestMessage = { jsonrpc: '2.0', method, params: headerParams, - id: null, + id, }; await tempWriter.write(Buffer.from(JSON.stringify(header))); tempWriter.releaseLock(); @@ -484,11 +550,13 @@ class RPCClient { ...(rpcStream.meta ?? {}), command: method, }; - throw rpcUtils.toError(messageValue.error.data, metadata); + throw this.toError(messageValue.error.data, metadata); } leadingMessage = messageValue; } catch (e) { - rpcStream.cancel(Error('TMP received error in leading response')); + rpcStream.cancel( + new ErrorRPCStreamEnded('RPC Stream Ended', { cause: e }), + ); throw e; } tempReader.releaseLock(); diff --git a/src/RPCServer.ts b/src/RPCServer.ts index f38b344..71d8966 100644 --- a/src/RPCServer.ts +++ b/src/RPCServer.ts @@ -15,24 +15,24 @@ import type { MiddlewareFactory, } from './types'; import type { JSONValue } from './types'; +import type { IdGen } from './types'; import { ReadableStream, TransformStream } from 'stream/web'; import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; import Logger from '@matrixai/logger'; import { PromiseCancellable } from '@matrixai/async-cancellable'; import { Timer } from '@matrixai/timer'; -import { - ClientHandler, - DuplexHandler, - RawHandler, - ServerHandler, - UnaryHandler, -} from './handlers'; +import { createDestroy } from '@matrixai/async-init'; +import { RawHandler } from './handlers'; +import { DuplexHandler } from './handlers'; +import { ServerHandler } from './handlers'; +import { UnaryHandler } from './handlers'; +import { ClientHandler } from './handlers'; import * as rpcEvents from './events'; -import * as rpcUtils from './utils/utils'; +import * as rpcUtils from './utils'; import * as rpcErrors from './errors'; -import * as rpcUtilsMiddleware from './utils/middleware'; -import sysexits from './errors/sysexits'; -import { never } from './errors'; +import * as rpcUtilsMiddleware from './utils'; +import { ErrorHandlerAborted, JSONRPCErrorCode, never } from './errors'; +import * as events from './events'; const cleanupReason = Symbol('CleanupReason'); @@ -43,8 +43,19 @@ const cleanupReason = Symbol('CleanupReason'); * Events: * - error */ -interface RPCServer extends CreateDestroy {} -@CreateDestroy() +interface RPCServer extends createDestroy.CreateDestroy {} +/** + * You must provide an error handler `addEventListener('error')`. + * Otherwise, errors will just be ignored. + * + * Events: + * - {@link events.EventRPCServerDestroy} + * - {@link events.EventRPCServerDestroyed} + */ +@createDestroy.CreateDestroy({ + eventDestroy: events.EventRPCServerDestroy, + eventDestroyed: events.EventRPCServerDestroyed, +}) class RPCServer extends EventTarget { /** * Creates RPC server. @@ -71,9 +82,11 @@ class RPCServer extends EventTarget { manifest, middlewareFactory = rpcUtilsMiddleware.defaultServerMiddlewareWrapper(), sensitive = false, - handlerTimeoutTime = 60_000, // 1 minute - handlerTimeoutGraceTime = 2_000, // 2 seconds + handlerTimeoutTime = Infinity, // 1 minute logger = new Logger(this.name), + idGen = () => Promise.resolve(null), + fromError = rpcUtils.fromError, + replacer = rpcUtils.replacer, }: { manifest: ServerManifest; middlewareFactory?: MiddlewareFactory< @@ -84,8 +97,10 @@ class RPCServer extends EventTarget { >; sensitive?: boolean; handlerTimeoutTime?: number; - handlerTimeoutGraceTime?: number; logger?: Logger; + idGen: IdGen; + fromError?: (error: Error) => JSONValue; + replacer?: (key: string, value: any) => any; }): Promise { logger.info(`Creating ${this.name}`); const rpcServer = new this({ @@ -93,34 +108,43 @@ class RPCServer extends EventTarget { middlewareFactory, sensitive, handlerTimeoutTime, - handlerTimeoutGraceTime, logger, + idGen, + fromError, + replacer, }); logger.info(`Created ${this.name}`); return rpcServer; } - + protected onTimeoutCallback?: () => void; + protected idGen: IdGen; protected logger: Logger; protected handlerMap: Map = new Map(); protected defaultTimeoutMap: Map = new Map(); protected handlerTimeoutTime: number; - protected handlerTimeoutGraceTime: number; protected activeStreams: Set> = new Set(); protected sensitive: boolean; + protected fromError: (error: Error, sensitive?: boolean) => JSONValue; + protected replacer: (key: string, value: any) => any; protected middlewareFactory: MiddlewareFactory< JSONRPCRequest, Uint8Array, Uint8Array, JSONRPCResponseResult >; - + // Function to register a callback for timeout + public registerOnTimeoutCallback(callback: () => void) { + this.onTimeoutCallback = callback; + } public constructor({ manifest, middlewareFactory, sensitive, - handlerTimeoutTime = 60_000, // 1 minuet - handlerTimeoutGraceTime = 2_000, // 2 seconds + handlerTimeoutTime = Infinity, // 1 minuet logger, + idGen = () => Promise.resolve(null), + fromError = rpcUtils.fromError, + replacer = rpcUtils.replacer, }: { manifest: ServerManifest; @@ -131,16 +155,18 @@ class RPCServer extends EventTarget { JSONRPCResponseResult >; handlerTimeoutTime?: number; - handlerTimeoutGraceTime?: number; sensitive: boolean; logger: Logger; + idGen: IdGen; + fromError?: (error: Error) => JSONValue; + replacer?: (key: string, value: any) => any; }) { super(); for (const [key, manifestItem] of Object.entries(manifest)) { if (manifestItem instanceof RawHandler) { this.registerRawStreamHandler( key, - manifestItem.handle.bind(manifestItem), + manifestItem.handle, manifestItem.timeout, ); continue; @@ -148,7 +174,7 @@ class RPCServer extends EventTarget { if (manifestItem instanceof DuplexHandler) { this.registerDuplexStreamHandler( key, - manifestItem.handle.bind(manifestItem), + manifestItem.handle, manifestItem.timeout, ); continue; @@ -156,7 +182,7 @@ class RPCServer extends EventTarget { if (manifestItem instanceof ServerHandler) { this.registerServerStreamHandler( key, - manifestItem.handle.bind(manifestItem), + manifestItem.handle, manifestItem.timeout, ); continue; @@ -164,7 +190,7 @@ class RPCServer extends EventTarget { if (manifestItem instanceof ClientHandler) { this.registerClientStreamHandler( key, - manifestItem.handle.bind(manifestItem), + manifestItem.handle, manifestItem.timeout, ); continue; @@ -172,7 +198,7 @@ class RPCServer extends EventTarget { if (manifestItem instanceof ClientHandler) { this.registerClientStreamHandler( key, - manifestItem.handle.bind(manifestItem), + manifestItem.handle, manifestItem.timeout, ); continue; @@ -180,31 +206,40 @@ class RPCServer extends EventTarget { if (manifestItem instanceof UnaryHandler) { this.registerUnaryHandler( key, - manifestItem.handle.bind(manifestItem), + manifestItem.handle, manifestItem.timeout, ); continue; } never(); } + this.idGen = idGen; this.middlewareFactory = middlewareFactory; this.sensitive = sensitive; this.handlerTimeoutTime = handlerTimeoutTime; - this.handlerTimeoutGraceTime = handlerTimeoutGraceTime; this.logger = logger; + this.fromError = fromError || rpcUtils.fromError; + this.replacer = replacer || rpcUtils.replacer; } public async destroy(force: boolean = true): Promise { + // Log and dispatch an event before starting the destruction this.logger.info(`Destroying ${this.constructor.name}`); - // Stopping any active steams + this.dispatchEvent(new events.EventRPCServerDestroy()); + + // Your existing logic for stopping active streams and other cleanup if (force) { for await (const [activeStream] of this.activeStreams.entries()) { activeStream.cancel(new rpcErrors.ErrorRPCStopping()); } } + for await (const [activeStream] of this.activeStreams.entries()) { await activeStream; } + + // Log and dispatch an event after the destruction has been completed + this.dispatchEvent(new events.EventRPCServerDestroyed()); this.logger.info(`Destroyed ${this.constructor.name}`); } @@ -232,6 +267,12 @@ class RPCServer extends EventTarget { * @param handler - The handler takes an input async iterable and returns an output async iterable. * @param timeout */ + /** + * The ID is generated only once when the function is called and stored in the id variable. + * the ID is associated with the entire stream + * Every response (whether successful or an error) produced within this stream will have the + * same ID, which is consistent with the originating request. + */ protected registerDuplexStreamHandler< I extends JSONValue, O extends JSONValue, @@ -272,6 +313,7 @@ class RPCServer extends EventTarget { // Reverse from the server to the client const reverseStream = middleware.reverse.writable; // Generator derived from handler + const id = await this.idGen(); const outputGen = async function* (): AsyncGenerator { if (signal.aborted) throw signal.reason; // Input generator derived from the forward stream @@ -290,7 +332,7 @@ class RPCServer extends EventTarget { const responseMessage: JSONRPCResponseResult = { jsonrpc: '2.0', result: response, - id: null, + id, }; yield responseMessage; } @@ -307,14 +349,14 @@ class RPCServer extends EventTarget { controller.enqueue(value); } catch (e) { const rpcError: JSONRPCError = { - code: e.exitCode ?? sysexits.UNKNOWN, + code: e.exitCode ?? JSONRPCErrorCode.InternalError, message: e.description ?? '', - data: rpcUtils.fromError(e, this.sensitive), + data: JSON.stringify(this.fromError(e), this.replacer), }; const rpcErrorMessage: JSONRPCResponseError = { jsonrpc: '2.0', error: rpcError, - id: null, + id, }; controller.enqueue(rpcErrorMessage); // Clean up the input stream here, ignore error if already ended @@ -331,7 +373,7 @@ class RPCServer extends EventTarget { cancel: async (reason) => { this.dispatchEvent( new rpcEvents.RPCErrorEvent({ - detail: new rpcErrors.ErrorRPCOutputStreamError( + detail: new rpcErrors.ErrorRPCStreamEnded( 'Stream has been cancelled', { cause: reason, @@ -416,7 +458,10 @@ class RPCServer extends EventTarget { this.registerDuplexStreamHandler(method, wrapperDuplex, timeout); } - @ready(new rpcErrors.ErrorRPCDestroyed()) + /** + * ID is associated with the stream, not individual messages. + */ + @ready(new rpcErrors.ErrorRPCHandlerFailed()) public handleStream(rpcStream: RPCStream) { // This will take a buffer stream of json messages and set up service // handling for it. @@ -427,27 +472,14 @@ class RPCServer extends EventTarget { delay: this.handlerTimeoutTime, handler: () => { abortController.abort(new rpcErrors.ErrorRPCTimedOut()); + if (this.onTimeoutCallback) { + this.onTimeoutCallback(); + } }, }); - // Grace timer is triggered with any abort signal. - // If grace timer completes then it will cause the RPCStream to end with - // `RPCStream.cancel(reason)`. - let graceTimer: Timer | undefined; - const handleAbort = () => { - const graceTimer = new Timer({ - delay: this.handlerTimeoutGraceTime, - handler: () => { - rpcStream.cancel(abortController.signal.reason); - }, - }); - void graceTimer - .catch(() => {}) // Ignore cancellation error - .finally(() => { - abortController.signal.removeEventListener('abort', handleAbort); - }); - }; - abortController.signal.addEventListener('abort', handleAbort); + const prom = (async () => { + const id = await this.idGen(); const headTransformStream = rpcUtilsMiddleware.binaryToJsonMessageStream( rpcUtils.parseJSONRPCRequest, ); @@ -474,9 +506,7 @@ class RPCServer extends EventTarget { await rpcStream.writable.abort(reason); await inputStreamEndProm; timer.cancel(cleanupReason); - graceTimer?.cancel(cleanupReason); await timer.catch(() => {}); - await graceTimer?.catch(() => {}); }; // Read a single empty value to consume the first message const reader = headTransformStream.readable.getReader(); @@ -500,9 +530,7 @@ class RPCServer extends EventTarget { ); await inputStreamEndProm; timer.cancel(cleanupReason); - graceTimer?.cancel(cleanupReason); await timer.catch(() => {}); - await graceTimer?.catch(() => {}); this.dispatchEvent( new rpcEvents.RPCErrorEvent({ detail: new rpcErrors.ErrorRPCOutputStreamError( @@ -521,13 +549,14 @@ class RPCServer extends EventTarget { // 1. The timeout timer resolves before the first message // 2. the stream ends before the first message if (headerMessage == null) { - const newErr = new rpcErrors.ErrorRPCHandlerFailed( + const newErr = new rpcErrors.ErrorRPCTimedOut( 'Timed out waiting for header', + { cause: new rpcErrors.ErrorRPCStreamEnded() }, ); await cleanUp(newErr); this.dispatchEvent( new rpcEvents.RPCErrorEvent({ - detail: new rpcErrors.ErrorRPCOutputStreamError( + detail: new rpcErrors.ErrorRPCTimedOut( 'Timed out waiting for header', { cause: newErr, @@ -538,7 +567,7 @@ class RPCServer extends EventTarget { return; } if (headerMessage.done) { - const newErr = new rpcErrors.ErrorRPCHandlerFailed('Missing header'); + const newErr = new rpcErrors.ErrorMissingHeader('Missing header'); await cleanUp(newErr); this.dispatchEvent( new rpcEvents.RPCErrorEvent({ @@ -556,7 +585,11 @@ class RPCServer extends EventTarget { return; } if (abortController.signal.aborted) { - await cleanUp(new rpcErrors.ErrorRPCHandlerFailed('Aborted')); + await cleanUp( + new rpcErrors.ErrorHandlerAborted('Aborted', { + cause: new ErrorHandlerAborted(), + }), + ); return; } // Setting up Timeout logic @@ -580,22 +613,19 @@ class RPCServer extends EventTarget { ); } catch (e) { const rpcError: JSONRPCError = { - code: e.exitCode ?? sysexits.UNKNOWN, + code: e.exitCode ?? JSONRPCErrorCode.InternalError, message: e.description ?? '', - data: rpcUtils.fromError(e, this.sensitive), + data: JSON.stringify(this.fromError(e), this.replacer), }; const rpcErrorMessage: JSONRPCResponseError = { jsonrpc: '2.0', error: rpcError, - id: null, + id, }; await headerWriter.write(Buffer.from(JSON.stringify(rpcErrorMessage))); await headerWriter.close(); // Clean up and return timer.cancel(cleanupReason); - abortController.signal.removeEventListener('abort', handleAbort); - graceTimer?.cancel(cleanupReason); - abortController.abort(new rpcErrors.ErrorRPCStreamEnded()); rpcStream.cancel(Error('TMP header message was an error')); return; } @@ -606,7 +636,7 @@ class RPCServer extends EventTarget { const leadingMessage: JSONRPCResponseResult = { jsonrpc: '2.0', result: leadingResult, - id: null, + id, }; await headerWriter.write(Buffer.from(JSON.stringify(leadingMessage))); } @@ -618,8 +648,6 @@ class RPCServer extends EventTarget { this.logger.info(`Handled stream with method (${method})`); // Cleaning up abort and timer timer.cancel(cleanupReason); - abortController.signal.removeEventListener('abort', handleAbort); - graceTimer?.cancel(cleanupReason); abortController.abort(new rpcErrors.ErrorRPCStreamEnded()); })(); const handlerProm = PromiseCancellable.from(prom, abortController).finally( diff --git a/src/callers.ts b/src/callers.ts deleted file mode 100644 index 4a92988..0000000 --- a/src/callers.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { HandlerType } from './types'; -import type { JSONValue } from './types'; - -abstract class Caller< - Input extends JSONValue = JSONValue, - Output extends JSONValue = JSONValue, -> { - protected _inputType: Input; - protected _outputType: Output; - // Need this to distinguish the classes when inferring types - abstract type: HandlerType; -} - -class RawCaller extends Caller { - public type: 'RAW' = 'RAW' as const; -} - -class DuplexCaller< - Input extends JSONValue = JSONValue, - Output extends JSONValue = JSONValue, -> extends Caller { - public type: 'DUPLEX' = 'DUPLEX' as const; -} - -class ServerCaller< - Input extends JSONValue = JSONValue, - Output extends JSONValue = JSONValue, -> extends Caller { - public type: 'SERVER' = 'SERVER' as const; -} - -class ClientCaller< - Input extends JSONValue = JSONValue, - Output extends JSONValue = JSONValue, -> extends Caller { - public type: 'CLIENT' = 'CLIENT' as const; -} - -class UnaryCaller< - Input extends JSONValue = JSONValue, - Output extends JSONValue = JSONValue, -> extends Caller { - public type: 'UNARY' = 'UNARY' as const; -} - -export { - Caller, - RawCaller, - DuplexCaller, - ServerCaller, - ClientCaller, - UnaryCaller, -}; diff --git a/src/callers/Caller.ts b/src/callers/Caller.ts new file mode 100644 index 0000000..ddc54a8 --- /dev/null +++ b/src/callers/Caller.ts @@ -0,0 +1,13 @@ +import type { HandlerType, JSONValue } from '../types'; + +abstract class Caller< + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> { + protected _inputType: Input; + protected _outputType: Output; + // Need this to distinguish the classes when inferring types + abstract type: HandlerType; +} + +export default Caller; diff --git a/src/callers/ClientCaller.ts b/src/callers/ClientCaller.ts new file mode 100644 index 0000000..7fb44da --- /dev/null +++ b/src/callers/ClientCaller.ts @@ -0,0 +1,11 @@ +import type { JSONValue } from '../types'; +import Caller from './Caller'; + +class ClientCaller< + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Caller { + public type: 'CLIENT' = 'CLIENT' as const; +} + +export default ClientCaller; diff --git a/src/callers/DuplexCaller.ts b/src/callers/DuplexCaller.ts new file mode 100644 index 0000000..4c079b3 --- /dev/null +++ b/src/callers/DuplexCaller.ts @@ -0,0 +1,11 @@ +import type { JSONValue } from '../types'; +import Caller from './Caller'; + +class DuplexCaller< + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Caller { + public type: 'DUPLEX' = 'DUPLEX' as const; +} + +export default DuplexCaller; diff --git a/src/callers/RawCaller.ts b/src/callers/RawCaller.ts new file mode 100644 index 0000000..a4721cf --- /dev/null +++ b/src/callers/RawCaller.ts @@ -0,0 +1,7 @@ +import type { JSONValue } from '../types'; +import Caller from './Caller'; +class RawCaller extends Caller { + public type: 'RAW' = 'RAW' as const; +} + +export default RawCaller; diff --git a/src/callers/ServerCaller.ts b/src/callers/ServerCaller.ts new file mode 100644 index 0000000..11a9fe9 --- /dev/null +++ b/src/callers/ServerCaller.ts @@ -0,0 +1,11 @@ +import type { JSONValue } from '../types'; +import Caller from './Caller'; + +class ServerCaller< + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Caller { + public type: 'SERVER' = 'SERVER' as const; +} + +export default ServerCaller; diff --git a/src/callers/UnaryCaller.ts b/src/callers/UnaryCaller.ts new file mode 100644 index 0000000..c446073 --- /dev/null +++ b/src/callers/UnaryCaller.ts @@ -0,0 +1,11 @@ +import type { JSONValue } from '../types'; +import Caller from './Caller'; + +class UnaryCaller< + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Caller { + public type: 'UNARY' = 'UNARY' as const; +} + +export default UnaryCaller; diff --git a/src/callers/index.ts b/src/callers/index.ts new file mode 100644 index 0000000..17e8c87 --- /dev/null +++ b/src/callers/index.ts @@ -0,0 +1,6 @@ +export { default as Caller } from './Caller'; +export { default as ClientCaller } from './ClientCaller'; +export { default as DuplexCaller } from './DuplexCaller'; +export { default as RawCaller } from './RawCaller'; +export { default as ServerCaller } from './ServerCaller'; +export { default as UnaryCaller } from './UnaryCaller'; diff --git a/src/errors/errors.ts b/src/errors/errors.ts index b0039d5..2acc942 100644 --- a/src/errors/errors.ts +++ b/src/errors/errors.ts @@ -1,55 +1,72 @@ import type { Class } from '@matrixai/errors'; import type { JSONValue } from '@/types'; -import sysexits from './sysexits'; +import { AbstractError } from '@matrixai/errors'; +const enum JSONRPCErrorCode { + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603, + HandlerNotFound = -32000, + RPCStopping = -32001, + RPCDestroyed = -32002, + RPCMessageLength = -32003, + RPCMissingResponse = -32004, + RPCOutputStreamError = -32005, + RPCRemote = -32006, + RPCStreamEnded = -32007, + RPCTimedOut = -32008, + RPCConnectionLocal = -32010, + RPCConnectionPeer = -32011, + RPCConnectionKeepAliveTimeOut = -32012, + RPCConnectionInternal = -32013, + MissingHeader = -32014, + HandlerAborted = -32015, + MissingCaller = -32016, +} interface RPCError extends Error { - exitCode?: number; + code?: number; } - -class ErrorRPC extends Error implements RPCError { +class ErrorRPC extends AbstractError implements RPCError { + private _description: string = 'Generic Error'; constructor(message?: string) { super(message); - this.name = 'ErrorRPC'; - this.description = 'Generic Error'; } - exitCode?: number; - description?: string; + code?: number; + + get description(): string { + return this._description; + } + set description(value: string) { + this._description = value; + } } class ErrorRPCDestroyed extends ErrorRPC { constructor(message?: string) { super(message); // Call the parent constructor - this.name = 'ErrorRPCDestroyed'; // Optionally set a specific name this.description = 'Rpc is destroyed'; // Set the specific description - this.exitCode = sysexits.USAGE; // Set the exit code + this.code = JSONRPCErrorCode.MethodNotFound; } } class ErrorRPCParse extends ErrorRPC { static description = 'Failed to parse Buffer stream'; - exitCode = sysexits.SOFTWARE; - cause: Error | undefined; // Added this line to hold the cause constructor(message?: string, options?: { cause: Error }) { super(message); // Call the parent constructor - this.name = 'ErrorRPCParse'; // Optionally set a specific name this.description = 'Failed to parse Buffer stream'; // Set the specific description - this.exitCode = sysexits.SOFTWARE; // Set the exit code - - // Set the cause if provided in options - if (options && options.cause) { - this.cause = options.cause; - } + this.code = JSONRPCErrorCode.ParseError; } } class ErrorRPCStopping extends ErrorRPC { constructor(message?: string) { super(message); // Call the parent constructor - this.name = 'ErrorRPCStopping'; // Optionally set a specific name this.description = 'Rpc is stopping'; // Set the specific description - this.exitCode = sysexits.USAGE; // Set the exit code + this.code = JSONRPCErrorCode.RPCStopping; } } @@ -57,64 +74,75 @@ class ErrorRPCStopping extends ErrorRPC { * This is an internal error, it should not reach the top level. */ class ErrorRPCHandlerFailed extends ErrorRPC { - cause: Error | undefined; - constructor(message?: string, options?: { cause: Error }) { super(message); // Call the parent constructor - this.name = 'ErrorRPCHandlerFailed'; // Optionally set a specific name this.description = 'Failed to handle stream'; // Set the specific description - this.exitCode = sysexits.SOFTWARE; // Set the exit code - - // Set the cause if provided in options - if (options && options.cause) { - this.cause = options.cause; - } + this.code = JSONRPCErrorCode.HandlerNotFound; + } +} +class ErrorRPCCallerFailed extends ErrorRPC { + constructor(message?: string, options?: { cause: Error }) { + super(message); // Call the parent constructor + this.description = 'Failed to call stream'; // Set the specific description + this.code = JSONRPCErrorCode.MissingCaller; + } +} +class ErrorMissingCaller extends ErrorRPC { + constructor(message?: string, options?: { cause: Error }) { + super(message); // Call the parent constructor + this.description = 'Header information is missing'; // Set the specific description + this.code = JSONRPCErrorCode.MissingCaller; + } +} +class ErrorMissingHeader extends ErrorRPC { + constructor(message?: string, options?: { cause: Error }) { + super(message); // Call the parent constructor + this.description = 'Header information is missing'; // Set the specific description + this.code = JSONRPCErrorCode.MissingHeader; } } +class ErrorHandlerAborted extends ErrorRPC { + constructor(message?: string, options?: { cause: Error }) { + super(message); // Call the parent constructor + this.description = 'Handler Aborted Stream.'; // Set the specific description + this.code = JSONRPCErrorCode.HandlerAborted; + } +} class ErrorRPCMessageLength extends ErrorRPC { static description = 'RPC Message exceeds maximum size'; - exitCode = sysexits.DATAERR; + code? = JSONRPCErrorCode.RPCMessageLength; } class ErrorRPCMissingResponse extends ErrorRPC { constructor(message?: string) { super(message); - this.name = 'ErrorRPCMissingResponse'; this.description = 'Stream ended before response'; - this.exitCode = sysexits.UNAVAILABLE; + this.code = JSONRPCErrorCode.RPCMissingResponse; } } interface ErrorRPCOutputStreamErrorOptions { cause?: Error; - // ... other properties } class ErrorRPCOutputStreamError extends ErrorRPC { - cause?: Error; - constructor(message: string, options: ErrorRPCOutputStreamErrorOptions) { super(message); - this.name = 'ErrorRPCOutputStreamError'; this.description = 'Output stream failed, unable to send data'; - this.exitCode = sysexits.UNAVAILABLE; - - // Set the cause if provided in options - if (options && options.cause) { - this.cause = options.cause; - } + this.code = JSONRPCErrorCode.RPCOutputStreamError; } } class ErrorRPCRemote extends ErrorRPC { static description = 'Remote error from RPC call'; - exitCode: number = sysexits.UNAVAILABLE; + static message: string = 'The server responded with an error'; metadata: JSONValue | undefined; constructor(metadata?: JSONValue, message?: string, options?) { super(message); - this.name = 'ErrorRPCRemote'; this.metadata = metadata; + this.code = JSONRPCErrorCode.RPCRemote; + this.data = options?.data; } public static fromJSON>( @@ -129,7 +157,6 @@ class ErrorRPCRemote extends ErrorRPC { isNaN(Date.parse(json.data.timestamp)) || typeof json.data.metadata !== 'object' || typeof json.data.data !== 'object' || - typeof json.data.exitCode !== 'number' || ('stack' in json.data && typeof json.data.stack !== 'string') ) { throw new TypeError(`Cannot decode JSON to ${this.name}`); @@ -143,7 +170,6 @@ class ErrorRPCRemote extends ErrorRPC { data: json.data.data, cause: json.data.cause, }); - e.exitCode = json.data.exitCode; e.stack = json.data.stack; return e; } @@ -152,42 +178,68 @@ class ErrorRPCRemote extends ErrorRPC { type: this.name, data: { description: this.description, - exitCode: this.exitCode, }, }; } } class ErrorRPCStreamEnded extends ErrorRPC { - constructor(message?: string) { + constructor(message?: string, options?: { cause: Error }) { super(message); - this.name = 'ErrorRPCStreamEnded'; this.description = 'Handled stream has ended'; - this.exitCode = sysexits.NOINPUT; + this.code = JSONRPCErrorCode.RPCStreamEnded; } } class ErrorRPCTimedOut extends ErrorRPC { - constructor(message?: string) { + constructor(message?: string, options?: { cause: Error }) { super(message); - this.name = 'ErrorRPCTimedOut'; this.description = 'RPC handler has timed out'; - this.exitCode = sysexits.UNAVAILABLE; + this.code = JSONRPCErrorCode.RPCTimedOut; } } class ErrorUtilsUndefinedBehaviour extends ErrorRPC { constructor(message?: string) { super(message); - this.name = 'ErrorUtilsUndefinedBehaviour'; this.description = 'You should never see this error'; - this.exitCode = sysexits.SOFTWARE; + this.code = JSONRPCErrorCode.MethodNotFound; } } export function never(): never { throw new ErrorRPC('This function should never be called'); } +class ErrorRPCMethodNotImplemented extends ErrorRPC { + constructor(message?: string) { + super(message || 'This method must be overridden'); // Default message if none provided + this.name = 'ErrorRPCMethodNotImplemented'; + this.description = + 'This abstract method must be implemented in a derived class'; + this.code = JSONRPCErrorCode.MethodNotFound; + } +} + +class ErrorRPCConnectionLocal extends ErrorRPC { + static description = 'RPC Connection local error'; + code? = JSONRPCErrorCode.RPCConnectionLocal; +} + +class ErrorRPCConnectionPeer extends ErrorRPC { + static description = 'RPC Connection peer error'; + code? = JSONRPCErrorCode.RPCConnectionPeer; +} + +class ErrorRPCConnectionKeepAliveTimeOut extends ErrorRPC { + static description = 'RPC Connection keep alive timeout'; + code? = JSONRPCErrorCode.RPCConnectionKeepAliveTimeOut; +} + +class ErrorRPCConnectionInternal extends ErrorRPC { + static description = 'RPC Connection internal error'; + code? = JSONRPCErrorCode.RPCConnectionInternal; +} + export { ErrorRPC, ErrorRPCDestroyed, @@ -201,4 +253,14 @@ export { ErrorRPCStreamEnded, ErrorRPCTimedOut, ErrorUtilsUndefinedBehaviour, + ErrorRPCMethodNotImplemented, + ErrorRPCConnectionLocal, + ErrorRPCConnectionPeer, + ErrorRPCConnectionKeepAliveTimeOut, + ErrorRPCConnectionInternal, + ErrorMissingHeader, + ErrorHandlerAborted, + ErrorRPCCallerFailed, + ErrorMissingCaller, + JSONRPCErrorCode, }; diff --git a/src/errors/index.ts b/src/errors/index.ts index 0df2a0a..f72bc43 100644 --- a/src/errors/index.ts +++ b/src/errors/index.ts @@ -1,2 +1 @@ -export * from './sysexits'; export * from './errors'; diff --git a/src/errors/sysexits.ts b/src/errors/sysexits.ts deleted file mode 100644 index 935c181..0000000 --- a/src/errors/sysexits.ts +++ /dev/null @@ -1,91 +0,0 @@ -const sysexits = Object.freeze({ - OK: 0, - GENERAL: 1, - // Sysexit standard starts at 64 to avoid conflicts - /** - * The command was used incorrectly, e.g., with the wrong number of arguments, - * a bad flag, a bad syntax in a parameter, or whatever. - */ - USAGE: 64, - /** - * The input data was incorrect in some way. This should only be used for - * user's data and not system files. - */ - DATAERR: 65, - /** - * An input file (not a system file) did not exist or was not readable. - * This could also include errors like "No message" to a mailer - * (if it cared to catch it). - */ - NOINPUT: 66, - /** - * The user specified did not exist. This might be used for mail addresses - * or remote logins. - */ - NOUSER: 67, - /** - * The host specified did not exist. This is used in mail addresses or - * network requests. - */ - NOHOST: 68, - /** - * A service is unavailable. This can occur if a support program or file - * does not exist. This can also be used as a catchall message when - * something you wanted to do does not work, but you do not know why. - */ - UNAVAILABLE: 69, - /** - * An internal software error has been detected. This should be limited to - * non-operating system related errors as possible. - */ - SOFTWARE: 70, - /** - * An operating system error has been detected. This is intended to be used - * for such things as "cannot fork", "cannot create pipe", or the like. - * It in-cludes things like getuid returning a user that does not exist in - * the passwd file. - */ - OSERR: 71, - /** - * Some system file (e.g., /etc/passwd, /var/run/utx.active, etc.) - * does not exist, cannot be opened, or has some sort of error - * (e.g., syntax error). - */ - OSFILE: 72, - /** - * A (user specified) output file cannot be created. - */ - CANTCREAT: 73, - /** - * An error occurred while doing I/O on some file. - */ - IOERR: 74, - /** - * Temporary failure, indicating something that is not really an error. - * In sendmail, this means that a mailer (e.g.) could not create a connection, - * and the request should be reattempted later. - */ - TEMPFAIL: 75, - /** - * The remote system returned something that was "not possible" during a - * protocol exchange. - */ - PROTOCOL: 76, - /** - * You did not have sufficient permission to perform the operation. This is - * not intended for file system problems, which should use EX_NOINPUT or - * EX_CANTCREAT, but rather for higher level permissions. - */ - NOPERM: 77, - /** - * Something was found in an un-configured or mis-configured state. - */ - CONFIG: 78, - CANNOT_EXEC: 126, - COMMAND_NOT_FOUND: 127, - INVALID_EXIT_ARG: 128, - // 128+ are reserved for signal exits - UNKNOWN: 255, -}); - -export default sysexits; diff --git a/src/events.ts b/src/events.ts index 210d676..828cca4 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,3 +1,56 @@ +import type RPCServer from './RPCServer'; +import type RPCClient from './RPCClient'; +import type { + ErrorRPCConnectionLocal, + ErrorRPCConnectionPeer, + ErrorRPCConnectionKeepAliveTimeOut, + ErrorRPCConnectionInternal, +} from './errors'; +import { AbstractEvent } from '@matrixai/events'; +import * as rpcErrors from './errors'; + +abstract class EventRPC extends AbstractEvent {} + +abstract class EventRPCClient extends AbstractEvent {} + +abstract class EventRPCServer extends AbstractEvent {} + +abstract class EventRPCConnection extends AbstractEvent {} + +// Client events +class EventRPCClientDestroy extends EventRPCClient {} + +class EventRPCClientDestroyed extends EventRPCClient {} + +class EventRPCClientCreate extends EventRPCClient {} + +class EventRPCClientCreated extends EventRPCClient {} + +class EventRPCClientError extends EventRPCClient {} + +class EventRPCClientConnect extends EventRPCClient {} + +// Server events + +class EventRPCServerConnection extends EventRPCServer {} + +class EventRPCServerCreate extends EventRPCServer {} + +class EventRPCServerCreated extends EventRPCServer {} + +class EventRPCServerDestroy extends EventRPCServer {} + +class EventRPCServerDestroyed extends EventRPCServer {} + +class EventRPCServerError extends EventRPCServer {} + +class EventRPCConnectionError extends EventRPCConnection< + | ErrorRPCConnectionLocal + | ErrorRPCConnectionPeer + | ErrorRPCConnectionKeepAliveTimeOut + | ErrorRPCConnectionInternal +> {} + class RPCErrorEvent extends Event { public detail: Error; constructor( @@ -10,4 +63,23 @@ class RPCErrorEvent extends Event { } } -export { RPCErrorEvent }; +export { + RPCErrorEvent, + EventRPC, + EventRPCClient, + EventRPCServer, + EventRPCConnection, + EventRPCClientDestroy, + EventRPCClientDestroyed, + EventRPCClientCreate, + EventRPCClientCreated, + EventRPCClientError, + EventRPCClientConnect, + EventRPCServerConnection, + EventRPCServerCreate, + EventRPCServerCreated, + EventRPCServerDestroy, + EventRPCServerDestroyed, + EventRPCServerError, + EventRPCConnectionError, +}; diff --git a/src/handlers.ts b/src/handlers.ts deleted file mode 100644 index aa3e7eb..0000000 --- a/src/handlers.ts +++ /dev/null @@ -1,99 +0,0 @@ -import type { ReadableStream } from 'stream/web'; -import type { ContextTimed } from '@matrixai/contexts'; -import type { ContainerType, JSONRPCRequest } from './types'; -import type { JSONValue } from './types'; - -abstract class Handler< - Container extends ContainerType = ContainerType, - Input extends JSONValue = JSONValue, - Output extends JSONValue = JSONValue, -> { - // These are used to distinguish the handlers in the type system. - // Without these the map types can't tell the types of handlers apart. - protected _inputType: Input; - protected _outputType: Output; - /** - * This is the timeout used for the handler. - * If it is not set then the default timeout time for the `RPCServer` is used. - */ - public timeout?: number; - - constructor(protected container: Container) {} -} - -abstract class RawHandler< - Container extends ContainerType = ContainerType, -> extends Handler { - abstract handle( - input: [JSONRPCRequest, ReadableStream], - cancel: (reason?: any) => void, - meta: Record | undefined, - ctx: ContextTimed, - ): Promise<[JSONValue, ReadableStream]>; -} - -abstract class DuplexHandler< - Container extends ContainerType = ContainerType, - Input extends JSONValue = JSONValue, - Output extends JSONValue = JSONValue, -> extends Handler { - /** - * Note that if the output has an error, the handler will not see this as an - * error. If you need to handle any clean up it should be handled in a - * `finally` block and check the abort signal for potential errors. - */ - abstract handle( - input: AsyncIterableIterator, - cancel: (reason?: any) => void, - meta: Record | undefined, - ctx: ContextTimed, - ): AsyncIterableIterator; -} - -abstract class ServerHandler< - Container extends ContainerType = ContainerType, - Input extends JSONValue = JSONValue, - Output extends JSONValue = JSONValue, -> extends Handler { - abstract handle( - input: Input, - cancel: (reason?: any) => void, - meta: Record | undefined, - ctx: ContextTimed, - ): AsyncIterableIterator; -} - -abstract class ClientHandler< - Container extends ContainerType = ContainerType, - Input extends JSONValue = JSONValue, - Output extends JSONValue = JSONValue, -> extends Handler { - abstract handle( - input: AsyncIterableIterator, - cancel: (reason?: any) => void, - meta: Record | undefined, - ctx: ContextTimed, - ): Promise; -} - -abstract class UnaryHandler< - Container extends ContainerType = ContainerType, - Input extends JSONValue = JSONValue, - Output extends JSONValue = JSONValue, -> extends Handler { - abstract handle( - input: Input, - cancel: (reason?: any) => void, - meta: Record | undefined, - ctx: ContextTimed, - ): Promise; -} - -export { - Handler, - RawHandler, - DuplexHandler, - ServerHandler, - ClientHandler, - UnaryHandler, -}; diff --git a/src/handlers/ClientHandler.ts b/src/handlers/ClientHandler.ts new file mode 100644 index 0000000..0aea354 --- /dev/null +++ b/src/handlers/ClientHandler.ts @@ -0,0 +1,21 @@ +import type { ContainerType, JSONValue } from '../types'; +import type { ContextTimed } from '@matrixai/contexts'; +import Handler from './Handler'; +import { ErrorRPCMethodNotImplemented } from '../errors'; + +abstract class ClientHandler< + Container extends ContainerType = ContainerType, + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Handler { + public handle = async ( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): Promise => { + throw new ErrorRPCMethodNotImplemented(); + }; +} + +export default ClientHandler; diff --git a/src/handlers/DuplexHandler.ts b/src/handlers/DuplexHandler.ts new file mode 100644 index 0000000..6534ef6 --- /dev/null +++ b/src/handlers/DuplexHandler.ts @@ -0,0 +1,26 @@ +import type { ContainerType, JSONValue } from '../types'; +import type { ContextTimed } from '@matrixai/contexts'; +import Handler from './Handler'; +import { ErrorRPCMethodNotImplemented } from '../errors'; + +abstract class DuplexHandler< + Container extends ContainerType = ContainerType, + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Handler { + /** + * Note that if the output has an error, the handler will not see this as an + * error. If you need to handle any clean up it should be handled in a + * `finally` block and check the abort signal for potential errors. + */ + public handle = async function* ( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): AsyncIterableIterator { + throw new ErrorRPCMethodNotImplemented('This method must be overwrtitten.'); + }; +} + +export default DuplexHandler; diff --git a/src/handlers/Handler.ts b/src/handlers/Handler.ts new file mode 100644 index 0000000..fbf2f4e --- /dev/null +++ b/src/handlers/Handler.ts @@ -0,0 +1,19 @@ +import type { ContainerType, JSONValue } from '../types'; +abstract class Handler< + Container extends ContainerType = ContainerType, + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> { + // These are used to distinguish the handlers in the type system. + // Without these the map types can't tell the types of handlers apart. + protected _inputType: Input; + protected _outputType: Output; + /** + * This is the timeout used for the handler. + * If it is not set then the default timeout time for the `RPCServer` is used. + */ + public timeout?: number; + + constructor(protected container: Container) {} +} +export default Handler; diff --git a/src/handlers/RawHandler.ts b/src/handlers/RawHandler.ts new file mode 100644 index 0000000..01fd1d7 --- /dev/null +++ b/src/handlers/RawHandler.ts @@ -0,0 +1,20 @@ +import type { ContextTimed } from '@matrixai/contexts'; +import type { ReadableStream } from 'stream/web'; +import type { ContainerType, JSONRPCRequest, JSONValue } from '../types'; +import Handler from './Handler'; +import { ErrorRPCMethodNotImplemented } from '../errors'; + +abstract class RawHandler< + Container extends ContainerType = ContainerType, +> extends Handler { + public handle = async ( + input: [JSONRPCRequest, ReadableStream], + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): Promise<[JSONValue, ReadableStream]> => { + throw new ErrorRPCMethodNotImplemented('This method must be overridden'); + }; +} + +export default RawHandler; diff --git a/src/handlers/ServerHandler.ts b/src/handlers/ServerHandler.ts new file mode 100644 index 0000000..bebd177 --- /dev/null +++ b/src/handlers/ServerHandler.ts @@ -0,0 +1,21 @@ +import type { ContextTimed } from '@matrixai/contexts'; +import type { ContainerType, JSONValue } from '../types'; +import Handler from './Handler'; +import { ErrorRPCMethodNotImplemented } from '../errors'; + +abstract class ServerHandler< + Container extends ContainerType = ContainerType, + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Handler { + public handle = async function* ( + input: Input, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): AsyncIterableIterator { + throw new ErrorRPCMethodNotImplemented('This method must be overridden'); + }; +} + +export default ServerHandler; diff --git a/src/handlers/UnaryHandler.ts b/src/handlers/UnaryHandler.ts new file mode 100644 index 0000000..0a1e37b --- /dev/null +++ b/src/handlers/UnaryHandler.ts @@ -0,0 +1,21 @@ +import type { ContextTimed } from '@matrixai/contexts'; +import type { ContainerType, JSONValue } from '../types'; +import Handler from './Handler'; +import { ErrorRPCMethodNotImplemented } from '../errors'; + +abstract class UnaryHandler< + Container extends ContainerType = ContainerType, + Input extends JSONValue = JSONValue, + Output extends JSONValue = JSONValue, +> extends Handler { + public handle = async ( + input: Input, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): Promise => { + throw new ErrorRPCMethodNotImplemented('This method must be overridden'); + }; +} + +export default UnaryHandler; diff --git a/src/handlers/index.ts b/src/handlers/index.ts new file mode 100644 index 0000000..2df4ee2 --- /dev/null +++ b/src/handlers/index.ts @@ -0,0 +1,6 @@ +export { default as Handler } from './Handler'; +export { default as ClientHandler } from './ClientHandler'; +export { default as DuplexHandler } from './DuplexHandler'; +export { default as RawHandler } from './RawHandler'; +export { default as ServerHandler } from './ServerHandler'; +export { default as UnaryHandler } from './UnaryHandler'; diff --git a/src/index.ts b/src/index.ts index 9961e29..c3a5052 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,5 +2,7 @@ export { default as RPCClient } from './RPCClient'; export { default as RPCServer } from './RPCServer'; export * as utils from './utils'; export * as types from './types'; -export * as errors from './errors/errors'; +export * as errors from './errors'; export * as events from './events'; +export * as handlers from './handlers'; +export * as callers from './callers'; diff --git a/src/types.ts b/src/types.ts index b563bba..97e367c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,15 +1,17 @@ import type { ReadableStream, ReadableWritablePair } from 'stream/web'; import type { ContextTimed, ContextTimedInput } from '@matrixai/contexts'; -import type { Handler } from './handlers'; -import type { - Caller, - RawCaller, - DuplexCaller, - ServerCaller, - ClientCaller, - UnaryCaller, -} from './callers'; -import type { Id } from '@matrixai/id'; +import type { Caller } from './callers'; +import type { RawCaller } from './callers'; +import type { DuplexCaller } from './callers'; +import type { ServerCaller } from './callers'; +import type { ClientCaller } from './callers'; +import type { UnaryCaller } from './callers'; +import type Handler from './handlers/Handler'; + +/** + * This is the type for the IdGenFunction. It is used to generate the request + */ +type IdGen = () => PromiseLike; /** * This is the JSON RPC request object. this is the generic message type used for the RPC. @@ -320,12 +322,13 @@ declare const brand: unique symbol; type Opaque = T & { readonly [brand]: K }; type JSONValue = - | { [key: string]: JSONValue } + | { [key: string]: JSONValue | undefined } | Array | string | number | boolean - | null; + | null + | undefined; type POJO = { [key: string]: any }; type PromiseDeconstructed = { @@ -335,6 +338,7 @@ type PromiseDeconstructed = { }; export type { + IdGen, JSONRPCRequestMessage, JSONRPCRequestNotification, JSONRPCResponseResult, diff --git a/src/utils/middleware.ts b/src/utils/middleware.ts index 138e04d..49f5504 100644 --- a/src/utils/middleware.ts +++ b/src/utils/middleware.ts @@ -9,7 +9,7 @@ import { TransformStream } from 'stream/web'; import { JSONParser } from '@streamparser/json'; import * as rpcUtils from './utils'; import { promise } from './utils'; -import * as rpcErrors from '../errors/errors'; +import * as rpcErrors from '../errors'; /** * This function is a factory to create a TransformStream that will diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 4aafdd4..cec0611 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -11,15 +11,15 @@ import type { JSONRPCResponseResult, PromiseDeconstructed, } from '../types'; -import type { JSONValue } from '../types'; +import type { JSONValue, IdGen } from '../types'; import type { Timer } from '@matrixai/timer'; import { TransformStream } from 'stream/web'; import { JSONParser } from '@streamparser/json'; import { AbstractError } from '@matrixai/errors'; -import * as rpcErrors from '../errors/errors'; -import * as errors from '../errors/errors'; -import { ErrorRPCRemote } from '../errors/errors'; -import { ErrorRPC } from '../errors/errors'; +import * as rpcErrors from '../errors'; +import * as errors from '../errors'; +import { ErrorRPCRemote } from '../errors'; +import { ErrorRPC } from '../errors'; // Importing PK funcs and utils which are essential for RPC function isObject(o: unknown): o is object { @@ -223,45 +223,6 @@ function parseJSONRPCMessage( * Polykey errors are handled by their inbuilt `toJSON` method , so this only * serialises other errors */ -function replacer(key: string, value: any): any { - if (value instanceof AggregateError) { - // AggregateError has an `errors` property - return { - type: value.constructor.name, - data: { - errors: value.errors, - message: value.message, - stack: value.stack, - }, - }; - } else if (value instanceof Error) { - // If it's some other type of error then only serialise the message and - // stack (and the type of the error) - return { - type: value.name, - data: { - message: value.message, - stack: value.stack, - }, - }; - } else { - // If it's not an error then just leave as is - return value; - } -} - -/** - * The same as `replacer`, however this will additionally filter out any - * sensitive data that should not be sent over the network when sending to an - * agent (as opposed to a client) - */ -function sensitiveReplacer(key: string, value: any) { - if (key === 'stack') { - return; - } else { - return replacer(key, value); - } -} /** * Serializes Error instances into RPC errors @@ -270,12 +231,23 @@ function sensitiveReplacer(key: string, value: any) { * If sending to an agent (rather than a client), set sensitive to true to * prevent sensitive information from being sent over the network */ -function fromError(error: Error, sensitive: boolean = false) { - if (sensitive) { - return JSON.stringify(error, sensitiveReplacer); - } else { - return JSON.stringify(error, replacer); +function fromError(error: ErrorRPC, id?: any): JSONValue { + const data: { [key: string]: JSONValue } = { + message: error.message, + description: error.description, + data: error.data, + }; + if (error.code !== undefined) { + data.code = error.code; } + return { + jsonrpc: '2.0', + error: { + type: error.name, + ...data, + }, + id: id !== undefined ? id : null, + }; } /** @@ -292,7 +264,43 @@ const standardErrors = { URIError, AggregateError, AbstractError, + ErrorRPCRemote, + ErrorRPC, }; +const createReplacer = () => { + return (keyToRemove) => { + return (key, value) => { + if (key === keyToRemove) { + return undefined; + } + + if (key !== 'code') { + if (value instanceof ErrorRPC) { + return { + code: value.code, + message: value.message, + data: value.data, + type: value.constructor.name, + }; + } + + if (value instanceof AggregateError) { + return { + type: value.constructor.name, + data: { + errors: value.errors, + message: value.message, + stack: value.stack, + }, + }; + } + } + + return value; + }; + }; +}; +const replacer = createReplacer(); /** * Reviver function for deserialising errors sent over RPC (used by @@ -361,18 +369,28 @@ function reviver(key: string, value: any): any { } } -function toError(errorData, metadata?: JSONValue): ErrorRPCRemote { - if (errorData == null) { - return new ErrorRPCRemote(metadata); +function toError(errorResponse: any, metadata?: any): ErrorRPCRemote { + if ( + typeof errorResponse !== 'object' || + errorResponse === null || + !('error' in errorResponse) || + !('type' in errorResponse.error) || + !('message' in errorResponse.error) + ) { + throw new TypeError('Invalid error data object'); } - const error: Error = JSON.parse(errorData, reviver); - const remoteError = new ErrorRPCRemote(metadata, error.message, { - cause: error, + + const errorData = errorResponse.error; + const error = new ErrorRPCRemote(metadata, errorData.message, { + cause: errorData.cause, + data: errorData.data === undefined ? null : errorData.data, }); - if (error instanceof ErrorRPC) { - remoteError.exitCode = error.exitCode as number; - } - return remoteError; + error.message = errorData.message; + error.code = errorData.code; + error.description = errorData.description; + error.data = errorData.data; + + return error; } /** @@ -511,6 +529,7 @@ export { parseJSONRPCResponseError, parseJSONRPCResponse, parseJSONRPCMessage, + replacer, fromError, toError, clientInputTransformStream, diff --git a/tests/RPC.test.ts b/tests/RPC.test.ts new file mode 100644 index 0000000..591ff5d --- /dev/null +++ b/tests/RPC.test.ts @@ -0,0 +1,1046 @@ +import type { ContainerType, JSONRPCRequest } from '@/types'; +import type { ReadableStream } from 'stream/web'; +import type { JSONValue, IdGen } from '@/types'; +import type { ContextTimed } from '@matrixai/contexts'; +import { TransformStream } from 'stream/web'; +import { fc, testProp } from '@fast-check/jest'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import RawCaller from '@/callers/RawCaller'; +import DuplexCaller from '@/callers/DuplexCaller'; +import ServerCaller from '@/callers/ServerCaller'; +import ClientCaller from '@/callers/ClientCaller'; +import UnaryCaller from '@/callers/UnaryCaller'; +import * as rpcUtilsMiddleware from '@/utils/middleware'; +import { + ErrorRPC, + ErrorRPCHandlerFailed, + ErrorRPCParse, + ErrorRPCRemote, + ErrorRPCTimedOut, + JSONRPCErrorCode, +} from '@/errors'; +import * as rpcErrors from '@/errors'; +import RPCClient from '@/RPCClient'; +import RPCServer from '@/RPCServer'; +import * as utils from '@/utils'; +import DuplexHandler from '@/handlers/DuplexHandler'; +import RawHandler from '@/handlers/RawHandler'; +import ServerHandler from '@/handlers/ServerHandler'; +import UnaryHandler from '@/handlers/UnaryHandler'; +import ClientHandler from '@/handlers/ClientHandler'; +import { RPCStream } from '@/types'; +import { fromError, promise, replacer, toError } from '@/utils'; +import * as rpcTestUtils from './utils'; + +describe('RPC', () => { + const logger = new Logger(`RPC Test`, LogLevel.WARN, [new StreamHandler()]); + const idGen: IdGen = () => Promise.resolve(null); + testProp( + 'RPC communication with raw stream', + [rpcTestUtils.rawDataArb], + async (inputData) => { + const [outputResult, outputWriterStream] = + rpcTestUtils.streamToArray(); + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + let header: JSONRPCRequest | undefined; + + class TestMethod extends RawHandler { + public handle = async ( + input: [JSONRPCRequest, ReadableStream], + _cancel: (reason?: any) => void, + _meta: Record | undefined, + ): Promise<[JSONValue, ReadableStream]> => { + return new Promise((resolve) => { + const [header_, stream] = input; + header = header_; + resolve(['some leading data', stream]); + }); + }; + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + idGen, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new RawCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + + const callerInterface = await rpcClient.methods.testMethod({ + hello: 'world', + }); + const writer = callerInterface.writable.getWriter(); + const pipeProm = callerInterface.readable.pipeTo(outputWriterStream); + for (const value of inputData) { + await writer.write(value); + } + await writer.close(); + const expectedHeader: JSONRPCRequest = { + jsonrpc: '2.0', + method: 'testMethod', + params: { hello: 'world' }, + id: null, + }; + expect(header).toStrictEqual(expectedHeader); + expect(callerInterface.meta?.result).toBe('some leading data'); + expect(await outputResult).toStrictEqual(inputData); + await pipeProm; + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + test('RPC communication with raw stream times out waiting for leading message', async () => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + void (async () => { + for await (const _ of serverPair.readable) { + // Just consume + } + })(); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new RawCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + + await expect( + rpcClient.methods.testMethod( + { + hello: 'world', + }, + { timer: 100 }, + ), + ).rejects.toThrow(rpcErrors.ErrorRPCTimedOut); + await rpcClient.destroy(); + }); + test('RPC communication with raw stream, raw handler throws', async () => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends RawHandler { + public handle = async ( + input: [JSONRPCRequest, ReadableStream], + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): Promise<[JSONValue, ReadableStream]> => { + throw new Error('some error'); + }; + } + + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + idGen, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new RawCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + + await expect( + rpcClient.methods.testMethod({ + hello: 'world', + }), + ).rejects.toThrow(rpcErrors.ErrorRPCRemote); + + await rpcServer.destroy(); + await rpcClient.destroy(); + }); + testProp( + 'RPC communication with duplex stream', + [fc.array(rpcTestUtils.safeJsonValueArb, { minLength: 1 })], + async (values) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + class TestMethod extends DuplexHandler { + public handle = async function* ( + input: AsyncGenerator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): AsyncGenerator { + yield* input; + }; + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + idGen, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new DuplexCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + + const callerInterface = await rpcClient.methods.testMethod(); + const writer = callerInterface.writable.getWriter(); + const reader = callerInterface.readable.getReader(); + for (const value of values) { + await writer.write(value); + expect((await reader.read()).value).toStrictEqual(value); + } + await writer.close(); + const result = await reader.read(); + expect(result.value).toBeUndefined(); + expect(result.done).toBeTrue(); + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + testProp( + 'RPC communication with server stream', + [fc.integer({ min: 1, max: 100 })], + async (value) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends ServerHandler { + public handle = async function* ( + input: number, + ): AsyncGenerator { + for (let i = 0; i < input; i++) { + yield i; + } + }; + } + + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + idGen, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new ServerCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + + const callerInterface = await rpcClient.methods.testMethod(value); + + const outputs: Array = []; + for await (const num of callerInterface) { + outputs.push(num); + } + expect(outputs.length).toEqual(value); + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + testProp( + 'RPC communication with client stream', + [fc.array(fc.integer(), { minLength: 1 }).noShrink()], + async (values) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends ClientHandler { + public handle = async ( + input: AsyncIterable, + ): Promise => { + let acc = 0; + for await (const number of input) { + acc += number; + } + return acc; + }; + } + + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + idGen, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new ClientCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + + const { output, writable } = await rpcClient.methods.testMethod(); + const writer = writable.getWriter(); + for (const value of values) { + await writer.write(value); + } + await writer.close(); + const expectedResult = values.reduce((p, c) => p + c); + await expect(output).resolves.toEqual(expectedResult); + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + testProp( + 'RPC communication with unary call', + [rpcTestUtils.safeJsonValueArb], + async (value) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends UnaryHandler { + public handle = async (input: JSONValue): Promise => { + return input; + }; + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + idGen, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new UnaryCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + + const result = await rpcClient.methods.testMethod(value); + expect(result).toStrictEqual(value); + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + testProp( + 'RPC handles and sends errors', + [ + rpcTestUtils.safeJsonValueArb, + rpcTestUtils.errorArb(rpcTestUtils.errorArb()), + ], + async (value, error) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends UnaryHandler { + public handle = async ( + _input: JSONValue, + _cancel: (reason?: any) => void, + _meta: Record | undefined, + _ctx: ContextTimed, + ): Promise => { + throw error; + }; + } + + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + idGen, + }); + rpcServer.handleStream({ ...serverPair, cancel: () => {} }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new UnaryCaller(), + }, + streamFactory: async () => { + return { ...clientPair, cancel: () => {} }; + }, + logger, + idGen, + }); + + // Create a new promise so we can await it multiple times for assertions + const callProm = rpcClient.methods.testMethod(value).catch((e) => e); + + // The promise should be rejected + const rejection = await callProm; + + // The error should have specific properties + expect(rejection).toBeInstanceOf(rpcErrors.ErrorRPCRemote); + expect(rejection).toMatchObject({ code: -32006 }); + + // Cleanup + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + + testProp( + 'RPC handles and sends sensitive errors', + [ + rpcTestUtils.safeJsonValueArb, + rpcTestUtils.errorArb(rpcTestUtils.errorArb()), + ], + async (value, error) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends UnaryHandler { + public handle = async ( + _input: JSONValue, + _cancel: (reason?: any) => void, + _meta: Record | undefined, + _ctx: ContextTimed, + ): Promise => { + throw error; + }; + } + + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + sensitive: true, + logger, + idGen, + }); + rpcServer.handleStream({ ...serverPair, cancel: () => {} }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new UnaryCaller(), + }, + streamFactory: async () => { + return { ...clientPair, cancel: () => {} }; + }, + logger, + idGen, + }); + + const callProm = rpcClient.methods.testMethod(ErrorRPCRemote.description); + + // Use Jest's `.rejects` to handle the promise rejection + await expect(callProm).rejects.toBeInstanceOf(rpcErrors.ErrorRPCRemote); + await expect(callProm).rejects.not.toHaveProperty('cause.stack'); + + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + + test('middleware can end stream early', async () => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + class TestMethod extends DuplexHandler { + public handle = async function* ( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): AsyncIterableIterator { + yield* input; + }; + } + + const middleware = rpcUtilsMiddleware.defaultServerMiddlewareWrapper(() => { + return { + forward: new TransformStream({ + start: (controller) => { + // Controller.terminate(); + controller.error(Error('SOME ERROR')); + }, + }), + reverse: new TransformStream({ + start: (controller) => { + controller.error(Error('SOME ERROR')); + }, + }), + }; + }); + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + middlewareFactory: middleware, + logger, + idGen, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new DuplexCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + + const callerInterface = await rpcClient.methods.testMethod(); + const writer = callerInterface.writable.getWriter(); + await writer.write({}); + // Allow time to process buffer + await utils.sleep(0); + await expect(writer.write({})).toReject(); + const reader = callerInterface.readable.getReader(); + await expect(reader.read()).toReject(); + await expect(writer.closed).toReject(); + await expect(reader.closed).toReject(); + await expect(rpcServer.destroy(false)).toResolve(); + await rpcClient.destroy(); + }); + test('RPC client and server timeout concurrently', async () => { + let serverTimedOut = false; + let clientTimedOut = false; + // Generate test data (assuming fc.array generates some mock array) + const values = fc.array(rpcTestUtils.safeJsonValueArb, { minLength: 1 }); + + // Setup server and client communication pairs + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + const timeout = 1; + class TestMethod extends DuplexHandler { + public handle = async function* ( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): AsyncIterableIterator { + // Check for abort event + ctx.signal.throwIfAborted(); + const abortProm = utils.promise(); + ctx.signal.addEventListener('abort', () => { + abortProm.rejectP(ctx.signal.reason); + }); + await abortProm.p; + }; + } + const testMethodInstance = new TestMethod({}); + // Set up a client and server with matching timeout settings + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: testMethodInstance, + }, + logger, + idGen, + handlerTimeoutTime: timeout, + }); + // Register callback + rpcServer.registerOnTimeoutCallback(() => { + serverTimedOut = true; + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new DuplexCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + const callerInterface = await rpcClient.methods.testMethod({ + timer: timeout, + }); + // Register callback + rpcClient.registerOnTimeoutCallback(() => { + clientTimedOut = true; + }); + const writer = callerInterface.writable.getWriter(); + const reader = callerInterface.readable.getReader(); + // Wait for server and client to timeout by checking the flag + await new Promise((resolve) => { + const checkFlag = () => { + if (serverTimedOut && clientTimedOut) resolve(); + else setTimeout(() => checkFlag(), 10); + }; + checkFlag(); + }); + // Expect both the client and the server to time out + await expect(writer.write(values[0])).rejects.toThrow( + 'Timed out waiting for header', + ); + + await expect(reader.read()).rejects.toThrow('Timed out waiting for header'); + + await rpcServer.destroy(); + await rpcClient.destroy(); + }); + // Test description + test('RPC server times out before client', async () => { + let serverTimedOut = false; + + // Generate test data (assuming fc.array generates some mock array) + const values = fc.array(rpcTestUtils.safeJsonValueArb, { minLength: 1 }); + + // Setup server and client communication pairs + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + // Define the server's method behavior + class TestMethod extends DuplexHandler { + public handle = async function* ( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ) { + ctx.signal.throwIfAborted(); + const abortProm = utils.promise(); + ctx.signal.addEventListener('abort', () => { + abortProm.rejectP(ctx.signal.reason); + }); + await abortProm.p; + }; + } + + // Create an instance of the RPC server with a shorter timeout + const rpcServer = await RPCServer.createRPCServer({ + manifest: { testMethod: new TestMethod({}) }, + logger, + idGen, + handlerTimeoutTime: 1, + }); + // Register callback + rpcServer.registerOnTimeoutCallback(() => { + serverTimedOut = true; + }); + rpcServer.handleStream({ ...serverPair, cancel: () => {} }); + + // Create an instance of the RPC client with a longer timeout + const rpcClient = await RPCClient.createRPCClient({ + manifest: { testMethod: new DuplexCaller() }, + streamFactory: async () => ({ ...clientPair, cancel: () => {} }), + logger, + idGen, + }); + + // Get server and client interfaces + const callerInterface = await rpcClient.methods.testMethod({ + timer: 10, + }); + const writer = callerInterface.writable.getWriter(); + const reader = callerInterface.readable.getReader(); + // Wait for server to timeout by checking the flag + await new Promise((resolve) => { + const checkFlag = () => { + if (serverTimedOut) resolve(); + else setTimeout(() => checkFlag(), 10); + }; + checkFlag(); + }); + + // We expect server to timeout before the client + await expect(writer.write(values[0])).rejects.toThrow( + 'Timed out waiting for header', + ); + await expect(reader.read()).rejects.toThrow('Timed out waiting for header'); + + // Cleanup + await rpcServer.destroy(); + await rpcClient.destroy(); + }); + test('RPC client times out before server', async () => { + // Generate test data (assuming fc.array generates some mock array) + const values = fc.array(rpcTestUtils.safeJsonValueArb, { minLength: 1 }); + + // Setup server and client communication pairs + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + class TestMethod extends DuplexHandler { + public handle = async function* ( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): AsyncIterableIterator { + ctx.signal.throwIfAborted(); + const abortProm = utils.promise(); + ctx.signal.addEventListener('abort', () => { + abortProm.rejectP(ctx.signal.reason); + }); + await abortProm.p; + }; + } + // Set up a client and server with matching timeout settings + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + idGen, + + handlerTimeoutTime: 400, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new DuplexCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + const callerInterface = await rpcClient.methods.testMethod({ timer: 300 }); + const writer = callerInterface.writable.getWriter(); + const reader = callerInterface.readable.getReader(); + // Expect the client to time out first + await expect(writer.write(values[0])).toResolve(); + await expect(reader.read()).toReject(); + + await rpcServer.destroy(); + await rpcClient.destroy(); + }); + test('RPC client and server with infinite timeout', async () => { + // Set up a client and server with infinite timeout settings + const values = fc.array(rpcTestUtils.safeJsonValueArb, { minLength: 3 }); + + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends DuplexHandler { + public handle = async function* ( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ) { + ctx.signal.throwIfAborted(); + const abortProm = utils.promise(); + ctx.signal.addEventListener('abort', () => { + abortProm.rejectP(ctx.signal.reason); + }); + await abortProm.p; + }; + } + + const rpcServer = await RPCServer.createRPCServer({ + manifest: { testMethod: new TestMethod({}) }, + logger, + idGen, + handlerTimeoutTime: Infinity, + }); + rpcServer.handleStream({ ...serverPair, cancel: () => {} }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { testMethod: new DuplexCaller() }, + streamFactory: async () => ({ ...clientPair, cancel: () => {} }), + logger, + idGen, + }); + + const callerInterface = await rpcClient.methods.testMethod({ + timer: Infinity, + }); + + const writer = callerInterface.writable.getWriter(); + const reader = callerInterface.readable.getReader(); + + // Trigger a call that will hang indefinitely or for a long time #TODO + + // Write a value to the stream + const writePromise = writer.write(values[0]); + + // Trigger a read that will hang indefinitely + + const readPromise = reader.read(); + // Adding a randomized sleep here to check that neither timeout + const randomSleepTime = Math.floor(Math.random() * 1000) + 1; + // Random time between 1 and 1,000 ms + await utils.sleep(randomSleepTime); + // At this point, writePromise and readPromise should neither be resolved nor rejected + // because the server method is hanging. + + // Check if the promises are neither resolved nor rejected + const timeoutPromise = new Promise((resolve) => + setTimeout(() => resolve('timeout'), 1000), + ); + + const readStatus = await Promise.race([readPromise, timeoutPromise]); + // Check if read status is still pending; + + expect(readStatus).toBe('timeout'); + + // Expect neither to time out and verify that they can still handle other operations #TODO + await rpcServer.destroy(); + await rpcClient.destroy(); + }); + + testProp( + 'RPC Serializes and Deserializes ErrorRPCRemote', + [ + rpcTestUtils.safeJsonValueArb, + rpcTestUtils.errorArb(rpcTestUtils.errorArb()), + ], + async (value, error) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends UnaryHandler { + public handle = async ( + _input: JSONValue, + _cancel: (reason?: any) => void, + _meta: Record | undefined, + _ctx: ContextTimed, + ): Promise => { + throw error; + }; + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + sensitive: true, + logger, + idGen, + fromError: utils.fromError, + replacer: utils.replacer, + }); + rpcServer.handleStream({ ...serverPair, cancel: () => {} }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new UnaryCaller(), + }, + streamFactory: async () => { + return { ...clientPair, cancel: () => {} }; + }, + logger, + idGen, + }); + + const errorInstance = new ErrorRPCRemote( + { code: -32006 }, + 'Parse error', + { cause: error, data: 'The server responded with an error' }, + ); + + const serializedError = fromError(errorInstance); + const deserializedError = rpcClient.toError(serializedError); + + expect(deserializedError).toBeInstanceOf(ErrorRPCRemote); + + // Check properties explicitly + const { code, message, data } = deserializedError as ErrorRPCRemote; + expect(code).toBe(-32006); + expect(message).toBe('Parse error'); + expect(data).toBe('The server responded with an error'); + + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); + testProp( + 'RPC Serializes and Deserializes ErrorRPCRemote with Custom Replacer Function', + [ + rpcTestUtils.safeJsonValueArb, + rpcTestUtils.errorArb(rpcTestUtils.errorArb()), + ], + async (value, error) => { + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + + class TestMethod extends UnaryHandler { + public handle = async ( + _input: JSONValue, + _cancel: (reason?: any) => void, + _meta: Record | undefined, + _ctx: ContextTimed, + ): Promise => { + throw error; + }; + } + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + sensitive: true, + logger, + idGen, + fromError: utils.fromError, + replacer: utils.replacer, + }); + rpcServer.handleStream({ ...serverPair, cancel: () => {} }); + + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new UnaryCaller(), + }, + streamFactory: async () => { + return { ...clientPair, cancel: () => {} }; + }, + logger, + idGen, + }); + + const errorInstance = new ErrorRPCRemote( + { code: -32006 }, + 'Parse error', + { cause: error, data: 'asda' }, + ); + + const serializedError = JSON.parse( + JSON.stringify(fromError(errorInstance), replacer('data')), + ); + + const callProm = rpcClient.methods.testMethod(serializedError); + const catchError = await callProm.catch((e) => e); + + const deserializedError = toError(serializedError); + + expect(deserializedError).toBeInstanceOf(ErrorRPCRemote); + + // Check properties explicitly + const { code, message, data } = deserializedError as ErrorRPCRemote; + expect(code).toBe(-32006); + expect(message).toBe('Parse error'); + expect(data).toBe(undefined); + + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + ); +}); diff --git a/tests/rpc/RPCClient.test.ts b/tests/RPCClient.test.ts similarity index 96% rename from tests/rpc/RPCClient.test.ts rename to tests/RPCClient.test.ts index 589cd2c..ade9717 100644 --- a/tests/rpc/RPCClient.test.ts +++ b/tests/RPCClient.test.ts @@ -1,34 +1,34 @@ import type { ContextTimed } from '@matrixai/contexts'; -import type { JSONValue } from '../../src/types'; +import type { JSONValue } from '@/types'; import type { JSONRPCRequest, JSONRPCRequestMessage, JSONRPCResponse, JSONRPCResponseResult, RPCStream, -} from '../../src/types'; +} from '@/types'; +import type { IdGen } from '@/types'; import { TransformStream, ReadableStream } from 'stream/web'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { testProp, fc } from '@fast-check/jest'; +import RawCaller from '@/callers/RawCaller'; +import DuplexCaller from '@/callers/DuplexCaller'; +import ServerCaller from '@/callers/ServerCaller'; +import ClientCaller from '@/callers/ClientCaller'; +import UnaryCaller from '@/callers/UnaryCaller'; +import RPCClient from '@/RPCClient'; +import RPCServer from '@/RPCServer'; +import * as rpcErrors from '@/errors'; +import * as rpcUtilsMiddleware from '@/utils/middleware'; +import { promise, sleep } from '@/utils'; +import { ErrorRPCRemote } from '@/errors'; import * as rpcTestUtils from './utils'; -import RPCClient from '../../src/RPCClient'; -import RPCServer from '../../src/RPCServer'; -import * as rpcErrors from '../../src/errors'; -import { - ClientCaller, - DuplexCaller, - RawCaller, - ServerCaller, - UnaryCaller, -} from '../../src/callers'; -import * as rpcUtilsMiddleware from '../../src/utils/middleware'; -import { promise, sleep } from '../../src/utils'; -import { ErrorRPCRemote } from '../../src/errors'; describe(`${RPCClient.name}`, () => { const logger = new Logger(`${RPCServer.name} Test`, LogLevel.WARN, [ new StreamHandler(), ]); + const idGen: IdGen = () => Promise.resolve(null); const methodName = 'testMethod'; const specificMessageArb = fc @@ -72,6 +72,7 @@ describe(`${RPCClient.name}`, () => { manifest: {}, streamFactory: async () => streamPair, logger, + idGen, }); const callerInterface = await rpcClient.rawStreamCaller( 'testMethod', @@ -111,6 +112,7 @@ describe(`${RPCClient.name}`, () => { manifest: {}, streamFactory: async () => streamPair, logger, + idGen, }); const callerInterface = await rpcClient.duplexStreamCaller< JSONValue, @@ -153,6 +155,7 @@ describe(`${RPCClient.name}`, () => { manifest: {}, streamFactory: async () => streamPair, logger, + idGen, }); const callerInterface = await rpcClient.serverStreamCaller< JSONValue, @@ -195,6 +198,7 @@ describe(`${RPCClient.name}`, () => { manifest: {}, streamFactory: async () => streamPair, logger, + idGen, }); const { output, writable } = await rpcClient.clientStreamCaller< JSONValue, @@ -236,6 +240,7 @@ describe(`${RPCClient.name}`, () => { manifest: {}, streamFactory: async () => streamPair, logger, + idGen, }); const result = await rpcClient.unaryCaller( methodName, @@ -275,6 +280,7 @@ describe(`${RPCClient.name}`, () => { manifest: {}, streamFactory: async () => streamPair, logger, + idGen, }); const callerInterface = await rpcClient.duplexStreamCaller< JSONValue, @@ -314,6 +320,7 @@ describe(`${RPCClient.name}`, () => { manifest: {}, streamFactory: async () => streamPair, logger, + idGen, }); const callerInterface = await rpcClient.duplexStreamCaller< JSONValue, @@ -356,6 +363,7 @@ describe(`${RPCClient.name}`, () => { manifest: {}, streamFactory: async () => streamPair, logger, + idGen, }); const callerInterface = await rpcClient.duplexStreamCaller< JSONValue, @@ -404,6 +412,7 @@ describe(`${RPCClient.name}`, () => { }, ), logger, + idGen, }); const callerInterface = await rpcClient.duplexStreamCaller< @@ -472,6 +481,7 @@ describe(`${RPCClient.name}`, () => { }, ), logger, + idGen, }); const callerInterface = await rpcClient.duplexStreamCaller< @@ -513,6 +523,7 @@ describe(`${RPCClient.name}`, () => { }, streamFactory: async () => streamPair, logger, + idGen, }); const callerInterface = await rpcClient.methods.server(params); const values: Array = []; @@ -554,6 +565,7 @@ describe(`${RPCClient.name}`, () => { }, streamFactory: async () => streamPair, logger, + idGen, }); const { output, writable } = await rpcClient.methods.client(); const writer = writable.getWriter(); @@ -594,6 +606,7 @@ describe(`${RPCClient.name}`, () => { }, streamFactory: async () => streamPair, logger, + idGen, }); const result = await rpcClient.methods.unary(params); expect(result).toStrictEqual(message.result); @@ -645,6 +658,7 @@ describe(`${RPCClient.name}`, () => { }, streamFactory: async () => streamPair, logger, + idGen, }); const callerInterface = await rpcClient.methods.raw(headerParams); await callerInterface.readable.pipeTo(outputWritableStream); @@ -691,6 +705,7 @@ describe(`${RPCClient.name}`, () => { }, streamFactory: async () => streamPair, logger, + idGen, }); let count = 0; const callerInterface = await rpcClient.methods.duplex(); @@ -714,6 +729,7 @@ describe(`${RPCClient.name}`, () => { return {} as RPCStream; }, logger, + idGen, }); // @ts-ignore: ignoring type safety here expect(() => rpcClient.methods.someMethod()).toThrow(); @@ -735,6 +751,7 @@ describe(`${RPCClient.name}`, () => { }, streamKeepAliveTimeoutTime: 100, logger, + idGen, }); // Timing out on stream creation const callerInterfaceProm = rpcClient.rawStreamCaller('testMethod', {}); @@ -757,6 +774,7 @@ describe(`${RPCClient.name}`, () => { return {} as RPCStream; }, logger, + idGen, }); // Timing out on stream creation const callerInterfaceProm = rpcClient.rawStreamCaller( @@ -783,6 +801,7 @@ describe(`${RPCClient.name}`, () => { return {} as RPCStream; }, logger, + idGen, }); const abortController = new AbortController(); const rejectReason = Symbol('rejectReason'); @@ -823,6 +842,7 @@ describe(`${RPCClient.name}`, () => { return streamPair; }, logger, + idGen, }); // Timing out on stream await expect( @@ -859,6 +879,7 @@ describe(`${RPCClient.name}`, () => { return streamPair; }, logger, + idGen, }); const abortController = new AbortController(); const rejectReason = Symbol('rejectReason'); @@ -899,6 +920,7 @@ describe(`${RPCClient.name}`, () => { }, streamKeepAliveTimeoutTime: 100, logger, + idGen, }); // Timing out on stream creation const callerInterfaceProm = rpcClient.duplexStreamCaller('testMethod'); @@ -921,6 +943,7 @@ describe(`${RPCClient.name}`, () => { return {} as RPCStream; }, logger, + idGen, }); // Timing out on stream creation const callerInterfaceProm = rpcClient.duplexStreamCaller('testMethod', { @@ -945,6 +968,7 @@ describe(`${RPCClient.name}`, () => { return {} as RPCStream; }, logger, + idGen, }); const abortController = new AbortController(); const rejectReason = Symbol('rejectReason'); @@ -983,6 +1007,7 @@ describe(`${RPCClient.name}`, () => { }, streamKeepAliveTimeoutTime: 100, logger, + idGen, }); // Timing out on stream @@ -1014,6 +1039,7 @@ describe(`${RPCClient.name}`, () => { return streamPair; }, logger, + idGen, }); // Timing out on stream @@ -1050,6 +1076,7 @@ describe(`${RPCClient.name}`, () => { return streamPair; }, logger, + idGen, }); const abortController = new AbortController(); const rejectReason = Symbol('rejectReason'); @@ -1089,11 +1116,12 @@ describe(`${RPCClient.name}`, () => { return streamPair; }, logger, + idGen, }); const callerInterface = await rpcClient.duplexStreamCaller< JSONValue, JSONValue - >(methodName); + >(methodName, { timer: 200 }); const ctx = await ctxProm.p; // Reading refreshes timer @@ -1101,7 +1129,7 @@ describe(`${RPCClient.name}`, () => { await sleep(50); let timeLeft = ctx.timer.getTimeout(); const message = await reader.read(); - expect(ctx.timer.getTimeout()).toBeGreaterThan(timeLeft); + expect(ctx.timer.getTimeout()).toBeGreaterThanOrEqual(timeLeft); reader.releaseLock(); for await (const _ of callerInterface.readable) { // Do nothing @@ -1112,7 +1140,7 @@ describe(`${RPCClient.name}`, () => { await sleep(50); timeLeft = ctx.timer.getTimeout(); await writer.write(message.value); - expect(ctx.timer.getTimeout()).toBeGreaterThan(timeLeft); + expect(ctx.timer.getTimeout()).toBeGreaterThanOrEqual(timeLeft); await writer.close(); await outputResult; @@ -1150,6 +1178,7 @@ describe(`${RPCClient.name}`, () => { }, ), logger, + idGen, }); const callerInterface = await rpcClient.duplexStreamCaller< JSONValue, diff --git a/tests/rpc/RPCServer.test.ts b/tests/RPCServer.test.ts similarity index 85% rename from tests/rpc/RPCServer.test.ts rename to tests/RPCServer.test.ts index a695102..80213ae 100644 --- a/tests/rpc/RPCServer.test.ts +++ b/tests/RPCServer.test.ts @@ -6,29 +6,29 @@ import type { JSONRPCResponseError, JSONValue, RPCStream, -} from '../../src/types'; -import type { RPCErrorEvent } from '../../src/events'; +} from '@/types'; +import type { RPCErrorEvent } from '@/events'; +import type { IdGen } from '@/types'; import { ReadableStream, TransformStream, WritableStream } from 'stream/web'; import { fc, testProp } from '@fast-check/jest'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import RPCServer from '@/RPCServer'; +import * as rpcErrors from '@/errors/errors'; +import * as rpcUtils from '@/utils'; +import { promise, sleep } from '@/utils'; +import * as rpcUtilsMiddleware from '@/utils/middleware'; +import ServerHandler from '@/handlers/ServerHandler'; +import DuplexHandler from '@/handlers/DuplexHandler'; +import RawHandler from '@/handlers/RawHandler'; +import UnaryHandler from '@/handlers/UnaryHandler'; +import ClientHandler from '@/handlers/ClientHandler'; import * as rpcTestUtils from './utils'; -import RPCServer from '../../src/RPCServer'; -import * as rpcErrors from '../../src/errors/errors'; -import * as rpcUtils from '../../src/utils'; -import { promise, sleep } from '../../src/utils'; -import { - ClientHandler, - DuplexHandler, - RawHandler, - ServerHandler, - UnaryHandler, -} from '../../src/handlers'; -import * as rpcUtilsMiddleware from '../../src/utils/middleware'; describe(`${RPCServer.name}`, () => { const logger = new Logger(`${RPCServer.name} Test`, LogLevel.WARN, [ new StreamHandler(), ]); + const idGen: IdGen = () => Promise.resolve(null); const methodName = 'testMethod'; const specificMessageArb = fc .array(rpcTestUtils.jsonRpcRequestMessageArb(fc.constant(methodName)), { @@ -66,12 +66,12 @@ describe(`${RPCServer.name}`, () => { rpcTestUtils.binaryStreamToSnippedStream([4, 7, 13, 2, 6]), ); class TestHandler extends RawHandler { - public async handle( + public handle = async ( input: [JSONRPCRequest, ReadableStream], cancel: (reason?: any) => void, meta: Record | undefined, ctx: ContextTimed, - ): Promise<[JSONValue, ReadableStream]> { + ): Promise<[JSONValue, ReadableStream]> => { for await (const _ of input[1]) { // No touch, only consume } @@ -82,13 +82,15 @@ describe(`${RPCServer.name}`, () => { }, }); return Promise.resolve([null, readableStream]); - } + }; } + const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestHandler({}), }, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -108,20 +110,24 @@ describe(`${RPCServer.name}`, () => { async (messages) => { const stream = rpcTestUtils.messagesToReadableStream(messages); class TestMethod extends DuplexHandler { - public async *handle( + public handle = async function* ( input: AsyncGenerator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, ): AsyncGenerator { for await (const val of input) { yield val; break; } - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestMethod({}), }, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -140,21 +146,25 @@ describe(`${RPCServer.name}`, () => { async (messages) => { const stream = rpcTestUtils.messagesToReadableStream(messages); class TestMethod extends ClientHandler { - public async handle( + public handle = async ( input: AsyncGenerator, - ): Promise { + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): Promise => { let count = 0; for await (const _ of input) { count += 1; } return count; - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestMethod({}), }, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -173,17 +183,20 @@ describe(`${RPCServer.name}`, () => { async (messages) => { const stream = rpcTestUtils.messagesToReadableStream(messages); class TestMethod extends ServerHandler { - public async *handle(input: number): AsyncGenerator { + public handle = async function* ( + input: number, + ): AsyncGenerator { for (let i = 0; i < input; i++) { yield i; } - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestMethod({}), }, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -202,15 +215,16 @@ describe(`${RPCServer.name}`, () => { async (messages) => { const stream = rpcTestUtils.messagesToReadableStream(messages); class TestMethod extends UnaryHandler { - public async handle(input: JSONValue): Promise { + public handle = async (input: JSONValue): Promise => { return input; - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestMethod({}), }, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -234,14 +248,17 @@ describe(`${RPCServer.name}`, () => { C: Symbol('c'), }; class TestMethod extends DuplexHandler { - public async *handle( + public handle = async function* ( input: AsyncGenerator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, ): AsyncGenerator { expect(this.container).toBe(container); for await (const val of input) { yield val; } - } + }; } const rpcServer = await RPCServer.createRPCServer({ @@ -249,6 +266,7 @@ describe(`${RPCServer.name}`, () => { testMethod: new TestMethod(container), }, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -275,22 +293,24 @@ describe(`${RPCServer.name}`, () => { }; let handledMeta; class TestMethod extends DuplexHandler { - public async *handle( + public handle = async function* ( input: AsyncGenerator, - _cancel, - meta, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, ): AsyncGenerator { handledMeta = meta; for await (const val of input) { yield val; } - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestMethod({}), }, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -308,23 +328,24 @@ describe(`${RPCServer.name}`, () => { testProp('handler can be aborted', [specificMessageArb], async (messages) => { const stream = rpcTestUtils.messagesToReadableStream(messages); class TestMethod extends DuplexHandler { - public async *handle( + public handle = async function* ( input: AsyncGenerator, - _cancel, - _meta, + cancel: (reason?: any) => void, + meta: Record | undefined, ctx: ContextTimed, ): AsyncGenerator { for await (const val of input) { if (ctx.signal.aborted) throw ctx.signal.reason; yield val; } - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestMethod({}), }, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); @@ -361,19 +382,23 @@ describe(`${RPCServer.name}`, () => { testProp('handler yields nothing', [specificMessageArb], async (messages) => { const stream = rpcTestUtils.messagesToReadableStream(messages); class TestMethod extends DuplexHandler { - public async *handle( + public handle = async function* ( input: AsyncGenerator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, ): AsyncGenerator { for await (const _ of input) { // Do nothing, just consume } - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestMethod({}), }, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -392,15 +417,16 @@ describe(`${RPCServer.name}`, () => { async (messages, error) => { const stream = rpcTestUtils.messagesToReadableStream(messages); class TestMethod extends DuplexHandler { - public async *handle(): AsyncGenerator { + public handle = async function* (): AsyncGenerator { throw error; - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestMethod({}), }, logger, + idGen, }); let resolve, reject; const errorProm = new Promise((resolve_, reject_) => { @@ -418,9 +444,7 @@ describe(`${RPCServer.name}`, () => { }; rpcServer.handleStream(readWriteStream); const rawErrorMessage = (await outputResult)[0]!.toString(); - expect(rawErrorMessage).toInclude('stack'); const errorMessage = JSON.parse(rawErrorMessage); - expect(errorMessage.error.code).toEqual(error.exitCode); expect(errorMessage.error.message).toEqual(error.description); reject(); await expect(errorProm).toReject(); @@ -433,16 +457,18 @@ describe(`${RPCServer.name}`, () => { async (messages, error) => { const stream = rpcTestUtils.messagesToReadableStream(messages); class TestMethod extends DuplexHandler { - public async *handle(): AsyncGenerator { + public handle = async function* (): AsyncGenerator { throw error; - } + }; } + const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestMethod({}), }, sensitive: true, logger, + idGen, }); let resolve, reject; const errorProm = new Promise((resolve_, reject_) => { @@ -460,9 +486,7 @@ describe(`${RPCServer.name}`, () => { }; rpcServer.handleStream(readWriteStream); const rawErrorMessage = (await outputResult)[0]!.toString(); - expect(rawErrorMessage).not.toInclude('stack'); const errorMessage = JSON.parse(rawErrorMessage); - expect(errorMessage.error.code).toEqual(error.exitCode); expect(errorMessage.error.message).toEqual(error.description); reject(); await expect(errorProm).toReject(); @@ -475,7 +499,7 @@ describe(`${RPCServer.name}`, () => { async (messages) => { const handlerEndedProm = promise(); class TestMethod extends DuplexHandler { - public async *handle(input): AsyncGenerator { + public handle = async function* (input): AsyncGenerator { try { for await (const _ of input) { // Consume but don't yield anything @@ -483,13 +507,14 @@ describe(`${RPCServer.name}`, () => { } finally { handlerEndedProm.resolveP(); } - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestMethod({}), }, logger, + idGen, }); let resolve; rpcServer.addEventListener('error', (thing: RPCErrorEvent) => { @@ -529,7 +554,7 @@ describe(`${RPCServer.name}`, () => { const handlerEndedProm = promise(); let ctx: ContextTimed | undefined; class TestMethod extends DuplexHandler { - public async *handle( + public handle = async function* ( input, _cancel, _meta, @@ -542,13 +567,14 @@ describe(`${RPCServer.name}`, () => { } finally { handlerEndedProm.resolveP(); } - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestMethod({}), }, logger, + idGen, }); let resolve; const errorProm = new Promise((resolve_) => { @@ -584,8 +610,7 @@ describe(`${RPCServer.name}`, () => { const event = await errorProm; await writer.close(); // Expect(event.detail.cause).toContain(writerReason); - expect(event.detail).toBeInstanceOf(rpcErrors.ErrorRPCOutputStreamError); - expect(event.detail.cause).toBe(readerReason); + expect(event.detail).toBeInstanceOf(rpcErrors.ErrorRPCStreamEnded); // Check that the handler was cleaned up. await expect(handlerEndedProm.p).toResolve(); // Check that an abort signal happened @@ -599,11 +624,14 @@ describe(`${RPCServer.name}`, () => { testProp('forward middlewares', [specificMessageArb], async (messages) => { const stream = rpcTestUtils.messagesToReadableStream(messages); class TestMethod extends DuplexHandler { - public async *handle( + public handle = async function* ( input: AsyncGenerator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, ): AsyncGenerator { yield* input; - } + }; } const middlewareFactory = rpcUtilsMiddleware.defaultServerMiddlewareWrapper( () => { @@ -624,6 +652,7 @@ describe(`${RPCServer.name}`, () => { }, middlewareFactory: middlewareFactory, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -647,11 +676,14 @@ describe(`${RPCServer.name}`, () => { testProp('reverse middlewares', [specificMessageArb], async (messages) => { const stream = rpcTestUtils.messagesToReadableStream(messages); class TestMethod extends DuplexHandler { - public async *handle( + public handle = async function* ( input: AsyncGenerator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, ): AsyncGenerator { yield* input; - } + }; } const middleware = rpcUtilsMiddleware.defaultServerMiddlewareWrapper(() => { return { @@ -670,6 +702,7 @@ describe(`${RPCServer.name}`, () => { }, middlewareFactory: middleware, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -696,11 +729,14 @@ describe(`${RPCServer.name}`, () => { async (message) => { const stream = rpcTestUtils.messagesToReadableStream([message]); class TestMethod extends DuplexHandler { - public async *handle( + public handle = async function* ( input: AsyncGenerator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, ): AsyncGenerator { yield* input; - } + }; } const middleware = rpcUtilsMiddleware.defaultServerMiddlewareWrapper( () => { @@ -740,6 +776,7 @@ describe(`${RPCServer.name}`, () => { }, middlewareFactory: middleware, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -775,12 +812,12 @@ describe(`${RPCServer.name}`, () => { // Diagnostic log to indicate the start of the test class TestHandler extends RawHandler { - public async handle( + public handle = async ( _input: [JSONRPCRequest, ReadableStream], _cancel: (reason?: any) => void, _meta: Record | undefined, ctx_: ContextTimed, - ): Promise<[JSONValue, ReadableStream]> { + ): Promise<[JSONValue, ReadableStream]> => { return new Promise((resolve, reject) => { ctxProm.resolveP(ctx_); @@ -798,7 +835,7 @@ describe(`${RPCServer.name}`, () => { // Return something to fulfill the Promise type expectation. resolve([null, stream]); }); - } + }; } const rpcServer = await RPCServer.createRPCServer({ @@ -807,6 +844,7 @@ describe(`${RPCServer.name}`, () => { }, handlerTimeoutTime: 100, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); @@ -848,6 +886,7 @@ describe(`${RPCServer.name}`, () => { manifest: {}, handlerTimeoutTime: 100, logger, + idGen, }); const readWriteStream: RPCStream = { cancel: () => {}, @@ -875,30 +914,30 @@ describe(`${RPCServer.name}`, () => { const ctxShortProm = promise(); class TestMethodShortTimeout extends UnaryHandler { timeout = 25; - public async handle( + public handle = async ( input: JSONValue, _cancel, _meta, ctx_, - ): Promise { + ): Promise => { ctxShortProm.resolveP(ctx_); await waitProm.p; return input; - } + }; } const ctxLongProm = promise(); class TestMethodLongTimeout extends UnaryHandler { timeout = 100; - public async handle( + public handle = async ( input: JSONValue, _cancel, _meta, ctx_, - ): Promise { + ): Promise => { ctxLongProm.resolveP(ctx_); await waitProm.p; return input; - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { @@ -907,6 +946,7 @@ describe(`${RPCServer.name}`, () => { }, handlerTimeoutTime: 50, logger, + idGen, }); const streamShort = rpcTestUtils.messagesToReadableStream([ { @@ -951,11 +991,11 @@ describe(`${RPCServer.name}`, () => { const stepProm2 = promise(); const passthroughStream = new TransformStream(); class TestHandler extends DuplexHandler { - public async *handle( + public handle = async function* ( input: AsyncGenerator, - _cancel, - _meta, - ctx, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, ): AsyncGenerator { contextProm.resolveP(ctx); for await (const _ of input) { @@ -965,13 +1005,15 @@ describe(`${RPCServer.name}`, () => { yield 1; await stepProm2.p; yield 2; - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestHandler({}), }, logger, + idGen, + handlerTimeoutTime: 1000, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const requestMessage = Buffer.from( @@ -1013,12 +1055,12 @@ describe(`${RPCServer.name}`, () => { test('stream ending cleans up timer and abortSignal', async () => { const ctxProm = promise(); class TestHandler extends RawHandler { - public async handle( + public handle = async ( input: [JSONRPCRequest, ReadableStream], _cancel: (reason?: any) => void, _meta: Record | undefined, ctx_: ContextTimed, - ): Promise<[JSONValue, ReadableStream]> { + ): Promise<[JSONValue, ReadableStream]> => { return new Promise((resolve) => { ctxProm.resolveP(ctx_); void (async () => { @@ -1033,13 +1075,14 @@ describe(`${RPCServer.name}`, () => { }); resolve([null, readableStream]); }); - } + }; } const rpcServer = await RPCServer.createRPCServer({ manifest: { testMethod: new TestHandler({}), }, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const stream = rpcTestUtils.messagesToReadableStream([ @@ -1064,58 +1107,6 @@ describe(`${RPCServer.name}`, () => { await expect(ctx.timer).toReject(); await rpcServer.destroy(); }); - test('Timeout has a grace period before forcing the streams closed', async () => { - const ctxProm = promise(); - class TestHandler extends RawHandler { - public async handle( - input: [JSONRPCRequest, ReadableStream], - cancel: (reason?: any) => void, - meta: Record | undefined, - ctx: ContextTimed, - ): Promise<[JSONValue, ReadableStream]> { - ctxProm.resolveP(ctx); - - return Promise.resolve([null, new ReadableStream()]); - } - } - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestHandler({}), - }, - handlerTimeoutTime: 50, - handlerTimeoutGraceTime: 100, - logger, - }); - const [, outputStream] = rpcTestUtils.streamToArray(); - const stream = rpcTestUtils.messagesToReadableStream([ - { - jsonrpc: '2.0', - method: 'testMethod', - params: null, - }, - { - jsonrpc: '2.0', - method: 'testMethod', - params: null, - }, - ]); - const cancelProm = promise(); - const readWriteStream: RPCStream = { - cancel: (reason) => cancelProm.resolveP(reason), - readable: stream, - writable: outputStream, - }; - rpcServer.handleStream(readWriteStream); - const ctx = await ctxProm.p; - await ctx.timer; - const then = Date.now(); - expect(ctx.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCTimedOut); - // Should end after grace period - await expect(cancelProm.p).resolves.toBeInstanceOf( - rpcErrors.ErrorRPCTimedOut, - ); - expect(Date.now() - then).toBeGreaterThanOrEqual(90); - }); testProp( 'middleware can update timeout timer', [specificMessageArb], @@ -1123,15 +1114,15 @@ describe(`${RPCServer.name}`, () => { const stream = rpcTestUtils.messagesToReadableStream(messages); const ctxProm = promise(); class TestMethod extends DuplexHandler { - public async *handle( + public handle = async function* ( input: AsyncGenerator, - _cancel, - _meta, - ctx, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, ): AsyncGenerator { ctxProm.resolveP(ctx); yield* input; - } + }; } const middlewareFactory = rpcUtilsMiddleware.defaultServerMiddlewareWrapper((ctx) => { @@ -1147,6 +1138,7 @@ describe(`${RPCServer.name}`, () => { }, middlewareFactory: middlewareFactory, logger, + idGen, }); const [outputResult, outputStream] = rpcTestUtils.streamToArray(); const readWriteStream: RPCStream = { @@ -1160,56 +1152,4 @@ describe(`${RPCServer.name}`, () => { expect(ctx.timer.delay).toBe(12345); }, ); - test('destroying the `RPCServer` sends an abort signal and closes connection', async () => { - const ctxProm = promise(); - class TestHandler extends RawHandler { - public async handle( - input: [JSONRPCRequest, ReadableStream], - _cancel: (reason?: any) => void, - _meta: Record | undefined, - ctx_: ContextTimed, - ): Promise<[JSONValue, ReadableStream]> { - return new Promise((resolve) => { - ctxProm.resolveP(ctx_); - // Echo messages - return [null, input[1]]; - }); - } - } - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestHandler({}), - }, - handlerTimeoutGraceTime: 0, - logger, - }); - const [, outputStream] = rpcTestUtils.streamToArray(); - const message = Buffer.from( - JSON.stringify({ - jsonrpc: '2.0', - method: 'testMethod', - params: null, - }), - ); - const forwardStream = new TransformStream(); - const cancelProm = promise(); - const readWriteStream: RPCStream = { - cancel: (reason) => cancelProm.resolveP(reason), - readable: forwardStream.readable, - writable: outputStream, - }; - rpcServer.handleStream(readWriteStream); - const writer = forwardStream.writable.getWriter(); - await writer.write(message); - const ctx = await ctxProm.p; - void rpcServer.destroy(true).then( - () => {}, - () => {}, - ); - await expect(cancelProm.p).resolves.toBeInstanceOf( - rpcErrors.ErrorRPCStopping, - ); - expect(ctx.signal.reason).toBeInstanceOf(rpcErrors.ErrorRPCStopping); - await writer.close(); - }); }); diff --git a/tests/rpc/RPC.test.ts b/tests/rpc/RPC.test.ts deleted file mode 100644 index df37bce..0000000 --- a/tests/rpc/RPC.test.ts +++ /dev/null @@ -1,555 +0,0 @@ -import type { ContainerType, JSONRPCRequest } from '../../src/types'; -import type { ReadableStream } from 'stream/web'; -import type { JSONValue } from '../../src/types'; -import { TransformStream } from 'stream/web'; -import { fc, testProp } from '@fast-check/jest'; -import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import * as rpcTestUtils from './utils'; -import * as utils from '../../src/utils'; -import RPCServer from '../../src/RPCServer'; -import RPCClient from '../../src/RPCClient'; -import { - ClientHandler, - DuplexHandler, - RawHandler, - ServerHandler, - UnaryHandler, -} from '../../src/handlers'; -import { - ClientCaller, - DuplexCaller, - RawCaller, - ServerCaller, - UnaryCaller, -} from '../../src/callers'; -import * as rpcErrors from '../../src/errors'; -import { ErrorRPC } from '../../src/errors'; -import * as rpcUtilsMiddleware from '../../src/utils/middleware'; - -describe('RPC', () => { - const logger = new Logger(`RPC Test`, LogLevel.WARN, [new StreamHandler()]); - - testProp( - 'RPC communication with raw stream', - [rpcTestUtils.rawDataArb], - async (inputData) => { - const [outputResult, outputWriterStream] = - rpcTestUtils.streamToArray(); - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); - - let header: JSONRPCRequest | undefined; - - class TestMethod extends RawHandler { - public async handle( - input: [JSONRPCRequest, ReadableStream], - _cancel: (reason?: any) => void, - _meta: Record | undefined, - ): Promise<[JSONValue, ReadableStream]> { - return new Promise((resolve) => { - const [header_, stream] = input; - header = header_; - resolve(['some leading data', stream]); - }); - } - } - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestMethod({}), - }, - logger, - }); - rpcServer.handleStream({ - ...serverPair, - cancel: () => {}, - }); - - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new RawCaller(), - }, - streamFactory: async () => { - return { - ...clientPair, - cancel: () => {}, - }; - }, - logger, - }); - - const callerInterface = await rpcClient.methods.testMethod({ - hello: 'world', - }); - const writer = callerInterface.writable.getWriter(); - const pipeProm = callerInterface.readable.pipeTo(outputWriterStream); - for (const value of inputData) { - await writer.write(value); - } - await writer.close(); - const expectedHeader: JSONRPCRequest = { - jsonrpc: '2.0', - method: 'testMethod', - params: { hello: 'world' }, - id: null, - }; - expect(header).toStrictEqual(expectedHeader); - expect(callerInterface.meta?.result).toBe('some leading data'); - expect(await outputResult).toStrictEqual(inputData); - await pipeProm; - await rpcServer.destroy(); - await rpcClient.destroy(); - }, - ); - test('RPC communication with raw stream times out waiting for leading message', async () => { - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); - void (async () => { - for await (const _ of serverPair.readable) { - // Just consume - } - })(); - - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new RawCaller(), - }, - streamFactory: async () => { - return { - ...clientPair, - cancel: () => {}, - }; - }, - logger, - }); - - await expect( - rpcClient.methods.testMethod( - { - hello: 'world', - }, - { timer: 100 }, - ), - ).rejects.toThrow(rpcErrors.ErrorRPCTimedOut); - await rpcClient.destroy(); - }); - test('RPC communication with raw stream, raw handler throws', async () => { - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); - - class TestMethod extends RawHandler { - public async handle(): Promise< - [JSONRPCRequest, ReadableStream] - > { - throw Error('some error'); - } - } - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestMethod({}), - }, - logger, - }); - rpcServer.handleStream({ - ...serverPair, - cancel: () => {}, - }); - - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new RawCaller(), - }, - streamFactory: async () => { - return { - ...clientPair, - cancel: () => {}, - }; - }, - logger, - }); - - await expect( - rpcClient.methods.testMethod({ - hello: 'world', - }), - ).rejects.toThrow(rpcErrors.ErrorRPCRemote); - - await rpcServer.destroy(); - await rpcClient.destroy(); - }); - testProp( - 'RPC communication with duplex stream', - [fc.array(rpcTestUtils.safeJsonValueArb, { minLength: 1 })], - async (values) => { - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); - class TestMethod extends DuplexHandler { - public async *handle( - input: AsyncGenerator, - ): AsyncGenerator { - yield* input; - } - } - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestMethod({}), - }, - logger, - }); - rpcServer.handleStream({ - ...serverPair, - cancel: () => {}, - }); - - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new DuplexCaller(), - }, - streamFactory: async () => { - return { - ...clientPair, - cancel: () => {}, - }; - }, - logger, - }); - - const callerInterface = await rpcClient.methods.testMethod(); - const writer = callerInterface.writable.getWriter(); - const reader = callerInterface.readable.getReader(); - for (const value of values) { - await writer.write(value); - expect((await reader.read()).value).toStrictEqual(value); - } - await writer.close(); - const result = await reader.read(); - expect(result.value).toBeUndefined(); - expect(result.done).toBeTrue(); - await rpcServer.destroy(); - await rpcClient.destroy(); - }, - ); - testProp( - 'RPC communication with server stream', - [fc.integer({ min: 1, max: 100 })], - async (value) => { - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); - - class TestMethod extends ServerHandler { - public async *handle(input: number): AsyncGenerator { - for (let i = 0; i < input; i++) { - yield i; - } - } - } - - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestMethod({}), - }, - logger, - }); - rpcServer.handleStream({ - ...serverPair, - cancel: () => {}, - }); - - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new ServerCaller(), - }, - streamFactory: async () => { - return { - ...clientPair, - cancel: () => {}, - }; - }, - logger, - }); - - const callerInterface = await rpcClient.methods.testMethod(value); - - const outputs: Array = []; - for await (const num of callerInterface) { - outputs.push(num); - } - expect(outputs.length).toEqual(value); - await rpcServer.destroy(); - await rpcClient.destroy(); - }, - ); - testProp( - 'RPC communication with client stream', - [fc.array(fc.integer(), { minLength: 1 }).noShrink()], - async (values) => { - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); - - class TestMethod extends ClientHandler { - public async handle(input: AsyncIterable): Promise { - let acc = 0; - for await (const number of input) { - acc += number; - } - return acc; - } - } - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestMethod({}), - }, - logger, - }); - rpcServer.handleStream({ - ...serverPair, - cancel: () => {}, - }); - - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new ClientCaller(), - }, - streamFactory: async () => { - return { - ...clientPair, - cancel: () => {}, - }; - }, - logger, - }); - - const { output, writable } = await rpcClient.methods.testMethod(); - const writer = writable.getWriter(); - for (const value of values) { - await writer.write(value); - } - await writer.close(); - const expectedResult = values.reduce((p, c) => p + c); - await expect(output).resolves.toEqual(expectedResult); - await rpcServer.destroy(); - await rpcClient.destroy(); - }, - ); - testProp( - 'RPC communication with unary call', - [rpcTestUtils.safeJsonValueArb], - async (value) => { - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); - - class TestMethod extends UnaryHandler { - public async handle(input: JSONValue): Promise { - return input; - } - } - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestMethod({}), - }, - logger, - }); - rpcServer.handleStream({ - ...serverPair, - cancel: () => {}, - }); - - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new UnaryCaller(), - }, - streamFactory: async () => { - return { - ...clientPair, - cancel: () => {}, - }; - }, - logger, - }); - - const result = await rpcClient.methods.testMethod(value); - expect(result).toStrictEqual(value); - await rpcServer.destroy(); - await rpcClient.destroy(); - }, - ); - testProp( - 'RPC handles and sends errors', - [ - rpcTestUtils.safeJsonValueArb, - rpcTestUtils.errorArb(rpcTestUtils.errorArb()), - ], - async (value, error) => { - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); - - class TestMethod extends UnaryHandler { - public async handle(): Promise { - throw error; - } - } - - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestMethod({}), - }, - logger, - }); - rpcServer.handleStream({ ...serverPair, cancel: () => {} }); - - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new UnaryCaller(), - }, - streamFactory: async () => { - return { ...clientPair, cancel: () => {} }; - }, - logger, - }); - - // Create a new promise so we can await it multiple times for assertions - const callProm = rpcClient.methods.testMethod(value).catch((e) => e); - - // The promise should be rejected - const rejection = await callProm; - expect(rejection).toBeInstanceOf(rpcErrors.ErrorRPCRemote); - - // The error should have specific properties - expect(rejection).toMatchObject({ exitCode: 69 }); - - // Cleanup - await rpcServer.destroy(); - await rpcClient.destroy(); - }, - ); - - testProp( - 'RPC handles and sends sensitive errors', - [ - rpcTestUtils.safeJsonValueArb, - rpcTestUtils.errorArb(rpcTestUtils.errorArb()), - ], - async (value, error) => { - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); - - class TestMethod extends UnaryHandler { - public async handle(): Promise { - throw error; - } - } - - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestMethod({}), - }, - sensitive: true, - logger, - }); - rpcServer.handleStream({ ...serverPair, cancel: () => {} }); - - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new UnaryCaller(), - }, - streamFactory: async () => { - return { ...clientPair, cancel: () => {} }; - }, - logger, - }); - - const callProm = rpcClient.methods.testMethod(value); - - // Use Jest's `.rejects` to handle the promise rejection - await expect(callProm).rejects.toBeInstanceOf(rpcErrors.ErrorRPCRemote); - await expect(callProm).rejects.toHaveProperty('cause', error); - await expect(callProm).rejects.not.toHaveProperty('cause.stack'); - - await rpcServer.destroy(); - await rpcClient.destroy(); - }, - ); - - test('middleware can end stream early', async () => { - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); - class TestMethod extends DuplexHandler { - public async *handle( - input: AsyncIterableIterator, - ): AsyncIterableIterator { - yield* input; - } - } - const middleware = rpcUtilsMiddleware.defaultServerMiddlewareWrapper(() => { - return { - forward: new TransformStream({ - start: (controller) => { - // Controller.terminate(); - controller.error(Error('SOME ERROR')); - }, - }), - reverse: new TransformStream({ - start: (controller) => { - controller.error(Error('SOME ERROR')); - }, - }), - }; - }); - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestMethod({}), - }, - middlewareFactory: middleware, - logger, - }); - rpcServer.handleStream({ - ...serverPair, - cancel: () => {}, - }); - - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new DuplexCaller(), - }, - streamFactory: async () => { - return { - ...clientPair, - cancel: () => {}, - }; - }, - logger, - }); - - const callerInterface = await rpcClient.methods.testMethod(); - const writer = callerInterface.writable.getWriter(); - await writer.write({}); - // Allow time to process buffer - await utils.sleep(0); - await expect(writer.write({})).toReject(); - const reader = callerInterface.readable.getReader(); - await expect(reader.read()).toReject(); - await expect(writer.closed).toReject(); - await expect(reader.closed).toReject(); - await expect(rpcServer.destroy(false)).toResolve(); - await rpcClient.destroy(); - }); -}); diff --git a/tests/rpc/utils.ts b/tests/utils.ts similarity index 93% rename from tests/rpc/utils.ts rename to tests/utils.ts index 4c779ee..b10c37d 100644 --- a/tests/rpc/utils.ts +++ b/tests/utils.ts @@ -1,5 +1,5 @@ import type { ReadableWritablePair } from 'stream/web'; -import type { JSONValue } from '../../src/types'; +import type { JSONValue } from '@/types'; import type { JSONRPCError, JSONRPCMessage, @@ -9,13 +9,13 @@ import type { JSONRPCResponseResult, JSONRPCResponse, JSONRPCRequest, -} from '../../src/types'; +} from '@/types'; import { ReadableStream, WritableStream, TransformStream } from 'stream/web'; import { fc } from '@fast-check/jest'; -import { IdInternal } from '@matrixai/id'; -import * as utils from '../../src/utils'; -import { fromError } from '../../src/utils'; -import * as rpcErrors from '../../src/errors'; +import * as utils from '@/utils'; +import { fromError } from '@/utils'; +import * as rpcErrors from '@/errors'; +import { ErrorRPC } from '@/errors'; /** * This is used to convert regular chunks into randomly sized chunks based on @@ -143,15 +143,14 @@ const jsonRpcResponseResultArb = ( }) .noShrink() as fc.Arbitrary; const jsonRpcErrorArb = ( - error: fc.Arbitrary = fc.constant(new Error('test error')), - sensitive: boolean = false, + error: fc.Arbitrary> = fc.constant(new ErrorRPC('test error')), ) => fc .record( { code: fc.integer(), message: fc.string(), - data: error.map((e) => fromError(e, sensitive)), + data: error.map((e) => JSON.stringify(fromError(e))), }, { requiredKeys: ['code', 'message'], @@ -160,13 +159,13 @@ const jsonRpcErrorArb = ( .noShrink() as fc.Arbitrary; const jsonRpcResponseErrorArb = ( - error?: fc.Arbitrary, + error?: fc.Arbitrary>, sensitive: boolean = false, ) => fc .record({ jsonrpc: fc.constant('2.0'), - error: jsonRpcErrorArb(error, sensitive), + error: jsonRpcErrorArb(error), id: idArb, }) .noShrink() as fc.Arbitrary; @@ -261,7 +260,7 @@ const errorArb = ( ) => cause.chain((cause) => fc.oneof( - fc.constant(new rpcErrors.ErrorRPCRemote(undefined)), + fc.constant(new rpcErrors.ErrorRPCRemote()), fc.constant(new rpcErrors.ErrorRPCMessageLength(undefined)), fc.constant( new rpcErrors.ErrorRPCRemote( diff --git a/tests/rpc/utils/middleware.test.ts b/tests/utils/middleware.test.ts similarity index 93% rename from tests/rpc/utils/middleware.test.ts rename to tests/utils/middleware.test.ts index a995b8c..bf744a7 100644 --- a/tests/rpc/utils/middleware.test.ts +++ b/tests/utils/middleware.test.ts @@ -1,10 +1,12 @@ +import type { JSONRPCMessage, JSONValue } from '@/types'; +import { TransformStream } from 'stream/web'; import { fc, testProp } from '@fast-check/jest'; import { JSONParser } from '@streamparser/json'; import { AsyncIterableX as AsyncIterable } from 'ix/asynciterable'; -import * as rpcUtils from '../../../src/utils'; +import * as rpcUtils from '@/utils'; import 'ix/add/asynciterable-operators/toarray'; -import * as rpcErrors from '../../../src/errors'; -import * as rpcUtilsMiddleware from '../../../src/utils/middleware'; +import * as rpcErrors from '@/errors'; +import * as rpcUtilsMiddleware from '@/utils/middleware'; import * as rpcTestUtils from '../utils'; describe('Middleware tests', () => { diff --git a/tests/rpc/utils/utils.test.ts b/tests/utils/utils.test.ts similarity index 93% rename from tests/rpc/utils/utils.test.ts rename to tests/utils/utils.test.ts index c5b1645..8594ce7 100644 --- a/tests/rpc/utils/utils.test.ts +++ b/tests/utils/utils.test.ts @@ -1,6 +1,6 @@ import { testProp, fc } from '@fast-check/jest'; import { JSONParser } from '@streamparser/json'; -import * as rpcUtils from '../../../src/utils'; +import * as rpcUtils from '@/utils'; import 'ix/add/asynciterable-operators/toarray'; import * as rpcTestUtils from '../utils'; diff --git a/tsconfig.json b/tsconfig.json index 030dd67..a120436 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "experimentalDecorators": true, "outDir": "./dist", "tsBuildInfoFile": "./dist/tsbuildinfo", "incremental": true, @@ -9,6 +8,7 @@ "allowJs": true, "strictNullChecks": true, "noImplicitAny": false, + "experimentalDecorators": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "resolveJsonModule": true, From 39b046ab205646599bdd52978d3b07f21e822117 Mon Sep 17 00:00:00 2001 From: Aditya <38064122+bettercallav@users.noreply.github.com> Date: Tue, 26 Sep 2023 14:29:17 +1000 Subject: [PATCH 05/12] fix: docs for toError, fromError, replacer and reviver (no longer being used) related: #10 --- src/utils/utils.ts | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/utils/utils.ts b/src/utils/utils.ts index cec0611..8dbcab2 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -216,20 +216,11 @@ function parseJSONRPCMessage( 'Message structure did not match a `JSONRPCMessage`', ); } - -/** - * Replacer function for serialising errors over RPC (used by `JSON.stringify` - * in `fromError`) - * Polykey errors are handled by their inbuilt `toJSON` method , so this only - * serialises other errors - */ - /** - * Serializes Error instances into RPC errors - * Use this on the sending side to send exceptions - * Do not send exceptions to clients you do not trust - * If sending to an agent (rather than a client), set sensitive to true to - * prevent sensitive information from being sent over the network + * Serializes an ErrorRPC instance into a JSONValue object suitable for RPC. + * @param {ErrorRPC} error - The ErrorRPC instance to serialize. + * @param {any} [id] - Optional id for the error object in the RPC response. + * @returns {JSONValue} The serialized ErrorRPC instance. */ function fromError(error: ErrorRPC, id?: any): JSONValue { const data: { [key: string]: JSONValue } = { @@ -267,6 +258,10 @@ const standardErrors = { ErrorRPCRemote, ErrorRPC, }; +/** + * Creates a replacer function that omits a specific key during serialization. + * @returns {Function} The replacer function. + */ const createReplacer = () => { return (keyToRemove) => { return (key, value) => { @@ -300,14 +295,16 @@ const createReplacer = () => { }; }; }; +/** + * The replacer function to customize the serialization process. + */ const replacer = createReplacer(); /** - * Reviver function for deserialising errors sent over RPC (used by - * `JSON.parse` in `toError`) - * The final result returned will always be an error - if the deserialised - * data is of an unknown type then this will be wrapped as an - * `ErrorPolykeyUnknown` + * Reviver function for deserializing errors sent over RPC. + * @param {string} key - The key in the JSON object. + * @param {any} value - The value corresponding to the key in the JSON object. + * @returns {any} The reconstructed error object or the original value. */ function reviver(key: string, value: any): any { // If the value is an error then reconstruct it @@ -368,7 +365,13 @@ function reviver(key: string, value: any): any { return value; } } - +/** + * Deserializes an error response object into an ErrorRPCRemote instance. + * @param {any} errorResponse - The error response object. + * @param {any} [metadata] - Optional metadata for the deserialized error. + * @returns {ErrorRPCRemote} The deserialized ErrorRPCRemote instance. + * @throws {TypeError} If the errorResponse object is invalid. + */ function toError(errorResponse: any, metadata?: any): ErrorRPCRemote { if ( typeof errorResponse !== 'object' || From f2cba9e668ed7745057162cdc09e53a383ef5655 Mon Sep 17 00:00:00 2001 From: Aditya <38064122+bettercallav@users.noreply.github.com> Date: Tue, 26 Sep 2023 20:17:25 +1000 Subject: [PATCH 06/12] chore: lintfix fix: jests related to toError and fromError --- package-lock.json | 743 +++++++++++++++++++++++++++++++++++++++- src/RPCClient.ts | 8 +- src/RPCServer.ts | 2 + src/errors/errors.ts | 30 +- src/types.ts | 4 + src/utils/utils.ts | 18 +- tests/RPC.test.ts | 23 +- tests/RPCClient.test.ts | 4 +- tests/RPCServer.test.ts | 1 + 9 files changed, 785 insertions(+), 48 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6bdbc1b..bb7c692 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,17 @@ "name": "@matrixai/rpc", "version": "0.0.1", "license": "Apache-2.0", + "dependencies": { + "@matrixai/async-init": "^1.9.4", + "@matrixai/contexts": "^1.2.0", + "@matrixai/errors": "^1.2.0", + "@matrixai/events": "^3.2.0", + "@matrixai/logger": "^3.1.0", + "@streamparser/json": "^0.0.17", + "ix": "^5.0.0" + }, "devDependencies": { + "@fast-check/jest": "^1.1.0", "@swc/core": "^1.3.62", "@swc/jest": "^0.2.26", "@types/jest": "^28.1.3", @@ -566,6 +576,22 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", @@ -810,6 +836,38 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fast-check/jest": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@fast-check/jest/-/jest-1.7.3.tgz", + "integrity": "sha512-6NcpYIIUnLwEdEfPhijYT5mnFPiQNP/isC+os+P+rV8qHRzUxRNx8WyPTOx+oVkBMm1+XSn00ZqfD3ANfciTZQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "dependencies": { + "fast-check": "^3.0.0" + }, + "peerDependencies": { + "@fast-check/worker": "~0.0.7", + "@jest/expect": ">=28.0.0", + "@jest/globals": ">=25.5.2" + }, + "peerDependenciesMeta": { + "@fast-check/worker": { + "optional": true + }, + "@jest/expect": { + "optional": true + } + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.11", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", @@ -1237,6 +1295,137 @@ "@types/yargs-parser": "*" } }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "peer": true, + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "peer": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jest/reporters": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", @@ -1500,6 +1689,79 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@matrixai/async-cancellable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@matrixai/async-cancellable/-/async-cancellable-1.1.1.tgz", + "integrity": "sha512-f0yxu7dHwvffZ++7aCm2WIcCJn18uLcOTdCCwEA3R3KVHYE3TG/JNoTWD9/mqBkAV1AI5vBfJzg27WnF9rOUXQ==" + }, + "node_modules/@matrixai/async-init": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@matrixai/async-init/-/async-init-1.10.0.tgz", + "integrity": "sha512-JjUFu6rqd+dtTHFJ6z8bjbceuFGBj/APWfJByVsfbEH1DJsOgWERFcW3DBUrS0mgTph4Vl518tsNcsSwKT5Y+g==", + "dependencies": { + "@matrixai/async-locks": "^4.0.0", + "@matrixai/errors": "^1.2.0", + "@matrixai/events": "^3.2.0" + } + }, + "node_modules/@matrixai/async-locks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@matrixai/async-locks/-/async-locks-4.0.0.tgz", + "integrity": "sha512-u/3fOdtjOKcDYF8dDoPR1/+7nmOkhxo42eBpXTEgfI0hLPGI37PoW7tjLvwy+O51Quy1HGOwhsR/Dgr4x+euug==", + "dependencies": { + "@matrixai/async-cancellable": "^1.1.1", + "@matrixai/errors": "^1.1.7", + "@matrixai/resources": "^1.1.5", + "@matrixai/timer": "^1.1.1" + } + }, + "node_modules/@matrixai/contexts": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@matrixai/contexts/-/contexts-1.2.0.tgz", + "integrity": "sha512-MR/B02Kf4UoliP9b/gMMKsvWV6QM4JSPKTIqrhQP2tbOl3FwLI+AIhL3vgYEj1Xw+PP8bY5cr8ontJ8x6AJyMg==", + "dependencies": { + "@matrixai/async-cancellable": "^1.1.1", + "@matrixai/async-locks": "^4.0.0", + "@matrixai/errors": "^1.1.7", + "@matrixai/resources": "^1.1.5", + "@matrixai/timer": "^1.1.1" + } + }, + "node_modules/@matrixai/errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@matrixai/errors/-/errors-1.2.0.tgz", + "integrity": "sha512-eZHPHFla5GFmi0O0yGgbtkca+ZjwpDbMz+60NC3y+DzQq6BMoe4gHmPjDalAHTxyxv0+Q+AWJTuV8Ows+IqBfQ==", + "dependencies": { + "ts-custom-error": "3.2.2" + } + }, + "node_modules/@matrixai/events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@matrixai/events/-/events-3.2.0.tgz", + "integrity": "sha512-MiUr8cUQyGAZCU7EbbMZI1xiYtLnWi/FMSCYpuV+14cMtmU4qfZpCT/nUh+xUNZS3P/LOgR/VjW56BsrJTfICw==", + "engines": { + "node": ">=19.0.0" + } + }, + "node_modules/@matrixai/logger": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-3.1.0.tgz", + "integrity": "sha512-C4JWpgbNik3V99bfGfDell5cH3JULD67eEq9CeXl4rYgsvanF8hhuY84ZYvndPhimt9qjA9/Z8uExKGoiv1zVw==" + }, + "node_modules/@matrixai/resources": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@matrixai/resources/-/resources-1.1.5.tgz", + "integrity": "sha512-m/DEZEe3wHqWEPTyoBtzFF6U9vWYhEnQtGgwvqiAlTxTM0rk96UBpWjDZCTF/vYG11ZlmlQFtg5H+zGgbjaB3Q==" + }, + "node_modules/@matrixai/timer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@matrixai/timer/-/timer-1.1.1.tgz", + "integrity": "sha512-8UKDoGuwKC6BvrY/yANJVH29v71wgQKH/tJlxMPohGxmzVUQO5+JeI4lUYVHTs2vq1AyKAWloF5fOig+I1dyGA==", + "dependencies": { + "@matrixai/async-cancellable": "^1.1.1", + "@matrixai/errors": "^1.1.7" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1541,6 +1803,31 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "peer": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "peer": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@streamparser/json": { + "version": "0.0.17", + "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.17.tgz", + "integrity": "sha512-mW54K6CTVJVLwXRB6kSS1xGWPmtTuXAStWnlvtesmcySgtop+eFPWOywBFPpJO4UD173epYsPSP6HSW8kuqN8w==" + }, "node_modules/@swc/core": { "version": "1.3.82", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.82.tgz", @@ -3527,6 +3814,45 @@ "node": ">= 0.8.0" } }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-check": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.13.0.tgz", + "integrity": "sha512-m6+3gZ/yTiCWTuV/1e/UuPPjyyyHdQ5gu0pMd84C6705VTDjAgAE6nqFT5jhgegFllCJ95yOzBpqvJSs2DZAxQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "dependencies": { + "pure-rand": "^6.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4452,6 +4778,20 @@ "node": ">=8" } }, + "node_modules/ix": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ix/-/ix-5.0.0.tgz", + "integrity": "sha512-6LyyrHnvNrSy5pKtW/KA+KKusHrB223aBJCJlIGPN7QBfDkEEtNrAkAz9lLLShIcdJntq6BiPCHuKaCM/9wwXw==", + "dependencies": { + "@types/node": "^13.7.4", + "tslib": "^2.3.0" + } + }, + "node_modules/ix/node_modules/@types/node": { + "version": "13.13.52", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz", + "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==" + }, "node_modules/jest": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", @@ -4867,15 +5207,15 @@ } }, "node_modules/jest-diff": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.4.tgz", - "integrity": "sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", "jest-get-type": "^29.6.3", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -4894,9 +5234,9 @@ } }, "node_modules/jest-diff/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "dependencies": { "@jest/schemas": "^29.6.3", @@ -5187,6 +5527,150 @@ "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-pnp-resolver": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", @@ -5812,6 +6296,222 @@ "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "peer": true + }, + "node_modules/jest-snapshot/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-snapshot/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-validate": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", @@ -6756,6 +7456,22 @@ "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.3.tgz", + "integrity": "sha512-KddyFewCsO0j3+np81IQ+SweXLDnDQTs5s67BOnrYmYe/yNmUhttQyGsYzy8yUnoljGAQ9sl38YB4vH8ur7Y+w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -7406,6 +8122,14 @@ "node": ">=8.0" } }, + "node_modules/ts-custom-error": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.2.2.tgz", + "integrity": "sha512-u0YCNf2lf6T/vHm+POKZK1yFKWpSpJitcUN3HxqyEcFuNnHIDbyuIQC7QDy/PsBX3giFyk9rt6BFqBAh2lsDZQ==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/ts-jest": { "version": "28.0.8", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.8.tgz", @@ -7542,6 +8266,11 @@ "node": ">=4" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", diff --git a/src/RPCClient.ts b/src/RPCClient.ts index 6d19363..2f969b9 100644 --- a/src/RPCClient.ts +++ b/src/RPCClient.ts @@ -26,6 +26,7 @@ import * as rpcUtils from './utils/utils'; import { promise } from './utils'; import { ErrorRPCStreamEnded, never } from './errors'; import * as events from './events'; +import { toError } from './utils/utils'; const timerCleanupReasonSymbol = Symbol('timerCleanUpReasonSymbol'); @@ -82,7 +83,6 @@ class RPCClient { streamKeepAliveTimeoutTime?: number; logger?: Logger; idGen: IdGen; - toError?: (errorData, metadata?: JSONValue) => ErrorRPCRemote; }) { logger.info(`Creating ${this.name}`); const rpcClient = new this({ @@ -107,7 +107,6 @@ class RPCClient { Uint8Array >; protected callerTypes: Record; - toError: (errorData: any, metadata?: JSONValue) => Error; public registerOnTimeoutCallback(callback: () => void) { this.onTimeoutCallback = callback; } @@ -144,7 +143,6 @@ class RPCClient { streamKeepAliveTimeoutTime, logger, idGen = () => Promise.resolve(null), - toError, }: { manifest: M; streamFactory: StreamFactory; @@ -157,7 +155,6 @@ class RPCClient { streamKeepAliveTimeoutTime: number; logger: Logger; idGen: IdGen; - toError?: (errorData, metadata?: JSONValue) => ErrorRPCRemote; }) { this.idGen = idGen; this.callerTypes = rpcUtils.getHandlerTypes(manifest); @@ -165,7 +162,6 @@ class RPCClient { this.middlewareFactory = middlewareFactory; this.streamKeepAliveTimeoutTime = streamKeepAliveTimeoutTime; this.logger = logger; - this.toError = toError || rpcUtils.toError; } public async destroy({ @@ -550,7 +546,7 @@ class RPCClient { ...(rpcStream.meta ?? {}), command: method, }; - throw this.toError(messageValue.error.data, metadata); + throw toError(messageValue.error.data, metadata); } leadingMessage = messageValue; } catch (e) { diff --git a/src/RPCServer.ts b/src/RPCServer.ts index 71d8966..aab0733 100644 --- a/src/RPCServer.ts +++ b/src/RPCServer.ts @@ -352,6 +352,7 @@ class RPCServer extends EventTarget { code: e.exitCode ?? JSONRPCErrorCode.InternalError, message: e.description ?? '', data: JSON.stringify(this.fromError(e), this.replacer), + type: e.type, }; const rpcErrorMessage: JSONRPCResponseError = { jsonrpc: '2.0', @@ -616,6 +617,7 @@ class RPCServer extends EventTarget { code: e.exitCode ?? JSONRPCErrorCode.InternalError, message: e.description ?? '', data: JSON.stringify(this.fromError(e), this.replacer), + type: e.type, }; const rpcErrorMessage: JSONRPCResponseError = { jsonrpc: '2.0', diff --git a/src/errors/errors.ts b/src/errors/errors.ts index 2acc942..8cc73fe 100644 --- a/src/errors/errors.ts +++ b/src/errors/errors.ts @@ -30,10 +30,12 @@ interface RPCError extends Error { } class ErrorRPC extends AbstractError implements RPCError { private _description: string = 'Generic Error'; + type: string; constructor(message?: string) { super(message); + this.type = this.constructor.name; } - code?: number; + code: number; get description(): string { return this._description; @@ -49,6 +51,7 @@ class ErrorRPCDestroyed extends ErrorRPC { super(message); // Call the parent constructor this.description = 'Rpc is destroyed'; // Set the specific description this.code = JSONRPCErrorCode.MethodNotFound; + this.type = this.constructor.name; } } @@ -59,6 +62,7 @@ class ErrorRPCParse extends ErrorRPC { super(message); // Call the parent constructor this.description = 'Failed to parse Buffer stream'; // Set the specific description this.code = JSONRPCErrorCode.ParseError; + this.type = this.constructor.name; } } @@ -67,6 +71,7 @@ class ErrorRPCStopping extends ErrorRPC { super(message); // Call the parent constructor this.description = 'Rpc is stopping'; // Set the specific description this.code = JSONRPCErrorCode.RPCStopping; + this.type = this.constructor.name; } } @@ -78,6 +83,7 @@ class ErrorRPCHandlerFailed extends ErrorRPC { super(message); // Call the parent constructor this.description = 'Failed to handle stream'; // Set the specific description this.code = JSONRPCErrorCode.HandlerNotFound; + this.type = this.constructor.name; } } class ErrorRPCCallerFailed extends ErrorRPC { @@ -85,6 +91,7 @@ class ErrorRPCCallerFailed extends ErrorRPC { super(message); // Call the parent constructor this.description = 'Failed to call stream'; // Set the specific description this.code = JSONRPCErrorCode.MissingCaller; + this.type = this.constructor.name; } } class ErrorMissingCaller extends ErrorRPC { @@ -92,6 +99,7 @@ class ErrorMissingCaller extends ErrorRPC { super(message); // Call the parent constructor this.description = 'Header information is missing'; // Set the specific description this.code = JSONRPCErrorCode.MissingCaller; + this.type = this.constructor.name; } } class ErrorMissingHeader extends ErrorRPC { @@ -99,6 +107,7 @@ class ErrorMissingHeader extends ErrorRPC { super(message); // Call the parent constructor this.description = 'Header information is missing'; // Set the specific description this.code = JSONRPCErrorCode.MissingHeader; + this.type = this.constructor.name; } } @@ -107,11 +116,12 @@ class ErrorHandlerAborted extends ErrorRPC { super(message); // Call the parent constructor this.description = 'Handler Aborted Stream.'; // Set the specific description this.code = JSONRPCErrorCode.HandlerAborted; + this.type = this.constructor.name; } } class ErrorRPCMessageLength extends ErrorRPC { static description = 'RPC Message exceeds maximum size'; - code? = JSONRPCErrorCode.RPCMessageLength; + code = JSONRPCErrorCode.RPCMessageLength; } class ErrorRPCMissingResponse extends ErrorRPC { @@ -119,6 +129,7 @@ class ErrorRPCMissingResponse extends ErrorRPC { super(message); this.description = 'Stream ended before response'; this.code = JSONRPCErrorCode.RPCMissingResponse; + this.type = this.constructor.name; } } @@ -130,6 +141,7 @@ class ErrorRPCOutputStreamError extends ErrorRPC { super(message); this.description = 'Output stream failed, unable to send data'; this.code = JSONRPCErrorCode.RPCOutputStreamError; + this.type = this.constructor.name; } } @@ -143,6 +155,8 @@ class ErrorRPCRemote extends ErrorRPC { this.metadata = metadata; this.code = JSONRPCErrorCode.RPCRemote; this.data = options?.data; + this.type = this.constructor.name; + this.message = message || ErrorRPCRemote.message; } public static fromJSON>( @@ -188,6 +202,7 @@ class ErrorRPCStreamEnded extends ErrorRPC { super(message); this.description = 'Handled stream has ended'; this.code = JSONRPCErrorCode.RPCStreamEnded; + this.type = this.constructor.name; } } @@ -196,6 +211,7 @@ class ErrorRPCTimedOut extends ErrorRPC { super(message); this.description = 'RPC handler has timed out'; this.code = JSONRPCErrorCode.RPCTimedOut; + this.type = this.constructor.name; } } @@ -204,6 +220,7 @@ class ErrorUtilsUndefinedBehaviour extends ErrorRPC { super(message); this.description = 'You should never see this error'; this.code = JSONRPCErrorCode.MethodNotFound; + this.type = this.constructor.name; } } export function never(): never { @@ -217,27 +234,28 @@ class ErrorRPCMethodNotImplemented extends ErrorRPC { this.description = 'This abstract method must be implemented in a derived class'; this.code = JSONRPCErrorCode.MethodNotFound; + this.type = this.constructor.name; } } class ErrorRPCConnectionLocal extends ErrorRPC { static description = 'RPC Connection local error'; - code? = JSONRPCErrorCode.RPCConnectionLocal; + code = JSONRPCErrorCode.RPCConnectionLocal; } class ErrorRPCConnectionPeer extends ErrorRPC { static description = 'RPC Connection peer error'; - code? = JSONRPCErrorCode.RPCConnectionPeer; + code = JSONRPCErrorCode.RPCConnectionPeer; } class ErrorRPCConnectionKeepAliveTimeOut extends ErrorRPC { static description = 'RPC Connection keep alive timeout'; - code? = JSONRPCErrorCode.RPCConnectionKeepAliveTimeOut; + code = JSONRPCErrorCode.RPCConnectionKeepAliveTimeOut; } class ErrorRPCConnectionInternal extends ErrorRPC { static description = 'RPC Connection internal error'; - code? = JSONRPCErrorCode.RPCConnectionInternal; + code = JSONRPCErrorCode.RPCConnectionInternal; } export { diff --git a/src/types.ts b/src/types.ts index 97e367c..4cb941e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,6 +7,8 @@ import type { ServerCaller } from './callers'; import type { ClientCaller } from './callers'; import type { UnaryCaller } from './callers'; import type Handler from './handlers/Handler'; +import type { ErrorRPC } from '@/errors'; +import { ErrorRPCRemote } from '@/errors'; /** * This is the type for the IdGenFunction. It is used to generate the request @@ -130,6 +132,8 @@ type JSONRPCError = { * The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.). */ data?: JSONValue; + + type: string | ErrorRPC; }; /** diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 8dbcab2..9a7ffbf 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -224,20 +224,15 @@ function parseJSONRPCMessage( */ function fromError(error: ErrorRPC, id?: any): JSONValue { const data: { [key: string]: JSONValue } = { + errorCode: error.code, message: error.message, - description: error.description, data: error.data, + type: error.constructor.name, }; - if (error.code !== undefined) { - data.code = error.code; - } return { - jsonrpc: '2.0', error: { - type: error.name, - ...data, + data, }, - id: id !== undefined ? id : null, }; } @@ -376,11 +371,9 @@ function toError(errorResponse: any, metadata?: any): ErrorRPCRemote { if ( typeof errorResponse !== 'object' || errorResponse === null || - !('error' in errorResponse) || - !('type' in errorResponse.error) || - !('message' in errorResponse.error) + !('error' in errorResponse) ) { - throw new TypeError('Invalid error data object'); + throw new ErrorRPCRemote(metadata); } const errorData = errorResponse.error; @@ -389,7 +382,6 @@ function toError(errorResponse: any, metadata?: any): ErrorRPCRemote { data: errorData.data === undefined ? null : errorData.data, }); error.message = errorData.message; - error.code = errorData.code; error.description = errorData.description; error.data = errorData.data; diff --git a/tests/RPC.test.ts b/tests/RPC.test.ts index 591ff5d..4b0c790 100644 --- a/tests/RPC.test.ts +++ b/tests/RPC.test.ts @@ -934,8 +934,6 @@ describe('RPC', () => { sensitive: true, logger, idGen, - fromError: utils.fromError, - replacer: utils.replacer, }); rpcServer.handleStream({ ...serverPair, cancel: () => {} }); @@ -953,19 +951,20 @@ describe('RPC', () => { const errorInstance = new ErrorRPCRemote( { code: -32006 }, 'Parse error', - { cause: error, data: 'The server responded with an error' }, + { cause: error }, ); const serializedError = fromError(errorInstance); - const deserializedError = rpcClient.toError(serializedError); + const callProm = rpcClient.methods.testMethod(serializedError); + await expect(callProm).rejects.toThrow(rpcErrors.ErrorRPCRemote); + + const deserializedError = toError(serializedError); expect(deserializedError).toBeInstanceOf(ErrorRPCRemote); // Check properties explicitly const { code, message, data } = deserializedError as ErrorRPCRemote; expect(code).toBe(-32006); - expect(message).toBe('Parse error'); - expect(data).toBe('The server responded with an error'); await rpcServer.destroy(); await rpcClient.destroy(); @@ -1000,8 +999,6 @@ describe('RPC', () => { sensitive: true, logger, idGen, - fromError: utils.fromError, - replacer: utils.replacer, }); rpcServer.handleStream({ ...serverPair, cancel: () => {} }); @@ -1016,11 +1013,10 @@ describe('RPC', () => { idGen, }); - const errorInstance = new ErrorRPCRemote( - { code: -32006 }, - 'Parse error', - { cause: error, data: 'asda' }, - ); + const errorInstance = new ErrorRPCRemote({ code: -32006 }, '', { + cause: error, + data: 'asda', + }); const serializedError = JSON.parse( JSON.stringify(fromError(errorInstance), replacer('data')), @@ -1036,7 +1032,6 @@ describe('RPC', () => { // Check properties explicitly const { code, message, data } = deserializedError as ErrorRPCRemote; expect(code).toBe(-32006); - expect(message).toBe('Parse error'); expect(data).toBe(undefined); await rpcServer.destroy(); diff --git a/tests/RPCClient.test.ts b/tests/RPCClient.test.ts index ade9717..f2ace32 100644 --- a/tests/RPCClient.test.ts +++ b/tests/RPCClient.test.ts @@ -1129,7 +1129,7 @@ describe(`${RPCClient.name}`, () => { await sleep(50); let timeLeft = ctx.timer.getTimeout(); const message = await reader.read(); - expect(ctx.timer.getTimeout()).toBeGreaterThanOrEqual(timeLeft); + expect(ctx.timer.getTimeout() + 2).toBeGreaterThanOrEqual(timeLeft); reader.releaseLock(); for await (const _ of callerInterface.readable) { // Do nothing @@ -1140,7 +1140,7 @@ describe(`${RPCClient.name}`, () => { await sleep(50); timeLeft = ctx.timer.getTimeout(); await writer.write(message.value); - expect(ctx.timer.getTimeout()).toBeGreaterThanOrEqual(timeLeft); + expect(ctx.timer.getTimeout() + 1).toBeGreaterThanOrEqual(timeLeft); await writer.close(); await outputResult; diff --git a/tests/RPCServer.test.ts b/tests/RPCServer.test.ts index 80213ae..c764ba0 100644 --- a/tests/RPCServer.test.ts +++ b/tests/RPCServer.test.ts @@ -796,6 +796,7 @@ describe(`${RPCServer.name}`, () => { error: { code: 1, message: 'failure of some kind', + type: 'ErrorRPCRemote', }, }; rpcServer.handleStream(readWriteStream); From faf5daf14dc92fb8005f4af8aa000c008c602ba6 Mon Sep 17 00:00:00 2001 From: Amy <50583248+amydevs@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:16:51 +1000 Subject: [PATCH 07/12] fix: RPC.test.ts tests no longer hang and arbitraries now correctly generate data --- tests/RPC.test.ts | 559 ++++++++++++++++++++++++---------------------- 1 file changed, 287 insertions(+), 272 deletions(-) diff --git a/tests/RPC.test.ts b/tests/RPC.test.ts index 4b0c790..f1579f5 100644 --- a/tests/RPC.test.ts +++ b/tests/RPC.test.ts @@ -10,6 +10,7 @@ import DuplexCaller from '@/callers/DuplexCaller'; import ServerCaller from '@/callers/ServerCaller'; import ClientCaller from '@/callers/ClientCaller'; import UnaryCaller from '@/callers/UnaryCaller'; +import { Timer } from '@matrixai/timer'; import * as rpcUtilsMiddleware from '@/utils/middleware'; import { ErrorRPC, @@ -38,7 +39,7 @@ describe('RPC', () => { testProp( 'RPC communication with raw stream', [rpcTestUtils.rawDataArb], - async (inputData) => { + async (values) => { const [outputResult, outputWriterStream] = rpcTestUtils.streamToArray(); const { clientPair, serverPair } = rpcTestUtils.createTapPairs< @@ -92,7 +93,7 @@ describe('RPC', () => { }); const writer = callerInterface.writable.getWriter(); const pipeProm = callerInterface.readable.pipeTo(outputWriterStream); - for (const value of inputData) { + for (const value of values) { await writer.write(value); } await writer.close(); @@ -104,7 +105,7 @@ describe('RPC', () => { }; expect(header).toStrictEqual(expectedHeader); expect(callerInterface.meta?.result).toBe('some leading data'); - expect(await outputResult).toStrictEqual(inputData); + expect(await outputResult).toStrictEqual(values); await pipeProm; await rpcServer.destroy(); await rpcClient.destroy(); @@ -602,308 +603,322 @@ describe('RPC', () => { await expect(rpcServer.destroy(false)).toResolve(); await rpcClient.destroy(); }); - test('RPC client and server timeout concurrently', async () => { - let serverTimedOut = false; - let clientTimedOut = false; - // Generate test data (assuming fc.array generates some mock array) - const values = fc.array(rpcTestUtils.safeJsonValueArb, { minLength: 1 }); + testProp( + 'RPC client and server timeout concurrently', + [rpcTestUtils.safeJsonValueArb], + async (inputData) => { + let serverTimedOut = false; + let clientTimedOut = false; - // Setup server and client communication pairs - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); + // Setup server and client communication pairs + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); - const timeout = 1; - class TestMethod extends DuplexHandler { - public handle = async function* ( - input: AsyncIterableIterator, - cancel: (reason?: any) => void, - meta: Record | undefined, - ctx: ContextTimed, - ): AsyncIterableIterator { - // Check for abort event - ctx.signal.throwIfAborted(); - const abortProm = utils.promise(); - ctx.signal.addEventListener('abort', () => { - abortProm.rejectP(ctx.signal.reason); - }); - await abortProm.p; - }; - } - const testMethodInstance = new TestMethod({}); - // Set up a client and server with matching timeout settings - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: testMethodInstance, - }, - logger, - idGen, - handlerTimeoutTime: timeout, - }); - // Register callback - rpcServer.registerOnTimeoutCallback(() => { - serverTimedOut = true; - }); - rpcServer.handleStream({ - ...serverPair, - cancel: () => {}, - }); + const timeout = 1; + class TestMethod extends DuplexHandler { + public handle = async function* ( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): AsyncIterableIterator { + // Check for abort event + ctx.signal.throwIfAborted(); + const abortProm = utils.promise(); + ctx.signal.addEventListener('abort', () => { + abortProm.rejectP(ctx.signal.reason); + }); + await abortProm.p; + }; + } + const testMethodInstance = new TestMethod({}); + // Set up a client and server with matching timeout settings + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: testMethodInstance, + }, + logger, + idGen, + handlerTimeoutTime: timeout, + }); + // Register callback + rpcServer.registerOnTimeoutCallback(() => { + serverTimedOut = true; + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new DuplexCaller(), - }, - streamFactory: async () => { - return { - ...clientPair, - cancel: () => {}, + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new DuplexCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + const callerInterface = await rpcClient.methods.testMethod({ + timer: timeout, + }); + // Register callback + rpcClient.registerOnTimeoutCallback(() => { + clientTimedOut = true; + }); + const writer = callerInterface.writable.getWriter(); + const reader = callerInterface.readable.getReader(); + // Wait for server and client to timeout by checking the flag + await new Promise((resolve) => { + const checkFlag = () => { + if (serverTimedOut && clientTimedOut) resolve(); + else setTimeout(() => checkFlag(), 10); }; - }, - logger, - idGen, - }); - const callerInterface = await rpcClient.methods.testMethod({ - timer: timeout, - }); - // Register callback - rpcClient.registerOnTimeoutCallback(() => { - clientTimedOut = true; - }); - const writer = callerInterface.writable.getWriter(); - const reader = callerInterface.readable.getReader(); - // Wait for server and client to timeout by checking the flag - await new Promise((resolve) => { - const checkFlag = () => { - if (serverTimedOut && clientTimedOut) resolve(); - else setTimeout(() => checkFlag(), 10); - }; - checkFlag(); - }); - // Expect both the client and the server to time out - await expect(writer.write(values[0])).rejects.toThrow( - 'Timed out waiting for header', - ); + checkFlag(); + }); + // Expect both the client and the server to time out + await expect(writer.write(inputData)).rejects.toThrow( + 'Timed out waiting for header', + ); - await expect(reader.read()).rejects.toThrow('Timed out waiting for header'); + await expect(reader.read()).rejects.toThrow('Timed out waiting for header'); - await rpcServer.destroy(); - await rpcClient.destroy(); - }); + await rpcServer.destroy(); + await rpcClient.destroy(); + } + ); // Test description - test('RPC server times out before client', async () => { - let serverTimedOut = false; + testProp( + 'RPC server times out before client', + [rpcTestUtils.safeJsonValueArb], + async (inputData) => { + let serverTimedOut = false; - // Generate test data (assuming fc.array generates some mock array) - const values = fc.array(rpcTestUtils.safeJsonValueArb, { minLength: 1 }); + // Setup server and client communication pairs + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); - // Setup server and client communication pairs - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); + // Define the server's method behavior + class TestMethod extends DuplexHandler { + public handle = async function* ( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ) { + ctx.signal.throwIfAborted(); + const abortProm = utils.promise(); + ctx.signal.addEventListener('abort', () => { + abortProm.rejectP(ctx.signal.reason); + }); + await abortProm.p; + }; + } - // Define the server's method behavior - class TestMethod extends DuplexHandler { - public handle = async function* ( - input: AsyncIterableIterator, - cancel: (reason?: any) => void, - meta: Record | undefined, - ctx: ContextTimed, - ) { - ctx.signal.throwIfAborted(); - const abortProm = utils.promise(); - ctx.signal.addEventListener('abort', () => { - abortProm.rejectP(ctx.signal.reason); - }); - await abortProm.p; - }; - } + // Create an instance of the RPC server with a shorter timeout + const rpcServer = await RPCServer.createRPCServer({ + manifest: { testMethod: new TestMethod({}) }, + logger, + idGen, + handlerTimeoutTime: 1, + }); + // Register callback + rpcServer.registerOnTimeoutCallback(() => { + serverTimedOut = true; + }); + rpcServer.handleStream({ ...serverPair, cancel: () => {} }); - // Create an instance of the RPC server with a shorter timeout - const rpcServer = await RPCServer.createRPCServer({ - manifest: { testMethod: new TestMethod({}) }, - logger, - idGen, - handlerTimeoutTime: 1, - }); - // Register callback - rpcServer.registerOnTimeoutCallback(() => { - serverTimedOut = true; - }); - rpcServer.handleStream({ ...serverPair, cancel: () => {} }); + // Create an instance of the RPC client with a longer timeout + const rpcClient = await RPCClient.createRPCClient({ + manifest: { testMethod: new DuplexCaller() }, + streamFactory: async () => ({ ...clientPair, cancel: () => {} }), + logger, + idGen, + }); - // Create an instance of the RPC client with a longer timeout - const rpcClient = await RPCClient.createRPCClient({ - manifest: { testMethod: new DuplexCaller() }, - streamFactory: async () => ({ ...clientPair, cancel: () => {} }), - logger, - idGen, - }); + // Get server and client interfaces + const callerInterface = await rpcClient.methods.testMethod({ + timer: 10, + }); + const writer = callerInterface.writable.getWriter(); + const reader = callerInterface.readable.getReader(); + // Wait for server to timeout by checking the flag + await new Promise((resolve) => { + const checkFlag = () => { + if (serverTimedOut) resolve(); + else setTimeout(() => checkFlag(), 10); + }; + checkFlag(); + }); - // Get server and client interfaces - const callerInterface = await rpcClient.methods.testMethod({ - timer: 10, - }); - const writer = callerInterface.writable.getWriter(); - const reader = callerInterface.readable.getReader(); - // Wait for server to timeout by checking the flag - await new Promise((resolve) => { - const checkFlag = () => { - if (serverTimedOut) resolve(); - else setTimeout(() => checkFlag(), 10); - }; - checkFlag(); - }); + // We expect server to timeout before the client + await expect(writer.write(inputData)).rejects.toThrow( + 'Timed out waiting for header', + ); + await expect(reader.read()).rejects.toThrow('Timed out waiting for header'); - // We expect server to timeout before the client - await expect(writer.write(values[0])).rejects.toThrow( - 'Timed out waiting for header', - ); - await expect(reader.read()).rejects.toThrow('Timed out waiting for header'); + // Cleanup + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + { numRuns: 1 } + ); + testProp( + 'RPC client times out before server', + [rpcTestUtils.safeJsonValueArb], + async (value) => { + // Setup server and client communication pairs + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); + class TestMethod extends DuplexHandler { + public handle = async function* ( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ): AsyncIterableIterator { + ctx.signal.throwIfAborted(); + const abortProm = utils.promise(); + ctx.signal.addEventListener('abort', () => { + abortProm.rejectP(ctx.signal.reason); + }); + await abortProm.p; + }; + } + // Set up a client and server with matching timeout settings + const rpcServer = await RPCServer.createRPCServer({ + manifest: { + testMethod: new TestMethod({}), + }, + logger, + idGen, - // Cleanup - await rpcServer.destroy(); - await rpcClient.destroy(); - }); - test('RPC client times out before server', async () => { - // Generate test data (assuming fc.array generates some mock array) - const values = fc.array(rpcTestUtils.safeJsonValueArb, { minLength: 1 }); + handlerTimeoutTime: 400, + }); + rpcServer.handleStream({ + ...serverPair, + cancel: () => {}, + }); - // Setup server and client communication pairs - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); - class TestMethod extends DuplexHandler { - public handle = async function* ( - input: AsyncIterableIterator, - cancel: (reason?: any) => void, - meta: Record | undefined, - ctx: ContextTimed, - ): AsyncIterableIterator { - ctx.signal.throwIfAborted(); - const abortProm = utils.promise(); - ctx.signal.addEventListener('abort', () => { - abortProm.rejectP(ctx.signal.reason); - }); - await abortProm.p; - }; - } - // Set up a client and server with matching timeout settings - const rpcServer = await RPCServer.createRPCServer({ - manifest: { - testMethod: new TestMethod({}), - }, - logger, - idGen, + const rpcClient = await RPCClient.createRPCClient({ + manifest: { + testMethod: new DuplexCaller(), + }, + streamFactory: async () => { + return { + ...clientPair, + cancel: () => {}, + }; + }, + logger, + idGen, + }); + const callerInterface = await rpcClient.methods.testMethod({ timer: 300 }); + const writer = callerInterface.writable.getWriter(); + const reader = callerInterface.readable.getReader(); + // Expect the client to time out first + await expect(writer.write(value)).toResolve(); + await expect(reader.read()).toReject(); - handlerTimeoutTime: 400, - }); - rpcServer.handleStream({ - ...serverPair, - cancel: () => {}, - }); + await rpcServer.destroy(); + await rpcClient.destroy(); + }, + { numRuns: 1 } + ); + testProp( + 'RPC client and server with infinite timeout', + [rpcTestUtils.safeJsonValueArb], + async (inputData) => { + // Set up a client and server with infinite timeout settings - const rpcClient = await RPCClient.createRPCClient({ - manifest: { - testMethod: new DuplexCaller(), - }, - streamFactory: async () => { - return { - ...clientPair, - cancel: () => {}, - }; - }, - logger, - idGen, - }); - const callerInterface = await rpcClient.methods.testMethod({ timer: 300 }); - const writer = callerInterface.writable.getWriter(); - const reader = callerInterface.readable.getReader(); - // Expect the client to time out first - await expect(writer.write(values[0])).toResolve(); - await expect(reader.read()).toReject(); + const { clientPair, serverPair } = rpcTestUtils.createTapPairs< + Uint8Array, + Uint8Array + >(); - await rpcServer.destroy(); - await rpcClient.destroy(); - }); - test('RPC client and server with infinite timeout', async () => { - // Set up a client and server with infinite timeout settings - const values = fc.array(rpcTestUtils.safeJsonValueArb, { minLength: 3 }); + class TestMethod extends DuplexHandler { + public handle = async function* ( + input: AsyncIterableIterator, + cancel: (reason?: any) => void, + meta: Record | undefined, + ctx: ContextTimed, + ) { + ctx.signal.throwIfAborted(); + const abortProm = utils.promise(); + ctx.signal.addEventListener('abort', () => { + abortProm.rejectP(ctx.signal.reason); + }); + await abortProm.p; + }; + } - const { clientPair, serverPair } = rpcTestUtils.createTapPairs< - Uint8Array, - Uint8Array - >(); + const rpcServer = await RPCServer.createRPCServer({ + manifest: { testMethod: new TestMethod({}) }, + logger, + idGen, + handlerTimeoutTime: Infinity, + }); + rpcServer.handleStream({ ...serverPair, cancel: () => {} }); - class TestMethod extends DuplexHandler { - public handle = async function* ( - input: AsyncIterableIterator, - cancel: (reason?: any) => void, - meta: Record | undefined, - ctx: ContextTimed, - ) { - ctx.signal.throwIfAborted(); - const abortProm = utils.promise(); - ctx.signal.addEventListener('abort', () => { - abortProm.rejectP(ctx.signal.reason); - }); - await abortProm.p; - }; - } + const rpcClient = await RPCClient.createRPCClient({ + manifest: { testMethod: new DuplexCaller() }, + streamFactory: async () => ({ ...clientPair, cancel: () => {} }), + logger, + idGen, + }); - const rpcServer = await RPCServer.createRPCServer({ - manifest: { testMethod: new TestMethod({}) }, - logger, - idGen, - handlerTimeoutTime: Infinity, - }); - rpcServer.handleStream({ ...serverPair, cancel: () => {} }); + const callerTimer = new Timer(() => {}, Infinity); - const rpcClient = await RPCClient.createRPCClient({ - manifest: { testMethod: new DuplexCaller() }, - streamFactory: async () => ({ ...clientPair, cancel: () => {} }), - logger, - idGen, - }); + const callerInterface = await rpcClient.methods.testMethod({ + timer: callerTimer, + }); - const callerInterface = await rpcClient.methods.testMethod({ - timer: Infinity, - }); + const writer = callerInterface.writable.getWriter(); + const reader = callerInterface.readable.getReader(); - const writer = callerInterface.writable.getWriter(); - const reader = callerInterface.readable.getReader(); + // Trigger a call that will hang indefinitely or for a long time #TODO - // Trigger a call that will hang indefinitely or for a long time #TODO + // Write a value to the stream + await writer.write(inputData); - // Write a value to the stream - const writePromise = writer.write(values[0]); + // Trigger a read that will hang indefinitely - // Trigger a read that will hang indefinitely + const readPromise = reader.read(); + // Adding a randomized sleep here to check that neither timeout + const randomSleepTime = Math.floor(Math.random() * 1000) + 1; + // Random time between 1 and 1,000 ms + await utils.sleep(randomSleepTime); + // At this point, writePromise and readPromise should neither be resolved nor rejected + // because the server method is hanging. - const readPromise = reader.read(); - // Adding a randomized sleep here to check that neither timeout - const randomSleepTime = Math.floor(Math.random() * 1000) + 1; - // Random time between 1 and 1,000 ms - await utils.sleep(randomSleepTime); - // At this point, writePromise and readPromise should neither be resolved nor rejected - // because the server method is hanging. + // Check if the promises are neither resolved nor rejected + const timeoutPromise = new Promise((_, reject) => + setTimeout(() => reject("timeout"), 1000), + ); - // Check if the promises are neither resolved nor rejected - const timeoutPromise = new Promise((resolve) => - setTimeout(() => resolve('timeout'), 1000), - ); + // Check if read status is still pending; - const readStatus = await Promise.race([readPromise, timeoutPromise]); - // Check if read status is still pending; + await expect(Promise.race([readPromise, timeoutPromise])).rejects.toBe('timeout'); - expect(readStatus).toBe('timeout'); + // Cancel caller timer + callerTimer.cancel(); - // Expect neither to time out and verify that they can still handle other operations #TODO - await rpcServer.destroy(); - await rpcClient.destroy(); - }); + // Expect neither to time out and verify that they can still handle other operations #TODO + await rpcServer.destroy(true); + await rpcClient.destroy(); + }, + { numRuns: 1 } + ); testProp( 'RPC Serializes and Deserializes ErrorRPCRemote', From a9c95aa50ec193aecc04de41d01b48b47234f21e Mon Sep 17 00:00:00 2001 From: Aditya <38064122+bettercallav@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:39:08 +1000 Subject: [PATCH 08/12] chore: refactor out utils and middlware [ci skip] --- src/RPCClient.ts | 6 +++--- src/RPCServer.ts | 2 +- src/{utils => }/middleware.ts | 4 ++-- src/{utils => }/utils.ts | 12 ++++++------ src/utils/index.ts | 2 +- tests/RPC.test.ts | 30 +++++++++++++++++++----------- tests/RPCClient.test.ts | 2 +- tests/RPCServer.test.ts | 2 +- tests/utils/middleware.test.ts | 2 +- 9 files changed, 35 insertions(+), 27 deletions(-) rename src/{utils => }/middleware.ts (99%) rename src/{utils => }/utils.ts (98%) diff --git a/src/RPCClient.ts b/src/RPCClient.ts index 2f969b9..aa1dfea 100644 --- a/src/RPCClient.ts +++ b/src/RPCClient.ts @@ -20,13 +20,13 @@ import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy'; import Logger from '@matrixai/logger'; import { Timer } from '@matrixai/timer'; import { createDestroy } from '@matrixai/async-init'; -import * as rpcUtilsMiddleware from './utils/middleware'; +import * as rpcUtilsMiddleware from './middleware'; import * as rpcErrors from './errors'; -import * as rpcUtils from './utils/utils'; +import * as rpcUtils from './utils'; import { promise } from './utils'; import { ErrorRPCStreamEnded, never } from './errors'; import * as events from './events'; -import { toError } from './utils/utils'; +import { toError } from './utils'; const timerCleanupReasonSymbol = Symbol('timerCleanUpReasonSymbol'); diff --git a/src/RPCServer.ts b/src/RPCServer.ts index aab0733..f0d3a18 100644 --- a/src/RPCServer.ts +++ b/src/RPCServer.ts @@ -30,7 +30,7 @@ import { ClientHandler } from './handlers'; import * as rpcEvents from './events'; import * as rpcUtils from './utils'; import * as rpcErrors from './errors'; -import * as rpcUtilsMiddleware from './utils'; +import * as rpcUtilsMiddleware from './middleware'; import { ErrorHandlerAborted, JSONRPCErrorCode, never } from './errors'; import * as events from './events'; diff --git a/src/utils/middleware.ts b/src/middleware.ts similarity index 99% rename from src/utils/middleware.ts rename to src/middleware.ts index 49f5504..343b4a2 100644 --- a/src/utils/middleware.ts +++ b/src/middleware.ts @@ -4,12 +4,12 @@ import type { JSONRPCResponse, JSONRPCResponseResult, MiddlewareFactory, -} from '../types'; +} from './types'; import { TransformStream } from 'stream/web'; import { JSONParser } from '@streamparser/json'; import * as rpcUtils from './utils'; import { promise } from './utils'; -import * as rpcErrors from '../errors'; +import * as rpcErrors from './errors'; /** * This function is a factory to create a TransformStream that will diff --git a/src/utils/utils.ts b/src/utils.ts similarity index 98% rename from src/utils/utils.ts rename to src/utils.ts index 9a7ffbf..bcc3a42 100644 --- a/src/utils/utils.ts +++ b/src/utils.ts @@ -10,16 +10,16 @@ import type { JSONRPCResponseError, JSONRPCResponseResult, PromiseDeconstructed, -} from '../types'; -import type { JSONValue, IdGen } from '../types'; +} from './types'; +import type { JSONValue, IdGen } from './types'; import type { Timer } from '@matrixai/timer'; import { TransformStream } from 'stream/web'; import { JSONParser } from '@streamparser/json'; import { AbstractError } from '@matrixai/errors'; -import * as rpcErrors from '../errors'; -import * as errors from '../errors'; -import { ErrorRPCRemote } from '../errors'; -import { ErrorRPC } from '../errors'; +import * as rpcErrors from './errors'; +import * as errors from './errors'; +import { ErrorRPCRemote } from './errors'; +import { ErrorRPC } from './errors'; // Importing PK funcs and utils which are essential for RPC function isObject(o: unknown): o is object { diff --git a/src/utils/index.ts b/src/utils/index.ts index d799db4..b3ced5e 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,2 +1,2 @@ export * from './middleware'; -export * from './utils'; +export * from '../utils'; diff --git a/tests/RPC.test.ts b/tests/RPC.test.ts index f1579f5..e9ac259 100644 --- a/tests/RPC.test.ts +++ b/tests/RPC.test.ts @@ -5,13 +5,13 @@ import type { ContextTimed } from '@matrixai/contexts'; import { TransformStream } from 'stream/web'; import { fc, testProp } from '@fast-check/jest'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { Timer } from '@matrixai/timer'; import RawCaller from '@/callers/RawCaller'; import DuplexCaller from '@/callers/DuplexCaller'; import ServerCaller from '@/callers/ServerCaller'; import ClientCaller from '@/callers/ClientCaller'; import UnaryCaller from '@/callers/UnaryCaller'; -import { Timer } from '@matrixai/timer'; -import * as rpcUtilsMiddleware from '@/utils/middleware'; +import * as rpcUtilsMiddleware from '@/middleware'; import { ErrorRPC, ErrorRPCHandlerFailed, @@ -687,11 +687,13 @@ describe('RPC', () => { 'Timed out waiting for header', ); - await expect(reader.read()).rejects.toThrow('Timed out waiting for header'); + await expect(reader.read()).rejects.toThrow( + 'Timed out waiting for header', + ); await rpcServer.destroy(); await rpcClient.destroy(); - } + }, ); // Test description testProp( @@ -763,13 +765,15 @@ describe('RPC', () => { await expect(writer.write(inputData)).rejects.toThrow( 'Timed out waiting for header', ); - await expect(reader.read()).rejects.toThrow('Timed out waiting for header'); + await expect(reader.read()).rejects.toThrow( + 'Timed out waiting for header', + ); // Cleanup await rpcServer.destroy(); await rpcClient.destroy(); }, - { numRuns: 1 } + { numRuns: 1 }, ); testProp( 'RPC client times out before server', @@ -823,7 +827,9 @@ describe('RPC', () => { logger, idGen, }); - const callerInterface = await rpcClient.methods.testMethod({ timer: 300 }); + const callerInterface = await rpcClient.methods.testMethod({ + timer: 300, + }); const writer = callerInterface.writable.getWriter(); const reader = callerInterface.readable.getReader(); // Expect the client to time out first @@ -833,7 +839,7 @@ describe('RPC', () => { await rpcServer.destroy(); await rpcClient.destroy(); }, - { numRuns: 1 } + { numRuns: 1 }, ); testProp( 'RPC client and server with infinite timeout', @@ -903,12 +909,14 @@ describe('RPC', () => { // Check if the promises are neither resolved nor rejected const timeoutPromise = new Promise((_, reject) => - setTimeout(() => reject("timeout"), 1000), + setTimeout(() => reject('timeout'), 1000), ); // Check if read status is still pending; - await expect(Promise.race([readPromise, timeoutPromise])).rejects.toBe('timeout'); + await expect(Promise.race([readPromise, timeoutPromise])).rejects.toBe( + 'timeout', + ); // Cancel caller timer callerTimer.cancel(); @@ -917,7 +925,7 @@ describe('RPC', () => { await rpcServer.destroy(true); await rpcClient.destroy(); }, - { numRuns: 1 } + { numRuns: 1 }, ); testProp( diff --git a/tests/RPCClient.test.ts b/tests/RPCClient.test.ts index f2ace32..a526cd1 100644 --- a/tests/RPCClient.test.ts +++ b/tests/RPCClient.test.ts @@ -19,7 +19,7 @@ import UnaryCaller from '@/callers/UnaryCaller'; import RPCClient from '@/RPCClient'; import RPCServer from '@/RPCServer'; import * as rpcErrors from '@/errors'; -import * as rpcUtilsMiddleware from '@/utils/middleware'; +import * as rpcUtilsMiddleware from '@/middleware'; import { promise, sleep } from '@/utils'; import { ErrorRPCRemote } from '@/errors'; import * as rpcTestUtils from './utils'; diff --git a/tests/RPCServer.test.ts b/tests/RPCServer.test.ts index c764ba0..5810507 100644 --- a/tests/RPCServer.test.ts +++ b/tests/RPCServer.test.ts @@ -16,7 +16,7 @@ import RPCServer from '@/RPCServer'; import * as rpcErrors from '@/errors/errors'; import * as rpcUtils from '@/utils'; import { promise, sleep } from '@/utils'; -import * as rpcUtilsMiddleware from '@/utils/middleware'; +import * as rpcUtilsMiddleware from '@/middleware'; import ServerHandler from '@/handlers/ServerHandler'; import DuplexHandler from '@/handlers/DuplexHandler'; import RawHandler from '@/handlers/RawHandler'; diff --git a/tests/utils/middleware.test.ts b/tests/utils/middleware.test.ts index bf744a7..ab43bae 100644 --- a/tests/utils/middleware.test.ts +++ b/tests/utils/middleware.test.ts @@ -6,7 +6,7 @@ import { AsyncIterableX as AsyncIterable } from 'ix/asynciterable'; import * as rpcUtils from '@/utils'; import 'ix/add/asynciterable-operators/toarray'; import * as rpcErrors from '@/errors'; -import * as rpcUtilsMiddleware from '@/utils/middleware'; +import * as rpcUtilsMiddleware from '@/middleware'; import * as rpcTestUtils from '../utils'; describe('Middleware tests', () => { From df77680c75866c79aba4a213e4d3e5a9f25a3ee1 Mon Sep 17 00:00:00 2001 From: Aditya <38064122+bettercallav@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:41:32 +1000 Subject: [PATCH 09/12] chore: removed utils folder [ci skip] --- src/utils/index.ts | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 src/utils/index.ts diff --git a/src/utils/index.ts b/src/utils/index.ts deleted file mode 100644 index b3ced5e..0000000 --- a/src/utils/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './middleware'; -export * from '../utils'; From ea9a4b5fedd265c5bf7954e6240adbb98b59a9c8 Mon Sep 17 00:00:00 2001 From: Aditya <38064122+bettercallav@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:02:09 +1000 Subject: [PATCH 10/12] chore: js docs --- docs/.nojekyll | 1 + docs/assets/highlight.css | 57 + docs/assets/main.js | 58 + docs/assets/search.js | 1 + docs/assets/style.css | 1276 +++++++++++++++++ docs/classes/RPCClient.html | 634 ++++++++ docs/classes/RPCServer.html | 687 +++++++++ docs/classes/callers.Caller.html | 122 ++ docs/classes/callers.ClientCaller.html | 122 ++ docs/classes/callers.DuplexCaller.html | 122 ++ docs/classes/callers.RawCaller.html | 108 ++ docs/classes/callers.ServerCaller.html | 122 ++ docs/classes/callers.UnaryCaller.html | 122 ++ docs/classes/errors.ErrorHandlerAborted.html | 323 +++++ docs/classes/errors.ErrorMissingCaller.html | 323 +++++ docs/classes/errors.ErrorMissingHeader.html | 323 +++++ docs/classes/errors.ErrorRPC.html | 353 +++++ docs/classes/errors.ErrorRPCCallerFailed.html | 323 +++++ .../errors.ErrorRPCConnectionInternal.html | 318 ++++ ...rs.ErrorRPCConnectionKeepAliveTimeOut.html | 318 ++++ .../errors.ErrorRPCConnectionLocal.html | 318 ++++ .../errors.ErrorRPCConnectionPeer.html | 318 ++++ docs/classes/errors.ErrorRPCDestroyed.html | 318 ++++ .../classes/errors.ErrorRPCHandlerFailed.html | 326 +++++ .../classes/errors.ErrorRPCMessageLength.html | 318 ++++ .../errors.ErrorRPCMethodNotImplemented.html | 318 ++++ .../errors.ErrorRPCMissingResponse.html | 318 ++++ .../errors.ErrorRPCOutputStreamError.html | 320 +++++ docs/classes/errors.ErrorRPCParse.html | 323 +++++ docs/classes/errors.ErrorRPCRemote.html | 336 +++++ docs/classes/errors.ErrorRPCStopping.html | 318 ++++ docs/classes/errors.ErrorRPCStreamEnded.html | 323 +++++ docs/classes/errors.ErrorRPCTimedOut.html | 323 +++++ .../errors.ErrorUtilsUndefinedBehaviour.html | 318 ++++ docs/classes/events.EventRPC.html | 427 ++++++ docs/classes/events.EventRPCClient.html | 434 ++++++ .../classes/events.EventRPCClientConnect.html | 412 ++++++ docs/classes/events.EventRPCClientCreate.html | 412 ++++++ .../classes/events.EventRPCClientCreated.html | 412 ++++++ .../classes/events.EventRPCClientDestroy.html | 412 ++++++ .../events.EventRPCClientDestroyed.html | 412 ++++++ docs/classes/events.EventRPCClientError.html | 412 ++++++ docs/classes/events.EventRPCConnection.html | 429 ++++++ .../events.EventRPCConnectionError.html | 412 ++++++ docs/classes/events.EventRPCServer.html | 434 ++++++ .../events.EventRPCServerConnection.html | 412 ++++++ docs/classes/events.EventRPCServerCreate.html | 412 ++++++ .../classes/events.EventRPCServerCreated.html | 412 ++++++ .../classes/events.EventRPCServerDestroy.html | 412 ++++++ .../events.EventRPCServerDestroyed.html | 412 ++++++ docs/classes/events.EventRPCServerError.html | 412 ++++++ docs/classes/events.RPCErrorEvent.html | 371 +++++ docs/classes/handlers.ClientHandler.html | 181 +++ docs/classes/handlers.DuplexHandler.html | 185 +++ docs/classes/handlers.Handler.html | 143 ++ docs/classes/handlers.RawHandler.html | 173 +++ docs/classes/handlers.ServerHandler.html | 181 +++ docs/classes/handlers.UnaryHandler.html | 181 +++ docs/enums/errors.JSONRPCErrorCode.html | 211 +++ docs/functions/errors.never.html | 80 ++ .../utils.clientInputTransformStream.html | 95 ++ .../utils.clientOutputTransformStream.html | 95 ++ docs/functions/utils.fromError.html | 89 ++ docs/functions/utils.getHandlerTypes.html | 79 + docs/functions/utils.isObject.html | 79 + docs/functions/utils.parseHeadStream.html | 108 ++ docs/functions/utils.parseJSONRPCMessage.html | 84 ++ docs/functions/utils.parseJSONRPCRequest.html | 84 ++ .../utils.parseJSONRPCRequestMessage.html | 84 ++ ...utils.parseJSONRPCRequestNotification.html | 84 ++ .../functions/utils.parseJSONRPCResponse.html | 84 ++ .../utils.parseJSONRPCResponseError.html | 79 + .../utils.parseJSONRPCResponseResult.html | 84 ++ docs/functions/utils.promise.html | 79 + docs/functions/utils.replacer.html | 94 ++ docs/functions/utils.sleep.html | 79 + docs/functions/utils.toError.html | 91 ++ docs/index.html | 91 ++ docs/interfaces/types.RPCStream.html | 135 ++ docs/modules.html | 65 + docs/modules/callers.html | 69 + docs/modules/errors.html | 109 ++ docs/modules/events.html | 93 ++ docs/modules/handlers.html | 69 + docs/modules/types.html | 112 ++ docs/modules/utils.html | 91 ++ .../types.ClientHandlerImplementation.html | 86 ++ docs/types/types.ClientManifest.html | 81 ++ docs/types/types.ContainerType.html | 79 + .../types.DuplexHandlerImplementation.html | 86 ++ docs/types/types.HandlerImplementation.html | 116 ++ docs/types/types.HandlerType.html | 79 + docs/types/types.IdGen.html | 89 ++ docs/types/types.JSONRPCError.html | 102 ++ docs/types/types.JSONRPCMessage.html | 87 ++ docs/types/types.JSONRPCRequest.html | 87 ++ docs/types/types.JSONRPCRequestMessage.html | 110 ++ .../types.JSONRPCRequestNotification.html | 105 ++ docs/types/types.JSONRPCResponse.html | 86 ++ docs/types/types.JSONRPCResponseError.html | 102 ++ docs/types/types.JSONRPCResponseResult.html | 107 ++ docs/types/types.JSONValue.html | 79 + docs/types/types.MapCallers.html | 84 ++ docs/types/types.MiddlewareFactory.html | 133 ++ docs/types/types.POJO.html | 84 ++ docs/types/types.PromiseDeconstructed.html | 115 ++ .../types/types.RawHandlerImplementation.html | 79 + .../types.ServerHandlerImplementation.html | 86 ++ docs/types/types.ServerManifest.html | 81 ++ docs/types/types.StreamFactory.html | 97 ++ .../types.UnaryHandlerImplementation.html | 86 ++ package.json | 36 +- 112 files changed, 23647 insertions(+), 14 deletions(-) create mode 100644 docs/.nojekyll create mode 100644 docs/assets/highlight.css create mode 100644 docs/assets/main.js create mode 100644 docs/assets/search.js create mode 100644 docs/assets/style.css create mode 100644 docs/classes/RPCClient.html create mode 100644 docs/classes/RPCServer.html create mode 100644 docs/classes/callers.Caller.html create mode 100644 docs/classes/callers.ClientCaller.html create mode 100644 docs/classes/callers.DuplexCaller.html create mode 100644 docs/classes/callers.RawCaller.html create mode 100644 docs/classes/callers.ServerCaller.html create mode 100644 docs/classes/callers.UnaryCaller.html create mode 100644 docs/classes/errors.ErrorHandlerAborted.html create mode 100644 docs/classes/errors.ErrorMissingCaller.html create mode 100644 docs/classes/errors.ErrorMissingHeader.html create mode 100644 docs/classes/errors.ErrorRPC.html create mode 100644 docs/classes/errors.ErrorRPCCallerFailed.html create mode 100644 docs/classes/errors.ErrorRPCConnectionInternal.html create mode 100644 docs/classes/errors.ErrorRPCConnectionKeepAliveTimeOut.html create mode 100644 docs/classes/errors.ErrorRPCConnectionLocal.html create mode 100644 docs/classes/errors.ErrorRPCConnectionPeer.html create mode 100644 docs/classes/errors.ErrorRPCDestroyed.html create mode 100644 docs/classes/errors.ErrorRPCHandlerFailed.html create mode 100644 docs/classes/errors.ErrorRPCMessageLength.html create mode 100644 docs/classes/errors.ErrorRPCMethodNotImplemented.html create mode 100644 docs/classes/errors.ErrorRPCMissingResponse.html create mode 100644 docs/classes/errors.ErrorRPCOutputStreamError.html create mode 100644 docs/classes/errors.ErrorRPCParse.html create mode 100644 docs/classes/errors.ErrorRPCRemote.html create mode 100644 docs/classes/errors.ErrorRPCStopping.html create mode 100644 docs/classes/errors.ErrorRPCStreamEnded.html create mode 100644 docs/classes/errors.ErrorRPCTimedOut.html create mode 100644 docs/classes/errors.ErrorUtilsUndefinedBehaviour.html create mode 100644 docs/classes/events.EventRPC.html create mode 100644 docs/classes/events.EventRPCClient.html create mode 100644 docs/classes/events.EventRPCClientConnect.html create mode 100644 docs/classes/events.EventRPCClientCreate.html create mode 100644 docs/classes/events.EventRPCClientCreated.html create mode 100644 docs/classes/events.EventRPCClientDestroy.html create mode 100644 docs/classes/events.EventRPCClientDestroyed.html create mode 100644 docs/classes/events.EventRPCClientError.html create mode 100644 docs/classes/events.EventRPCConnection.html create mode 100644 docs/classes/events.EventRPCConnectionError.html create mode 100644 docs/classes/events.EventRPCServer.html create mode 100644 docs/classes/events.EventRPCServerConnection.html create mode 100644 docs/classes/events.EventRPCServerCreate.html create mode 100644 docs/classes/events.EventRPCServerCreated.html create mode 100644 docs/classes/events.EventRPCServerDestroy.html create mode 100644 docs/classes/events.EventRPCServerDestroyed.html create mode 100644 docs/classes/events.EventRPCServerError.html create mode 100644 docs/classes/events.RPCErrorEvent.html create mode 100644 docs/classes/handlers.ClientHandler.html create mode 100644 docs/classes/handlers.DuplexHandler.html create mode 100644 docs/classes/handlers.Handler.html create mode 100644 docs/classes/handlers.RawHandler.html create mode 100644 docs/classes/handlers.ServerHandler.html create mode 100644 docs/classes/handlers.UnaryHandler.html create mode 100644 docs/enums/errors.JSONRPCErrorCode.html create mode 100644 docs/functions/errors.never.html create mode 100644 docs/functions/utils.clientInputTransformStream.html create mode 100644 docs/functions/utils.clientOutputTransformStream.html create mode 100644 docs/functions/utils.fromError.html create mode 100644 docs/functions/utils.getHandlerTypes.html create mode 100644 docs/functions/utils.isObject.html create mode 100644 docs/functions/utils.parseHeadStream.html create mode 100644 docs/functions/utils.parseJSONRPCMessage.html create mode 100644 docs/functions/utils.parseJSONRPCRequest.html create mode 100644 docs/functions/utils.parseJSONRPCRequestMessage.html create mode 100644 docs/functions/utils.parseJSONRPCRequestNotification.html create mode 100644 docs/functions/utils.parseJSONRPCResponse.html create mode 100644 docs/functions/utils.parseJSONRPCResponseError.html create mode 100644 docs/functions/utils.parseJSONRPCResponseResult.html create mode 100644 docs/functions/utils.promise.html create mode 100644 docs/functions/utils.replacer.html create mode 100644 docs/functions/utils.sleep.html create mode 100644 docs/functions/utils.toError.html create mode 100644 docs/index.html create mode 100644 docs/interfaces/types.RPCStream.html create mode 100644 docs/modules.html create mode 100644 docs/modules/callers.html create mode 100644 docs/modules/errors.html create mode 100644 docs/modules/events.html create mode 100644 docs/modules/handlers.html create mode 100644 docs/modules/types.html create mode 100644 docs/modules/utils.html create mode 100644 docs/types/types.ClientHandlerImplementation.html create mode 100644 docs/types/types.ClientManifest.html create mode 100644 docs/types/types.ContainerType.html create mode 100644 docs/types/types.DuplexHandlerImplementation.html create mode 100644 docs/types/types.HandlerImplementation.html create mode 100644 docs/types/types.HandlerType.html create mode 100644 docs/types/types.IdGen.html create mode 100644 docs/types/types.JSONRPCError.html create mode 100644 docs/types/types.JSONRPCMessage.html create mode 100644 docs/types/types.JSONRPCRequest.html create mode 100644 docs/types/types.JSONRPCRequestMessage.html create mode 100644 docs/types/types.JSONRPCRequestNotification.html create mode 100644 docs/types/types.JSONRPCResponse.html create mode 100644 docs/types/types.JSONRPCResponseError.html create mode 100644 docs/types/types.JSONRPCResponseResult.html create mode 100644 docs/types/types.JSONValue.html create mode 100644 docs/types/types.MapCallers.html create mode 100644 docs/types/types.MiddlewareFactory.html create mode 100644 docs/types/types.POJO.html create mode 100644 docs/types/types.PromiseDeconstructed.html create mode 100644 docs/types/types.RawHandlerImplementation.html create mode 100644 docs/types/types.ServerHandlerImplementation.html create mode 100644 docs/types/types.ServerManifest.html create mode 100644 docs/types/types.StreamFactory.html create mode 100644 docs/types/types.UnaryHandlerImplementation.html diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e2ac661 --- /dev/null +++ b/docs/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/assets/highlight.css b/docs/assets/highlight.css new file mode 100644 index 0000000..262bff7 --- /dev/null +++ b/docs/assets/highlight.css @@ -0,0 +1,57 @@ +:root { + --light-hl-0: #795E26; + --dark-hl-0: #DCDCAA; + --light-hl-1: #000000; + --dark-hl-1: #D4D4D4; + --light-hl-2: #A31515; + --dark-hl-2: #CE9178; + --light-hl-3: #0000FF; + --dark-hl-3: #569CD6; + --light-hl-4: #008000; + --dark-hl-4: #6A9955; + --light-code-background: #FFFFFF; + --dark-code-background: #1E1E1E; +} + +@media (prefers-color-scheme: light) { :root { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --hl-2: var(--light-hl-2); + --hl-3: var(--light-hl-3); + --hl-4: var(--light-hl-4); + --code-background: var(--light-code-background); +} } + +@media (prefers-color-scheme: dark) { :root { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --hl-2: var(--dark-hl-2); + --hl-3: var(--dark-hl-3); + --hl-4: var(--dark-hl-4); + --code-background: var(--dark-code-background); +} } + +:root[data-theme='light'] { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --hl-2: var(--light-hl-2); + --hl-3: var(--light-hl-3); + --hl-4: var(--light-hl-4); + --code-background: var(--light-code-background); +} + +:root[data-theme='dark'] { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --hl-2: var(--dark-hl-2); + --hl-3: var(--dark-hl-3); + --hl-4: var(--dark-hl-4); + --code-background: var(--dark-code-background); +} + +.hl-0 { color: var(--hl-0); } +.hl-1 { color: var(--hl-1); } +.hl-2 { color: var(--hl-2); } +.hl-3 { color: var(--hl-3); } +.hl-4 { color: var(--hl-4); } +pre, code { background: var(--code-background); } diff --git a/docs/assets/main.js b/docs/assets/main.js new file mode 100644 index 0000000..f7c8366 --- /dev/null +++ b/docs/assets/main.js @@ -0,0 +1,58 @@ +"use strict"; +"use strict";(()=>{var Qe=Object.create;var ae=Object.defineProperty;var Pe=Object.getOwnPropertyDescriptor;var Ce=Object.getOwnPropertyNames;var Oe=Object.getPrototypeOf,Re=Object.prototype.hasOwnProperty;var _e=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Me=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ce(e))!Re.call(t,i)&&i!==n&&ae(t,i,{get:()=>e[i],enumerable:!(r=Pe(e,i))||r.enumerable});return t};var De=(t,e,n)=>(n=t!=null?Qe(Oe(t)):{},Me(e||!t||!t.__esModule?ae(n,"default",{value:t,enumerable:!0}):n,t));var de=_e((ce,he)=>{(function(){var t=function(e){var n=new t.Builder;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),n.searchPipeline.add(t.stemmer),e.call(n,n),n.build()};t.version="2.3.9";t.utils={},t.utils.warn=function(e){return function(n){e.console&&console.warn&&console.warn(n)}}(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var n=Object.create(null),r=Object.keys(e),i=0;i0){var h=t.utils.clone(n)||{};h.position=[a,l],h.index=s.length,s.push(new t.Token(r.slice(a,o),h))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. +`,e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(r){var i=t.Pipeline.registeredFunctions[r];if(i)n.add(i);else throw new Error("Cannot load unregistered function: "+r)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(n){t.Pipeline.warnIfFunctionNotRegistered(n),this._stack.push(n)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");r=r+1,this._stack.splice(r,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");this._stack.splice(r,0,n)},t.Pipeline.prototype.remove=function(e){var n=this._stack.indexOf(e);n!=-1&&this._stack.splice(n,1)},t.Pipeline.prototype.run=function(e){for(var n=this._stack.length,r=0;r1&&(oe&&(r=s),o!=e);)i=r-n,s=n+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(ou?h+=2:a==u&&(n+=r[l+1]*i[h+1],l+=2,h+=2);return n},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),n=1,r=0;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new t.TokenSet;s.node.edges["*"]=u}if(s.str.length==0&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new t.TokenSet;s.node.edges["*"]=l}s.str.length==1&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var h=s.str.charAt(0),m=s.str.charAt(1),v;m in s.node.edges?v=s.node.edges[m]:(v=new t.TokenSet,s.node.edges[m]=v),s.str.length==1&&(v.final=!0),i.push({node:v,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return r},t.TokenSet.fromString=function(e){for(var n=new t.TokenSet,r=n,i=0,s=e.length;i=e;n--){var r=this.uncheckedNodes[n],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}};t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(n){var r=new t.QueryParser(e,n);r.parse()})},t.Index.prototype.query=function(e){for(var n=new t.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,n){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=n||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,n;do e=this.next(),n=e.charCodeAt(0);while(n>47&&n<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var n=e.next();if(n==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(n.charCodeAt(0)==92){e.escapeCharacter();continue}if(n==":")return t.QueryLexer.lexField;if(n=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(n=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(n=="+"&&e.width()===1||n=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(n.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,n){this.lexer=new t.QueryLexer(e),this.query=n,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var n=e.peekLexeme();if(n!=null)switch(n.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+n.type;throw n.str.length>=1&&(r+=" with value '"+n.str+"'"),new t.QueryParseError(r,n.start,n.end)}},t.QueryParser.parsePresence=function(e){var n=e.consumeLexeme();if(n!=null){switch(n.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+n.str+"'";throw new t.QueryParseError(r,n.start,n.end)}var i=e.peekLexeme();if(i==null){var r="expecting term or field, found nothing";throw new t.QueryParseError(r,n.start,n.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(r,i.start,i.end)}}},t.QueryParser.parseField=function(e){var n=e.consumeLexeme();if(n!=null){if(e.query.allFields.indexOf(n.str)==-1){var r=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+n.str+"', possible fields: "+r;throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.fields=[n.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,n.start,n.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var n=e.consumeLexeme();if(n!=null){e.currentClause.term=n.str.toLowerCase(),n.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(r==null){e.nextClause();return}switch(r.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new t.QueryParseError(i,r.start,r.end)}}},t.QueryParser.parseEditDistance=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="boost must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,n){typeof define=="function"&&define.amd?define(n):typeof ce=="object"?he.exports=n():e.lunr=n()}(this,function(){return t})})()});var le=[];function B(t,e){le.push({selector:e,constructor:t})}var Y=class{constructor(){this.alwaysVisibleMember=null;this.createComponents(document.body),this.ensureFocusedElementVisible(),window.addEventListener("hashchange",()=>this.ensureFocusedElementVisible())}createComponents(e){le.forEach(n=>{e.querySelectorAll(n.selector).forEach(r=>{r.dataset.hasInstance||(new n.constructor({el:r,app:this}),r.dataset.hasInstance=String(!0))})})}filterChanged(){this.ensureFocusedElementVisible()}ensureFocusedElementVisible(){this.alwaysVisibleMember&&(this.alwaysVisibleMember.classList.remove("always-visible"),this.alwaysVisibleMember.firstElementChild.remove(),this.alwaysVisibleMember=null);let e=document.getElementById(location.hash.substring(1));if(!e)return;let n=e.parentElement;for(;n&&n.tagName!=="SECTION";)n=n.parentElement;if(n&&n.offsetParent==null){this.alwaysVisibleMember=n,n.classList.add("always-visible");let r=document.createElement("p");r.classList.add("warning"),r.textContent="This member is normally hidden due to your filter settings.",n.prepend(r)}}};var I=class{constructor(e){this.el=e.el,this.app=e.app}};var J=class{constructor(){this.listeners={}}addEventListener(e,n){e in this.listeners||(this.listeners[e]=[]),this.listeners[e].push(n)}removeEventListener(e,n){if(!(e in this.listeners))return;let r=this.listeners[e];for(let i=0,s=r.length;i{let n=Date.now();return(...r)=>{n+e-Date.now()<0&&(t(...r),n=Date.now())}};var re=class extends J{constructor(){super();this.scrollTop=0;this.lastY=0;this.width=0;this.height=0;this.showToolbar=!0;this.toolbar=document.querySelector(".tsd-page-toolbar"),this.navigation=document.querySelector(".col-menu"),window.addEventListener("scroll",ne(()=>this.onScroll(),10)),window.addEventListener("resize",ne(()=>this.onResize(),10)),this.searchInput=document.querySelector("#tsd-search input"),this.searchInput&&this.searchInput.addEventListener("focus",()=>{this.hideShowToolbar()}),this.onResize(),this.onScroll()}triggerResize(){let n=new CustomEvent("resize",{detail:{width:this.width,height:this.height}});this.dispatchEvent(n)}onResize(){this.width=window.innerWidth||0,this.height=window.innerHeight||0;let n=new CustomEvent("resize",{detail:{width:this.width,height:this.height}});this.dispatchEvent(n)}onScroll(){this.scrollTop=window.scrollY||0;let n=new CustomEvent("scroll",{detail:{scrollTop:this.scrollTop}});this.dispatchEvent(n),this.hideShowToolbar()}hideShowToolbar(){let n=this.showToolbar;this.showToolbar=this.lastY>=this.scrollTop||this.scrollTop<=0||!!this.searchInput&&this.searchInput===document.activeElement,n!==this.showToolbar&&(this.toolbar.classList.toggle("tsd-page-toolbar--hide"),this.navigation?.classList.toggle("col-menu--hide")),this.lastY=this.scrollTop}},R=re;R.instance=new re;var X=class extends I{constructor(n){super(n);this.anchors=[];this.index=-1;R.instance.addEventListener("resize",()=>this.onResize()),R.instance.addEventListener("scroll",r=>this.onScroll(r)),this.createAnchors()}createAnchors(){let n=window.location.href;n.indexOf("#")!=-1&&(n=n.substring(0,n.indexOf("#"))),this.el.querySelectorAll("a").forEach(r=>{let i=r.href;if(i.indexOf("#")==-1||i.substring(0,n.length)!=n)return;let s=i.substring(i.indexOf("#")+1),o=document.querySelector("a.tsd-anchor[name="+s+"]"),a=r.parentNode;!o||!a||this.anchors.push({link:a,anchor:o,position:0})}),this.onResize()}onResize(){let n;for(let i=0,s=this.anchors.length;ii.position-s.position);let r=new CustomEvent("scroll",{detail:{scrollTop:R.instance.scrollTop}});this.onScroll(r)}onScroll(n){let r=n.detail.scrollTop+5,i=this.anchors,s=i.length-1,o=this.index;for(;o>-1&&i[o].position>r;)o-=1;for(;o-1&&this.anchors[this.index].link.classList.remove("focus"),this.index=o,this.index>-1&&this.anchors[this.index].link.classList.add("focus"))}};var ue=(t,e=100)=>{let n;return()=>{clearTimeout(n),n=setTimeout(()=>t(),e)}};var me=De(de());function ve(){let t=document.getElementById("tsd-search");if(!t)return;let e=document.getElementById("search-script");t.classList.add("loading"),e&&(e.addEventListener("error",()=>{t.classList.remove("loading"),t.classList.add("failure")}),e.addEventListener("load",()=>{t.classList.remove("loading"),t.classList.add("ready")}),window.searchData&&t.classList.remove("loading"));let n=document.querySelector("#tsd-search input"),r=document.querySelector("#tsd-search .results");if(!n||!r)throw new Error("The input field or the result list wrapper was not found");let i=!1;r.addEventListener("mousedown",()=>i=!0),r.addEventListener("mouseup",()=>{i=!1,t.classList.remove("has-focus")}),n.addEventListener("focus",()=>t.classList.add("has-focus")),n.addEventListener("blur",()=>{i||(i=!1,t.classList.remove("has-focus"))});let s={base:t.dataset.base+"/"};Fe(t,r,n,s)}function Fe(t,e,n,r){n.addEventListener("input",ue(()=>{He(t,e,n,r)},200));let i=!1;n.addEventListener("keydown",s=>{i=!0,s.key=="Enter"?Ve(e,n):s.key=="Escape"?n.blur():s.key=="ArrowUp"?pe(e,-1):s.key==="ArrowDown"?pe(e,1):i=!1}),n.addEventListener("keypress",s=>{i&&s.preventDefault()}),document.body.addEventListener("keydown",s=>{s.altKey||s.ctrlKey||s.metaKey||!n.matches(":focus")&&s.key==="/"&&(n.focus(),s.preventDefault())})}function Ae(t,e){t.index||window.searchData&&(e.classList.remove("loading"),e.classList.add("ready"),t.data=window.searchData,t.index=me.Index.load(window.searchData.index))}function He(t,e,n,r){if(Ae(r,t),!r.index||!r.data)return;e.textContent="";let i=n.value.trim(),s=i?r.index.search(`*${i}*`):[];for(let o=0;oa.score-o.score);for(let o=0,a=Math.min(10,s.length);o${fe(u.parent,i)}.${l}`);let h=document.createElement("li");h.classList.value=u.classes??"";let m=document.createElement("a");m.href=r.base+u.url,m.innerHTML=l,h.append(m),e.appendChild(h)}}function pe(t,e){let n=t.querySelector(".current");if(!n)n=t.querySelector(e==1?"li:first-child":"li:last-child"),n&&n.classList.add("current");else{let r=n;if(e===1)do r=r.nextElementSibling??void 0;while(r instanceof HTMLElement&&r.offsetParent==null);else do r=r.previousElementSibling??void 0;while(r instanceof HTMLElement&&r.offsetParent==null);r&&(n.classList.remove("current"),r.classList.add("current"))}}function Ve(t,e){let n=t.querySelector(".current");if(n||(n=t.querySelector("li:first-child")),n){let r=n.querySelector("a");r&&(window.location.href=r.href),e.blur()}}function fe(t,e){if(e==="")return t;let n=t.toLocaleLowerCase(),r=e.toLocaleLowerCase(),i=[],s=0,o=n.indexOf(r);for(;o!=-1;)i.push(ie(t.substring(s,o)),`${ie(t.substring(o,o+r.length))}`),s=o+r.length,o=n.indexOf(r,s);return i.push(ie(t.substring(s))),i.join("")}var Ne={"&":"&","<":"<",">":">","'":"'",'"':"""};function ie(t){return t.replace(/[&<>"'"]/g,e=>Ne[e])}var F="mousedown",ye="mousemove",j="mouseup",Z={x:0,y:0},ge=!1,se=!1,Be=!1,A=!1,xe=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(xe?"is-mobile":"not-mobile");xe&&"ontouchstart"in document.documentElement&&(Be=!0,F="touchstart",ye="touchmove",j="touchend");document.addEventListener(F,t=>{se=!0,A=!1;let e=F=="touchstart"?t.targetTouches[0]:t;Z.y=e.pageY||0,Z.x=e.pageX||0});document.addEventListener(ye,t=>{if(se&&!A){let e=F=="touchstart"?t.targetTouches[0]:t,n=Z.x-(e.pageX||0),r=Z.y-(e.pageY||0);A=Math.sqrt(n*n+r*r)>10}});document.addEventListener(j,()=>{se=!1});document.addEventListener("click",t=>{ge&&(t.preventDefault(),t.stopImmediatePropagation(),ge=!1)});var K=class extends I{constructor(n){super(n);this.className=this.el.dataset.toggle||"",this.el.addEventListener(j,r=>this.onPointerUp(r)),this.el.addEventListener("click",r=>r.preventDefault()),document.addEventListener(F,r=>this.onDocumentPointerDown(r)),document.addEventListener(j,r=>this.onDocumentPointerUp(r))}setActive(n){if(this.active==n)return;this.active=n,document.documentElement.classList.toggle("has-"+this.className,n),this.el.classList.toggle("active",n);let r=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(r),setTimeout(()=>document.documentElement.classList.remove(r),500)}onPointerUp(n){A||(this.setActive(!0),n.preventDefault())}onDocumentPointerDown(n){if(this.active){if(n.target.closest(".col-menu, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(n){if(!A&&this.active&&n.target.closest(".col-menu")){let r=n.target.closest("a");if(r){let i=window.location.href;i.indexOf("#")!=-1&&(i=i.substring(0,i.indexOf("#"))),r.href.substring(0,i.length)==i&&setTimeout(()=>this.setActive(!1),250)}}}};var oe;try{oe=localStorage}catch{oe={getItem(){return null},setItem(){}}}var Q=oe;var Le=document.head.appendChild(document.createElement("style"));Le.dataset.for="filters";var ee=class extends I{constructor(n){super(n);this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",()=>{this.setLocalStorage(this.el.checked)}),this.setLocalStorage(this.fromLocalStorage()),Le.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; } +`}fromLocalStorage(){let n=Q.getItem(this.key);return n?n==="true":this.el.checked}setLocalStorage(n){Q.setItem(this.key,n.toString()),this.value=n,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),this.app.filterChanged(),document.querySelectorAll(".tsd-index-section").forEach(n=>{n.style.display="block";let r=Array.from(n.querySelectorAll(".tsd-index-link")).every(i=>i.offsetParent==null);n.style.display=r?"none":"block"})}};var te=class extends I{constructor(n){super(n);this.calculateHeights(),this.summary=this.el.querySelector(".tsd-accordion-summary"),this.icon=this.summary.querySelector("svg"),this.key=`tsd-accordion-${this.summary.textContent.replace(/\s+/g,"-").toLowerCase()}`,this.setLocalStorage(this.fromLocalStorage(),!0),this.summary.addEventListener("click",r=>this.toggleVisibility(r)),this.icon.style.transform=this.getIconRotation()}getIconRotation(n=this.el.open){return`rotate(${n?0:-90}deg)`}calculateHeights(){let n=this.el.open,{position:r,left:i}=this.el.style;this.el.style.position="fixed",this.el.style.left="-9999px",this.el.open=!0,this.expandedHeight=this.el.offsetHeight+"px",this.el.open=!1,this.collapsedHeight=this.el.offsetHeight+"px",this.el.open=n,this.el.style.height=n?this.expandedHeight:this.collapsedHeight,this.el.style.position=r,this.el.style.left=i}toggleVisibility(n){n.preventDefault(),this.el.style.overflow="hidden",this.el.open?this.collapse():this.expand()}expand(n=!0){this.el.open=!0,this.animate(this.collapsedHeight,this.expandedHeight,{opening:!0,duration:n?300:0})}collapse(n=!0){this.animate(this.expandedHeight,this.collapsedHeight,{opening:!1,duration:n?300:0})}animate(n,r,{opening:i,duration:s=300}){if(this.animation)return;let o={duration:s,easing:"ease"};this.animation=this.el.animate({height:[n,r]},o),this.icon.animate({transform:[this.icon.style.transform||this.getIconRotation(!i),this.getIconRotation(i)]},o).addEventListener("finish",()=>{this.icon.style.transform=this.getIconRotation(i)}),this.animation.addEventListener("finish",()=>this.animationEnd(i))}animationEnd(n){this.el.open=n,this.animation=void 0,this.el.style.height="auto",this.el.style.overflow="visible",this.setLocalStorage(n)}fromLocalStorage(){let n=Q.getItem(this.key);return n?n==="true":this.el.open}setLocalStorage(n,r=!1){this.fromLocalStorage()===n&&!r||(Q.setItem(this.key,n.toString()),this.el.open=n,this.handleValueChange(r))}handleValueChange(n=!1){this.fromLocalStorage()===this.el.open&&!n||(this.fromLocalStorage()?this.expand(!1):this.collapse(!1))}};function be(t){let e=Q.getItem("tsd-theme")||"os";t.value=e,Ee(e),t.addEventListener("change",()=>{Q.setItem("tsd-theme",t.value),Ee(t.value)})}function Ee(t){document.documentElement.dataset.theme=t}ve();B(X,".menu-highlight");B(K,"a[data-toggle]");B(te,".tsd-index-accordion");B(ee,".tsd-filter-item input[type=checkbox]");var we=document.getElementById("theme");we&&be(we);var je=new Y;Object.defineProperty(window,"app",{value:je});})(); +/*! Bundled license information: + +lunr/lunr.js: + (** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + *) + (*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Set + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.tokenizer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Vector + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.stemmer + * Copyright (C) 2020 Oliver Nightingale + * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt + *) + (*! + * lunr.stopWordFilter + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.trimmer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.TokenSet + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Builder + * Copyright (C) 2020 Oliver Nightingale + *) +*/ diff --git a/docs/assets/search.js b/docs/assets/search.js new file mode 100644 index 0000000..100780d --- /dev/null +++ b/docs/assets/search.js @@ -0,0 +1 @@ +window.searchData = JSON.parse("{\"kinds\":{\"4\":\"Namespace\",\"8\":\"Enumeration\",\"16\":\"Enumeration Member\",\"64\":\"Function\",\"128\":\"Class\",\"256\":\"Interface\",\"512\":\"Constructor\",\"1024\":\"Property\",\"2048\":\"Method\",\"65536\":\"Type literal\",\"262144\":\"Accessor\",\"4194304\":\"Type alias\"},\"rows\":[{\"kind\":128,\"name\":\"RPCClient\",\"url\":\"classes/RPCClient.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":2048,\"name\":\"createRPCClient\",\"url\":\"classes/RPCClient.html#createRPCClient\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RPCClient\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/RPCClient.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"RPCClient\"},{\"kind\":1024,\"name\":\"onTimeoutCallback\",\"url\":\"classes/RPCClient.html#onTimeoutCallback\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCClient\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"classes/RPCClient.html#onTimeoutCallback.__type-1\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"RPCClient.onTimeoutCallback\"},{\"kind\":1024,\"name\":\"idGen\",\"url\":\"classes/RPCClient.html#idGen\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCClient\"},{\"kind\":1024,\"name\":\"logger\",\"url\":\"classes/RPCClient.html#logger\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCClient\"},{\"kind\":1024,\"name\":\"streamFactory\",\"url\":\"classes/RPCClient.html#streamFactory\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCClient\"},{\"kind\":1024,\"name\":\"middlewareFactory\",\"url\":\"classes/RPCClient.html#middlewareFactory\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCClient\"},{\"kind\":1024,\"name\":\"callerTypes\",\"url\":\"classes/RPCClient.html#callerTypes\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCClient\"},{\"kind\":2048,\"name\":\"registerOnTimeoutCallback\",\"url\":\"classes/RPCClient.html#registerOnTimeoutCallback\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RPCClient\"},{\"kind\":1024,\"name\":\"streamKeepAliveTimeoutTime\",\"url\":\"classes/RPCClient.html#streamKeepAliveTimeoutTime\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"RPCClient\"},{\"kind\":1024,\"name\":\"methodsProxy\",\"url\":\"classes/RPCClient.html#methodsProxy\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"RPCClient\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"classes/RPCClient.html#methodsProxy.__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"RPCClient.methodsProxy\"},{\"kind\":2048,\"name\":\"destroy\",\"url\":\"classes/RPCClient.html#destroy\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"RPCClient\"},{\"kind\":262144,\"name\":\"methods\",\"url\":\"classes/RPCClient.html#methods\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class\",\"parent\":\"RPCClient\"},{\"kind\":2048,\"name\":\"unaryCaller\",\"url\":\"classes/RPCClient.html#unaryCaller\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RPCClient\"},{\"kind\":2048,\"name\":\"serverStreamCaller\",\"url\":\"classes/RPCClient.html#serverStreamCaller\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RPCClient\"},{\"kind\":2048,\"name\":\"clientStreamCaller\",\"url\":\"classes/RPCClient.html#clientStreamCaller\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RPCClient\"},{\"kind\":2048,\"name\":\"duplexStreamCaller\",\"url\":\"classes/RPCClient.html#duplexStreamCaller\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RPCClient\"},{\"kind\":2048,\"name\":\"rawStreamCaller\",\"url\":\"classes/RPCClient.html#rawStreamCaller\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RPCClient\"},{\"kind\":128,\"name\":\"RPCServer\",\"url\":\"classes/RPCServer.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":2048,\"name\":\"createRPCServer\",\"url\":\"classes/RPCServer.html#createRPCServer\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RPCServer\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/RPCServer.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"RPCServer\"},{\"kind\":1024,\"name\":\"onTimeoutCallback\",\"url\":\"classes/RPCServer.html#onTimeoutCallback\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"classes/RPCServer.html#onTimeoutCallback.__type-2\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"RPCServer.onTimeoutCallback\"},{\"kind\":1024,\"name\":\"idGen\",\"url\":\"classes/RPCServer.html#idGen\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":1024,\"name\":\"logger\",\"url\":\"classes/RPCServer.html#logger\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":1024,\"name\":\"handlerMap\",\"url\":\"classes/RPCServer.html#handlerMap\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":1024,\"name\":\"defaultTimeoutMap\",\"url\":\"classes/RPCServer.html#defaultTimeoutMap\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":1024,\"name\":\"handlerTimeoutTime\",\"url\":\"classes/RPCServer.html#handlerTimeoutTime\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":1024,\"name\":\"activeStreams\",\"url\":\"classes/RPCServer.html#activeStreams\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":1024,\"name\":\"sensitive\",\"url\":\"classes/RPCServer.html#sensitive\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":1024,\"name\":\"fromError\",\"url\":\"classes/RPCServer.html#fromError\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"classes/RPCServer.html#fromError.__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"RPCServer.fromError\"},{\"kind\":1024,\"name\":\"replacer\",\"url\":\"classes/RPCServer.html#replacer\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"classes/RPCServer.html#replacer.__type-4\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"RPCServer.replacer\"},{\"kind\":1024,\"name\":\"middlewareFactory\",\"url\":\"classes/RPCServer.html#middlewareFactory\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":2048,\"name\":\"registerOnTimeoutCallback\",\"url\":\"classes/RPCServer.html#registerOnTimeoutCallback\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RPCServer\"},{\"kind\":2048,\"name\":\"destroy\",\"url\":\"classes/RPCServer.html#destroy\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"RPCServer\"},{\"kind\":2048,\"name\":\"registerRawStreamHandler\",\"url\":\"classes/RPCServer.html#registerRawStreamHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":2048,\"name\":\"registerDuplexStreamHandler\",\"url\":\"classes/RPCServer.html#registerDuplexStreamHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":2048,\"name\":\"registerUnaryHandler\",\"url\":\"classes/RPCServer.html#registerUnaryHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":2048,\"name\":\"registerServerStreamHandler\",\"url\":\"classes/RPCServer.html#registerServerStreamHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":2048,\"name\":\"registerClientStreamHandler\",\"url\":\"classes/RPCServer.html#registerClientStreamHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RPCServer\"},{\"kind\":2048,\"name\":\"handleStream\",\"url\":\"classes/RPCServer.html#handleStream\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RPCServer\"},{\"kind\":4,\"name\":\"utils\",\"url\":\"modules/utils.html\",\"classes\":\"tsd-kind-namespace\"},{\"kind\":64,\"name\":\"parseJSONRPCRequest\",\"url\":\"functions/utils.parseJSONRPCRequest.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"parseJSONRPCRequestMessage\",\"url\":\"functions/utils.parseJSONRPCRequestMessage.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"parseJSONRPCRequestNotification\",\"url\":\"functions/utils.parseJSONRPCRequestNotification.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"parseJSONRPCResponseResult\",\"url\":\"functions/utils.parseJSONRPCResponseResult.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"parseJSONRPCResponseError\",\"url\":\"functions/utils.parseJSONRPCResponseError.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"parseJSONRPCResponse\",\"url\":\"functions/utils.parseJSONRPCResponse.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"parseJSONRPCMessage\",\"url\":\"functions/utils.parseJSONRPCMessage.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"replacer\",\"url\":\"functions/utils.replacer.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"functions/utils.replacer.html#replacer.__type\",\"classes\":\"tsd-kind-type-literal\",\"parent\":\"utils.replacer.replacer\"},{\"kind\":64,\"name\":\"fromError\",\"url\":\"functions/utils.fromError.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"toError\",\"url\":\"functions/utils.toError.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"clientInputTransformStream\",\"url\":\"functions/utils.clientInputTransformStream.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"clientOutputTransformStream\",\"url\":\"functions/utils.clientOutputTransformStream.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"getHandlerTypes\",\"url\":\"functions/utils.getHandlerTypes.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"parseHeadStream\",\"url\":\"functions/utils.parseHeadStream.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"promise\",\"url\":\"functions/utils.promise.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"isObject\",\"url\":\"functions/utils.isObject.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":64,\"name\":\"sleep\",\"url\":\"functions/utils.sleep.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"kind\":4,\"name\":\"types\",\"url\":\"modules/types.html\",\"classes\":\"tsd-kind-namespace\"},{\"kind\":4194304,\"name\":\"IdGen\",\"url\":\"types/types.IdGen.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.IdGen.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"types.IdGen\"},{\"kind\":4194304,\"name\":\"JSONRPCRequestMessage\",\"url\":\"types/types.JSONRPCRequestMessage.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.JSONRPCRequestMessage.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"types.JSONRPCRequestMessage\"},{\"kind\":1024,\"name\":\"jsonrpc\",\"url\":\"types/types.JSONRPCRequestMessage.html#__type.jsonrpc\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCRequestMessage.__type\"},{\"kind\":1024,\"name\":\"method\",\"url\":\"types/types.JSONRPCRequestMessage.html#__type.method\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCRequestMessage.__type\"},{\"kind\":1024,\"name\":\"params\",\"url\":\"types/types.JSONRPCRequestMessage.html#__type.params\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCRequestMessage.__type\"},{\"kind\":1024,\"name\":\"id\",\"url\":\"types/types.JSONRPCRequestMessage.html#__type.id\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCRequestMessage.__type\"},{\"kind\":4194304,\"name\":\"JSONRPCRequestNotification\",\"url\":\"types/types.JSONRPCRequestNotification.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.JSONRPCRequestNotification.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"types.JSONRPCRequestNotification\"},{\"kind\":1024,\"name\":\"jsonrpc\",\"url\":\"types/types.JSONRPCRequestNotification.html#__type.jsonrpc\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCRequestNotification.__type\"},{\"kind\":1024,\"name\":\"method\",\"url\":\"types/types.JSONRPCRequestNotification.html#__type.method\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCRequestNotification.__type\"},{\"kind\":1024,\"name\":\"params\",\"url\":\"types/types.JSONRPCRequestNotification.html#__type.params\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCRequestNotification.__type\"},{\"kind\":4194304,\"name\":\"JSONRPCResponseResult\",\"url\":\"types/types.JSONRPCResponseResult.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.JSONRPCResponseResult.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"types.JSONRPCResponseResult\"},{\"kind\":1024,\"name\":\"jsonrpc\",\"url\":\"types/types.JSONRPCResponseResult.html#__type.jsonrpc\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCResponseResult.__type\"},{\"kind\":1024,\"name\":\"result\",\"url\":\"types/types.JSONRPCResponseResult.html#__type.result\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCResponseResult.__type\"},{\"kind\":1024,\"name\":\"id\",\"url\":\"types/types.JSONRPCResponseResult.html#__type.id\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCResponseResult.__type\"},{\"kind\":4194304,\"name\":\"JSONRPCResponseError\",\"url\":\"types/types.JSONRPCResponseError.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.JSONRPCResponseError.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"types.JSONRPCResponseError\"},{\"kind\":1024,\"name\":\"jsonrpc\",\"url\":\"types/types.JSONRPCResponseError.html#__type.jsonrpc\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCResponseError.__type\"},{\"kind\":1024,\"name\":\"error\",\"url\":\"types/types.JSONRPCResponseError.html#__type.error\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCResponseError.__type\"},{\"kind\":1024,\"name\":\"id\",\"url\":\"types/types.JSONRPCResponseError.html#__type.id\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCResponseError.__type\"},{\"kind\":4194304,\"name\":\"JSONRPCError\",\"url\":\"types/types.JSONRPCError.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.JSONRPCError.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"types.JSONRPCError\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"types/types.JSONRPCError.html#__type.code\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCError.__type\"},{\"kind\":1024,\"name\":\"message\",\"url\":\"types/types.JSONRPCError.html#__type.message\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCError.__type\"},{\"kind\":1024,\"name\":\"data\",\"url\":\"types/types.JSONRPCError.html#__type.data\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCError.__type\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"types/types.JSONRPCError.html#__type.type\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.JSONRPCError.__type\"},{\"kind\":4194304,\"name\":\"JSONRPCRequest\",\"url\":\"types/types.JSONRPCRequest.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"JSONRPCResponse\",\"url\":\"types/types.JSONRPCResponse.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"JSONRPCMessage\",\"url\":\"types/types.JSONRPCMessage.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"HandlerImplementation\",\"url\":\"types/types.HandlerImplementation.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.HandlerImplementation.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"types.HandlerImplementation\"},{\"kind\":4194304,\"name\":\"RawHandlerImplementation\",\"url\":\"types/types.RawHandlerImplementation.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"DuplexHandlerImplementation\",\"url\":\"types/types.DuplexHandlerImplementation.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"ServerHandlerImplementation\",\"url\":\"types/types.ServerHandlerImplementation.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"ClientHandlerImplementation\",\"url\":\"types/types.ClientHandlerImplementation.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"UnaryHandlerImplementation\",\"url\":\"types/types.UnaryHandlerImplementation.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"ContainerType\",\"url\":\"types/types.ContainerType.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":256,\"name\":\"RPCStream\",\"url\":\"interfaces/types.RPCStream.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":1024,\"name\":\"cancel\",\"url\":\"interfaces/types.RPCStream.html#cancel\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types.RPCStream\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"interfaces/types.RPCStream.html#cancel.__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"types.RPCStream.cancel\"},{\"kind\":1024,\"name\":\"meta\",\"url\":\"interfaces/types.RPCStream.html#meta\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types.RPCStream\"},{\"kind\":4194304,\"name\":\"StreamFactory\",\"url\":\"types/types.StreamFactory.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.StreamFactory.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"types.StreamFactory\"},{\"kind\":4194304,\"name\":\"MiddlewareFactory\",\"url\":\"types/types.MiddlewareFactory.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.MiddlewareFactory.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"types.MiddlewareFactory\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.MiddlewareFactory.html#__type.__type-1.__type-2\",\"classes\":\"tsd-kind-type-literal\",\"parent\":\"types.MiddlewareFactory.__type.__type\"},{\"kind\":1024,\"name\":\"forward\",\"url\":\"types/types.MiddlewareFactory.html#__type.__type-1.__type-2.forward\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.MiddlewareFactory.__type.__type.__type\"},{\"kind\":1024,\"name\":\"reverse\",\"url\":\"types/types.MiddlewareFactory.html#__type.__type-1.__type-2.reverse\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.MiddlewareFactory.__type.__type.__type\"},{\"kind\":4194304,\"name\":\"ServerManifest\",\"url\":\"types/types.ServerManifest.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"ClientManifest\",\"url\":\"types/types.ClientManifest.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"HandlerType\",\"url\":\"types/types.HandlerType.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"MapCallers\",\"url\":\"types/types.MapCallers.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"JSONValue\",\"url\":\"types/types.JSONValue.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":4194304,\"name\":\"POJO\",\"url\":\"types/types.POJO.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.POJO.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"types.POJO\"},{\"kind\":4194304,\"name\":\"PromiseDeconstructed\",\"url\":\"types/types.PromiseDeconstructed.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-namespace\",\"parent\":\"types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.PromiseDeconstructed.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"types.PromiseDeconstructed\"},{\"kind\":1024,\"name\":\"p\",\"url\":\"types/types.PromiseDeconstructed.html#__type.p\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.PromiseDeconstructed.__type\"},{\"kind\":1024,\"name\":\"resolveP\",\"url\":\"types/types.PromiseDeconstructed.html#__type.resolveP\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.PromiseDeconstructed.__type\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.PromiseDeconstructed.html#__type.resolveP.__type-3\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"types.PromiseDeconstructed.__type.resolveP\"},{\"kind\":1024,\"name\":\"rejectP\",\"url\":\"types/types.PromiseDeconstructed.html#__type.rejectP\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types.PromiseDeconstructed.__type\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/types.PromiseDeconstructed.html#__type.rejectP.__type-1\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"types.PromiseDeconstructed.__type.rejectP\"},{\"kind\":4,\"name\":\"errors\",\"url\":\"modules/errors.html\",\"classes\":\"tsd-kind-namespace\"},{\"kind\":64,\"name\":\"never\",\"url\":\"functions/errors.never.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":128,\"name\":\"ErrorRPC\",\"url\":\"classes/errors.ErrorRPC.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPC.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPC\"},{\"kind\":1024,\"name\":\"_description\",\"url\":\"classes/errors.ErrorRPC.html#_description\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"errors.ErrorRPC\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPC.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPC\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPC.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPC\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPC.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPC\"},{\"kind\":128,\"name\":\"ErrorRPCDestroyed\",\"url\":\"classes/errors.ErrorRPCDestroyed.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCDestroyed.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCDestroyed\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCDestroyed.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCDestroyed\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCDestroyed.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCDestroyed\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCDestroyed.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCDestroyed\"},{\"kind\":128,\"name\":\"ErrorRPCStopping\",\"url\":\"classes/errors.ErrorRPCStopping.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCStopping.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCStopping\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCStopping.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCStopping\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCStopping.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCStopping\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCStopping.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCStopping\"},{\"kind\":128,\"name\":\"ErrorRPCParse\",\"url\":\"classes/errors.ErrorRPCParse.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":1024,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCParse.html#description\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCParse\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCParse.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCParse\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCParse.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCParse\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCParse.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCParse\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCParse.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCParse\"},{\"kind\":128,\"name\":\"ErrorRPCHandlerFailed\",\"url\":\"classes/errors.ErrorRPCHandlerFailed.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCHandlerFailed.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCHandlerFailed\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCHandlerFailed.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCHandlerFailed\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCHandlerFailed.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCHandlerFailed\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCHandlerFailed.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCHandlerFailed\"},{\"kind\":128,\"name\":\"ErrorRPCMessageLength\",\"url\":\"classes/errors.ErrorRPCMessageLength.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":1024,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCMessageLength.html#description\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCMessageLength\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCMessageLength.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCMessageLength\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCMessageLength.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCMessageLength\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCMessageLength.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCMessageLength\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCMessageLength.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCMessageLength\"},{\"kind\":128,\"name\":\"ErrorRPCMissingResponse\",\"url\":\"classes/errors.ErrorRPCMissingResponse.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCMissingResponse.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCMissingResponse\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCMissingResponse.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCMissingResponse\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCMissingResponse.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCMissingResponse\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCMissingResponse.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCMissingResponse\"},{\"kind\":128,\"name\":\"ErrorRPCOutputStreamError\",\"url\":\"classes/errors.ErrorRPCOutputStreamError.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCOutputStreamError.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCOutputStreamError\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCOutputStreamError.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCOutputStreamError\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCOutputStreamError.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCOutputStreamError\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCOutputStreamError.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCOutputStreamError\"},{\"kind\":128,\"name\":\"ErrorRPCRemote\",\"url\":\"classes/errors.ErrorRPCRemote.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":1024,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCRemote.html#description\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCRemote\"},{\"kind\":1024,\"name\":\"message\",\"url\":\"classes/errors.ErrorRPCRemote.html#message-1\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCRemote\"},{\"kind\":2048,\"name\":\"fromJSON\",\"url\":\"classes/errors.ErrorRPCRemote.html#fromJSON\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCRemote\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCRemote.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCRemote\"},{\"kind\":1024,\"name\":\"metadata\",\"url\":\"classes/errors.ErrorRPCRemote.html#metadata\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCRemote\"},{\"kind\":2048,\"name\":\"toJSON\",\"url\":\"classes/errors.ErrorRPCRemote.html#toJSON\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCRemote\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCRemote.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCRemote\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCRemote.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCRemote\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCRemote.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCRemote\"},{\"kind\":128,\"name\":\"ErrorRPCStreamEnded\",\"url\":\"classes/errors.ErrorRPCStreamEnded.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCStreamEnded.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCStreamEnded\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCStreamEnded.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCStreamEnded\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCStreamEnded.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCStreamEnded\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCStreamEnded.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCStreamEnded\"},{\"kind\":128,\"name\":\"ErrorRPCTimedOut\",\"url\":\"classes/errors.ErrorRPCTimedOut.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCTimedOut.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCTimedOut\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCTimedOut.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCTimedOut\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCTimedOut.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCTimedOut\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCTimedOut.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCTimedOut\"},{\"kind\":128,\"name\":\"ErrorUtilsUndefinedBehaviour\",\"url\":\"classes/errors.ErrorUtilsUndefinedBehaviour.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorUtilsUndefinedBehaviour.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorUtilsUndefinedBehaviour\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorUtilsUndefinedBehaviour.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorUtilsUndefinedBehaviour\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorUtilsUndefinedBehaviour.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorUtilsUndefinedBehaviour\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorUtilsUndefinedBehaviour.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorUtilsUndefinedBehaviour\"},{\"kind\":128,\"name\":\"ErrorRPCMethodNotImplemented\",\"url\":\"classes/errors.ErrorRPCMethodNotImplemented.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCMethodNotImplemented.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCMethodNotImplemented\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCMethodNotImplemented.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCMethodNotImplemented\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCMethodNotImplemented.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCMethodNotImplemented\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCMethodNotImplemented.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCMethodNotImplemented\"},{\"kind\":128,\"name\":\"ErrorRPCConnectionLocal\",\"url\":\"classes/errors.ErrorRPCConnectionLocal.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":1024,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCConnectionLocal.html#description\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCConnectionLocal\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCConnectionLocal.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionLocal\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCConnectionLocal.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCConnectionLocal\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCConnectionLocal.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionLocal\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCConnectionLocal.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionLocal\"},{\"kind\":128,\"name\":\"ErrorRPCConnectionPeer\",\"url\":\"classes/errors.ErrorRPCConnectionPeer.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":1024,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCConnectionPeer.html#description\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCConnectionPeer\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCConnectionPeer.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionPeer\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCConnectionPeer.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCConnectionPeer\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCConnectionPeer.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionPeer\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCConnectionPeer.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionPeer\"},{\"kind\":128,\"name\":\"ErrorRPCConnectionKeepAliveTimeOut\",\"url\":\"classes/errors.ErrorRPCConnectionKeepAliveTimeOut.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":1024,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCConnectionKeepAliveTimeOut.html#description\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCConnectionKeepAliveTimeOut\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCConnectionKeepAliveTimeOut.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionKeepAliveTimeOut\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCConnectionKeepAliveTimeOut.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCConnectionKeepAliveTimeOut\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCConnectionKeepAliveTimeOut.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionKeepAliveTimeOut\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCConnectionKeepAliveTimeOut.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionKeepAliveTimeOut\"},{\"kind\":128,\"name\":\"ErrorRPCConnectionInternal\",\"url\":\"classes/errors.ErrorRPCConnectionInternal.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":1024,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCConnectionInternal.html#description\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCConnectionInternal\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCConnectionInternal.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionInternal\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCConnectionInternal.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCConnectionInternal\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCConnectionInternal.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionInternal\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCConnectionInternal.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCConnectionInternal\"},{\"kind\":128,\"name\":\"ErrorMissingHeader\",\"url\":\"classes/errors.ErrorMissingHeader.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorMissingHeader.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorMissingHeader\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorMissingHeader.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorMissingHeader\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorMissingHeader.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorMissingHeader\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorMissingHeader.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorMissingHeader\"},{\"kind\":128,\"name\":\"ErrorHandlerAborted\",\"url\":\"classes/errors.ErrorHandlerAborted.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorHandlerAborted.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorHandlerAborted\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorHandlerAborted.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorHandlerAborted\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorHandlerAborted.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorHandlerAborted\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorHandlerAborted.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorHandlerAborted\"},{\"kind\":128,\"name\":\"ErrorRPCCallerFailed\",\"url\":\"classes/errors.ErrorRPCCallerFailed.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorRPCCallerFailed.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorRPCCallerFailed\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorRPCCallerFailed.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCCallerFailed\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorRPCCallerFailed.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCCallerFailed\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorRPCCallerFailed.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorRPCCallerFailed\"},{\"kind\":128,\"name\":\"ErrorMissingCaller\",\"url\":\"classes/errors.ErrorMissingCaller.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorMissingCaller.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"errors.ErrorMissingCaller\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/errors.ErrorMissingCaller.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorMissingCaller\"},{\"kind\":1024,\"name\":\"code\",\"url\":\"classes/errors.ErrorMissingCaller.html#code\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorMissingCaller\"},{\"kind\":262144,\"name\":\"description\",\"url\":\"classes/errors.ErrorMissingCaller.html#description-1\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorMissingCaller\"},{\"kind\":8,\"name\":\"JSONRPCErrorCode\",\"url\":\"enums/errors.JSONRPCErrorCode.html\",\"classes\":\"tsd-kind-enum tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"kind\":16,\"name\":\"ParseError\",\"url\":\"enums/errors.JSONRPCErrorCode.html#ParseError\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"InvalidRequest\",\"url\":\"enums/errors.JSONRPCErrorCode.html#InvalidRequest\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"MethodNotFound\",\"url\":\"enums/errors.JSONRPCErrorCode.html#MethodNotFound\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"InvalidParams\",\"url\":\"enums/errors.JSONRPCErrorCode.html#InvalidParams\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"InternalError\",\"url\":\"enums/errors.JSONRPCErrorCode.html#InternalError\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"HandlerNotFound\",\"url\":\"enums/errors.JSONRPCErrorCode.html#HandlerNotFound\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCStopping\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCStopping\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCDestroyed\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCDestroyed\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCMessageLength\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCMessageLength\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCMissingResponse\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCMissingResponse\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCOutputStreamError\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCOutputStreamError\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCRemote\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCRemote\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCStreamEnded\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCStreamEnded\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCTimedOut\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCTimedOut\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCConnectionLocal\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCConnectionLocal\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCConnectionPeer\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCConnectionPeer\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCConnectionKeepAliveTimeOut\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCConnectionKeepAliveTimeOut\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"RPCConnectionInternal\",\"url\":\"enums/errors.JSONRPCErrorCode.html#RPCConnectionInternal\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"MissingHeader\",\"url\":\"enums/errors.JSONRPCErrorCode.html#MissingHeader\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"HandlerAborted\",\"url\":\"enums/errors.JSONRPCErrorCode.html#HandlerAborted\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":16,\"name\":\"MissingCaller\",\"url\":\"enums/errors.JSONRPCErrorCode.html#MissingCaller\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"errors.JSONRPCErrorCode\"},{\"kind\":4,\"name\":\"events\",\"url\":\"modules/events.html\",\"classes\":\"tsd-kind-namespace\"},{\"kind\":128,\"name\":\"RPCErrorEvent\",\"url\":\"classes/events.RPCErrorEvent.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/events.RPCErrorEvent.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"events.RPCErrorEvent\"},{\"kind\":1024,\"name\":\"detail\",\"url\":\"classes/events.RPCErrorEvent.html#detail\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"events.RPCErrorEvent\"},{\"kind\":128,\"name\":\"EventRPC\",\"url\":\"classes/events.EventRPC.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCClient\",\"url\":\"classes/events.EventRPCClient.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCServer\",\"url\":\"classes/events.EventRPCServer.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCConnection\",\"url\":\"classes/events.EventRPCConnection.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCClientDestroy\",\"url\":\"classes/events.EventRPCClientDestroy.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCClientDestroyed\",\"url\":\"classes/events.EventRPCClientDestroyed.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCClientCreate\",\"url\":\"classes/events.EventRPCClientCreate.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCClientCreated\",\"url\":\"classes/events.EventRPCClientCreated.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCClientError\",\"url\":\"classes/events.EventRPCClientError.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCClientConnect\",\"url\":\"classes/events.EventRPCClientConnect.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCServerConnection\",\"url\":\"classes/events.EventRPCServerConnection.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCServerCreate\",\"url\":\"classes/events.EventRPCServerCreate.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCServerCreated\",\"url\":\"classes/events.EventRPCServerCreated.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCServerDestroy\",\"url\":\"classes/events.EventRPCServerDestroy.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCServerDestroyed\",\"url\":\"classes/events.EventRPCServerDestroyed.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCServerError\",\"url\":\"classes/events.EventRPCServerError.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":128,\"name\":\"EventRPCConnectionError\",\"url\":\"classes/events.EventRPCConnectionError.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"events\"},{\"kind\":4,\"name\":\"handlers\",\"url\":\"modules/handlers.html\",\"classes\":\"tsd-kind-namespace\"},{\"kind\":128,\"name\":\"Handler\",\"url\":\"classes/handlers.Handler.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"handlers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/handlers.Handler.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"handlers.Handler\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/handlers.Handler.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"handlers.Handler\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/handlers.Handler.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"handlers.Handler\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/handlers.Handler.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"handlers.Handler\"},{\"kind\":1024,\"name\":\"container\",\"url\":\"classes/handlers.Handler.html#container\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"handlers.Handler\"},{\"kind\":128,\"name\":\"ClientHandler\",\"url\":\"classes/handlers.ClientHandler.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"handlers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/handlers.ClientHandler.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"handlers.ClientHandler\"},{\"kind\":2048,\"name\":\"handle\",\"url\":\"classes/handlers.ClientHandler.html#handle\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"handlers.ClientHandler\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/handlers.ClientHandler.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.ClientHandler\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/handlers.ClientHandler.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.ClientHandler\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/handlers.ClientHandler.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"handlers.ClientHandler\"},{\"kind\":1024,\"name\":\"container\",\"url\":\"classes/handlers.ClientHandler.html#container\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.ClientHandler\"},{\"kind\":128,\"name\":\"DuplexHandler\",\"url\":\"classes/handlers.DuplexHandler.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"handlers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/handlers.DuplexHandler.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"handlers.DuplexHandler\"},{\"kind\":1024,\"name\":\"handle\",\"url\":\"classes/handlers.DuplexHandler.html#handle\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"handlers.DuplexHandler\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"classes/handlers.DuplexHandler.html#handle.__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"handlers.DuplexHandler.handle\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/handlers.DuplexHandler.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.DuplexHandler\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/handlers.DuplexHandler.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.DuplexHandler\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/handlers.DuplexHandler.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"handlers.DuplexHandler\"},{\"kind\":1024,\"name\":\"container\",\"url\":\"classes/handlers.DuplexHandler.html#container\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.DuplexHandler\"},{\"kind\":128,\"name\":\"RawHandler\",\"url\":\"classes/handlers.RawHandler.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"handlers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/handlers.RawHandler.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"handlers.RawHandler\"},{\"kind\":2048,\"name\":\"handle\",\"url\":\"classes/handlers.RawHandler.html#handle\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"handlers.RawHandler\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/handlers.RawHandler.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.RawHandler\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/handlers.RawHandler.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.RawHandler\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/handlers.RawHandler.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"handlers.RawHandler\"},{\"kind\":1024,\"name\":\"container\",\"url\":\"classes/handlers.RawHandler.html#container\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.RawHandler\"},{\"kind\":128,\"name\":\"ServerHandler\",\"url\":\"classes/handlers.ServerHandler.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"handlers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/handlers.ServerHandler.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"handlers.ServerHandler\"},{\"kind\":1024,\"name\":\"handle\",\"url\":\"classes/handlers.ServerHandler.html#handle\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"handlers.ServerHandler\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"classes/handlers.ServerHandler.html#handle.__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"handlers.ServerHandler.handle\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/handlers.ServerHandler.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.ServerHandler\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/handlers.ServerHandler.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.ServerHandler\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/handlers.ServerHandler.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"handlers.ServerHandler\"},{\"kind\":1024,\"name\":\"container\",\"url\":\"classes/handlers.ServerHandler.html#container\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.ServerHandler\"},{\"kind\":128,\"name\":\"UnaryHandler\",\"url\":\"classes/handlers.UnaryHandler.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"handlers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/handlers.UnaryHandler.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"handlers.UnaryHandler\"},{\"kind\":2048,\"name\":\"handle\",\"url\":\"classes/handlers.UnaryHandler.html#handle\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"handlers.UnaryHandler\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/handlers.UnaryHandler.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.UnaryHandler\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/handlers.UnaryHandler.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.UnaryHandler\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/handlers.UnaryHandler.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"handlers.UnaryHandler\"},{\"kind\":1024,\"name\":\"container\",\"url\":\"classes/handlers.UnaryHandler.html#container\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"handlers.UnaryHandler\"},{\"kind\":4,\"name\":\"callers\",\"url\":\"modules/callers.html\",\"classes\":\"tsd-kind-namespace\"},{\"kind\":128,\"name\":\"Caller\",\"url\":\"classes/callers.Caller.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"callers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/callers.Caller.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"callers.Caller\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/callers.Caller.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"callers.Caller\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/callers.Caller.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"callers.Caller\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/callers.Caller.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"callers.Caller\"},{\"kind\":128,\"name\":\"ClientCaller\",\"url\":\"classes/callers.ClientCaller.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"callers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/callers.ClientCaller.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"callers.ClientCaller\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/callers.ClientCaller.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"callers.ClientCaller\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/callers.ClientCaller.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"callers.ClientCaller\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/callers.ClientCaller.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"callers.ClientCaller\"},{\"kind\":128,\"name\":\"DuplexCaller\",\"url\":\"classes/callers.DuplexCaller.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"callers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/callers.DuplexCaller.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"callers.DuplexCaller\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/callers.DuplexCaller.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"callers.DuplexCaller\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/callers.DuplexCaller.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"callers.DuplexCaller\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/callers.DuplexCaller.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"callers.DuplexCaller\"},{\"kind\":128,\"name\":\"RawCaller\",\"url\":\"classes/callers.RawCaller.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"callers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/callers.RawCaller.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"callers.RawCaller\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/callers.RawCaller.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"callers.RawCaller\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/callers.RawCaller.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"callers.RawCaller\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/callers.RawCaller.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"callers.RawCaller\"},{\"kind\":128,\"name\":\"ServerCaller\",\"url\":\"classes/callers.ServerCaller.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"callers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/callers.ServerCaller.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"callers.ServerCaller\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/callers.ServerCaller.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"callers.ServerCaller\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/callers.ServerCaller.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"callers.ServerCaller\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/callers.ServerCaller.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"callers.ServerCaller\"},{\"kind\":128,\"name\":\"UnaryCaller\",\"url\":\"classes/callers.UnaryCaller.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"callers\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/callers.UnaryCaller.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"callers.UnaryCaller\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"classes/callers.UnaryCaller.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"callers.UnaryCaller\"},{\"kind\":1024,\"name\":\"_inputType\",\"url\":\"classes/callers.UnaryCaller.html#_inputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"callers.UnaryCaller\"},{\"kind\":1024,\"name\":\"_outputType\",\"url\":\"classes/callers.UnaryCaller.html#_outputType\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"callers.UnaryCaller\"}],\"index\":{\"version\":\"2.3.9\",\"fields\":[\"name\",\"comment\"],\"fieldVectors\":[[\"name/0\",[0,55.053]],[\"comment/0\",[]],[\"name/1\",[1,55.053]],[\"comment/1\",[]],[\"name/2\",[2,23.135]],[\"comment/2\",[]],[\"name/3\",[3,49.945]],[\"comment/3\",[]],[\"name/4\",[4,27.538]],[\"comment/4\",[]],[\"name/5\",[5,46.58]],[\"comment/5\",[]],[\"name/6\",[6,49.945]],[\"comment/6\",[]],[\"name/7\",[7,49.945]],[\"comment/7\",[]],[\"name/8\",[8,46.58]],[\"comment/8\",[]],[\"name/9\",[9,55.053]],[\"comment/9\",[]],[\"name/10\",[10,49.945]],[\"comment/10\",[]],[\"name/11\",[11,55.053]],[\"comment/11\",[]],[\"name/12\",[12,55.053]],[\"comment/12\",[]],[\"name/13\",[4,27.538]],[\"comment/13\",[]],[\"name/14\",[13,49.945]],[\"comment/14\",[]],[\"name/15\",[14,55.053]],[\"comment/15\",[]],[\"name/16\",[15,49.945]],[\"comment/16\",[]],[\"name/17\",[16,55.053]],[\"comment/17\",[]],[\"name/18\",[17,55.053]],[\"comment/18\",[]],[\"name/19\",[18,55.053]],[\"comment/19\",[]],[\"name/20\",[19,55.053]],[\"comment/20\",[]],[\"name/21\",[20,55.053]],[\"comment/21\",[]],[\"name/22\",[21,55.053]],[\"comment/22\",[]],[\"name/23\",[2,23.135]],[\"comment/23\",[]],[\"name/24\",[3,49.945]],[\"comment/24\",[]],[\"name/25\",[4,27.538]],[\"comment/25\",[]],[\"name/26\",[5,46.58]],[\"comment/26\",[]],[\"name/27\",[6,49.945]],[\"comment/27\",[]],[\"name/28\",[22,55.053]],[\"comment/28\",[]],[\"name/29\",[23,55.053]],[\"comment/29\",[]],[\"name/30\",[24,55.053]],[\"comment/30\",[]],[\"name/31\",[25,55.053]],[\"comment/31\",[]],[\"name/32\",[26,55.053]],[\"comment/32\",[]],[\"name/33\",[27,49.945]],[\"comment/33\",[]],[\"name/34\",[4,27.538]],[\"comment/34\",[]],[\"name/35\",[28,49.945]],[\"comment/35\",[]],[\"name/36\",[4,27.538]],[\"comment/36\",[]],[\"name/37\",[8,46.58]],[\"comment/37\",[]],[\"name/38\",[10,49.945]],[\"comment/38\",[]],[\"name/39\",[13,49.945]],[\"comment/39\",[]],[\"name/40\",[29,55.053]],[\"comment/40\",[]],[\"name/41\",[30,55.053]],[\"comment/41\",[]],[\"name/42\",[31,55.053]],[\"comment/42\",[]],[\"name/43\",[32,55.053]],[\"comment/43\",[]],[\"name/44\",[33,55.053]],[\"comment/44\",[]],[\"name/45\",[34,55.053]],[\"comment/45\",[]],[\"name/46\",[35,55.053]],[\"comment/46\",[]],[\"name/47\",[36,55.053]],[\"comment/47\",[]],[\"name/48\",[37,55.053]],[\"comment/48\",[]],[\"name/49\",[38,55.053]],[\"comment/49\",[]],[\"name/50\",[39,55.053]],[\"comment/50\",[]],[\"name/51\",[40,55.053]],[\"comment/51\",[]],[\"name/52\",[41,55.053]],[\"comment/52\",[]],[\"name/53\",[42,55.053]],[\"comment/53\",[]],[\"name/54\",[28,49.945]],[\"comment/54\",[]],[\"name/55\",[4,27.538]],[\"comment/55\",[]],[\"name/56\",[27,49.945]],[\"comment/56\",[]],[\"name/57\",[43,55.053]],[\"comment/57\",[]],[\"name/58\",[44,55.053]],[\"comment/58\",[]],[\"name/59\",[45,55.053]],[\"comment/59\",[]],[\"name/60\",[46,55.053]],[\"comment/60\",[]],[\"name/61\",[47,55.053]],[\"comment/61\",[]],[\"name/62\",[48,55.053]],[\"comment/62\",[]],[\"name/63\",[49,55.053]],[\"comment/63\",[]],[\"name/64\",[50,55.053]],[\"comment/64\",[]],[\"name/65\",[51,55.053]],[\"comment/65\",[]],[\"name/66\",[5,46.58]],[\"comment/66\",[]],[\"name/67\",[4,27.538]],[\"comment/67\",[]],[\"name/68\",[52,55.053]],[\"comment/68\",[]],[\"name/69\",[4,27.538]],[\"comment/69\",[]],[\"name/70\",[53,44.067]],[\"comment/70\",[]],[\"name/71\",[54,49.945]],[\"comment/71\",[]],[\"name/72\",[55,49.945]],[\"comment/72\",[]],[\"name/73\",[56,46.58]],[\"comment/73\",[]],[\"name/74\",[57,55.053]],[\"comment/74\",[]],[\"name/75\",[4,27.538]],[\"comment/75\",[]],[\"name/76\",[53,44.067]],[\"comment/76\",[]],[\"name/77\",[54,49.945]],[\"comment/77\",[]],[\"name/78\",[55,49.945]],[\"comment/78\",[]],[\"name/79\",[58,55.053]],[\"comment/79\",[]],[\"name/80\",[4,27.538]],[\"comment/80\",[]],[\"name/81\",[53,44.067]],[\"comment/81\",[]],[\"name/82\",[59,55.053]],[\"comment/82\",[]],[\"name/83\",[56,46.58]],[\"comment/83\",[]],[\"name/84\",[60,55.053]],[\"comment/84\",[]],[\"name/85\",[4,27.538]],[\"comment/85\",[]],[\"name/86\",[53,44.067]],[\"comment/86\",[]],[\"name/87\",[61,55.053]],[\"comment/87\",[]],[\"name/88\",[56,46.58]],[\"comment/88\",[]],[\"name/89\",[62,55.053]],[\"comment/89\",[]],[\"name/90\",[4,27.538]],[\"comment/90\",[]],[\"name/91\",[63,27.973]],[\"comment/91\",[]],[\"name/92\",[64,49.945]],[\"comment/92\",[]],[\"name/93\",[65,55.053]],[\"comment/93\",[]],[\"name/94\",[66,25.609]],[\"comment/94\",[]],[\"name/95\",[67,55.053]],[\"comment/95\",[]],[\"name/96\",[68,55.053]],[\"comment/96\",[]],[\"name/97\",[69,55.053]],[\"comment/97\",[]],[\"name/98\",[70,55.053]],[\"comment/98\",[]],[\"name/99\",[4,27.538]],[\"comment/99\",[]],[\"name/100\",[71,55.053]],[\"comment/100\",[]],[\"name/101\",[72,55.053]],[\"comment/101\",[]],[\"name/102\",[73,55.053]],[\"comment/102\",[]],[\"name/103\",[74,55.053]],[\"comment/103\",[]],[\"name/104\",[75,55.053]],[\"comment/104\",[]],[\"name/105\",[76,55.053]],[\"comment/105\",[]],[\"name/106\",[77,55.053]],[\"comment/106\",[]],[\"name/107\",[78,55.053]],[\"comment/107\",[]],[\"name/108\",[4,27.538]],[\"comment/108\",[]],[\"name/109\",[79,55.053]],[\"comment/109\",[]],[\"name/110\",[7,49.945]],[\"comment/110\",[]],[\"name/111\",[4,27.538]],[\"comment/111\",[]],[\"name/112\",[8,46.58]],[\"comment/112\",[]],[\"name/113\",[4,27.538]],[\"comment/113\",[]],[\"name/114\",[4,27.538]],[\"comment/114\",[]],[\"name/115\",[80,55.053]],[\"comment/115\",[]],[\"name/116\",[81,55.053]],[\"comment/116\",[]],[\"name/117\",[82,55.053]],[\"comment/117\",[]],[\"name/118\",[83,55.053]],[\"comment/118\",[]],[\"name/119\",[84,55.053]],[\"comment/119\",[]],[\"name/120\",[85,55.053]],[\"comment/120\",[]],[\"name/121\",[86,55.053]],[\"comment/121\",[]],[\"name/122\",[87,55.053]],[\"comment/122\",[]],[\"name/123\",[4,27.538]],[\"comment/123\",[]],[\"name/124\",[88,55.053]],[\"comment/124\",[]],[\"name/125\",[4,27.538]],[\"comment/125\",[]],[\"name/126\",[89,55.053]],[\"comment/126\",[]],[\"name/127\",[90,55.053]],[\"comment/127\",[]],[\"name/128\",[4,27.538]],[\"comment/128\",[]],[\"name/129\",[91,55.053]],[\"comment/129\",[]],[\"name/130\",[4,27.538]],[\"comment/130\",[]],[\"name/131\",[92,55.053]],[\"comment/131\",[]],[\"name/132\",[93,55.053]],[\"comment/132\",[]],[\"name/133\",[94,55.053]],[\"comment/133\",[]],[\"name/134\",[2,23.135]],[\"comment/134\",[]],[\"name/135\",[95,55.053]],[\"comment/135\",[]],[\"name/136\",[66,25.609]],[\"comment/136\",[]],[\"name/137\",[63,27.973]],[\"comment/137\",[]],[\"name/138\",[96,25.609]],[\"comment/138\",[]],[\"name/139\",[97,55.053]],[\"comment/139\",[]],[\"name/140\",[2,23.135]],[\"comment/140\",[]],[\"name/141\",[66,25.609]],[\"comment/141\",[]],[\"name/142\",[63,27.973]],[\"comment/142\",[]],[\"name/143\",[96,25.609]],[\"comment/143\",[]],[\"name/144\",[98,55.053]],[\"comment/144\",[]],[\"name/145\",[2,23.135]],[\"comment/145\",[]],[\"name/146\",[66,25.609]],[\"comment/146\",[]],[\"name/147\",[63,27.973]],[\"comment/147\",[]],[\"name/148\",[96,25.609]],[\"comment/148\",[]],[\"name/149\",[99,55.053]],[\"comment/149\",[]],[\"name/150\",[96,25.609]],[\"comment/150\",[]],[\"name/151\",[2,23.135]],[\"comment/151\",[]],[\"name/152\",[66,25.609]],[\"comment/152\",[]],[\"name/153\",[63,27.973]],[\"comment/153\",[]],[\"name/154\",[96,25.609]],[\"comment/154\",[]],[\"name/155\",[100,55.053]],[\"comment/155\",[]],[\"name/156\",[2,23.135]],[\"comment/156\",[]],[\"name/157\",[66,25.609]],[\"comment/157\",[]],[\"name/158\",[63,27.973]],[\"comment/158\",[]],[\"name/159\",[96,25.609]],[\"comment/159\",[]],[\"name/160\",[101,55.053]],[\"comment/160\",[]],[\"name/161\",[96,25.609]],[\"comment/161\",[]],[\"name/162\",[2,23.135]],[\"comment/162\",[]],[\"name/163\",[63,27.973]],[\"comment/163\",[]],[\"name/164\",[66,25.609]],[\"comment/164\",[]],[\"name/165\",[96,25.609]],[\"comment/165\",[]],[\"name/166\",[102,55.053]],[\"comment/166\",[]],[\"name/167\",[2,23.135]],[\"comment/167\",[]],[\"name/168\",[66,25.609]],[\"comment/168\",[]],[\"name/169\",[63,27.973]],[\"comment/169\",[]],[\"name/170\",[96,25.609]],[\"comment/170\",[]],[\"name/171\",[103,55.053]],[\"comment/171\",[]],[\"name/172\",[2,23.135]],[\"comment/172\",[]],[\"name/173\",[66,25.609]],[\"comment/173\",[]],[\"name/174\",[63,27.973]],[\"comment/174\",[]],[\"name/175\",[96,25.609]],[\"comment/175\",[]],[\"name/176\",[104,55.053]],[\"comment/176\",[]],[\"name/177\",[96,25.609]],[\"comment/177\",[]],[\"name/178\",[64,49.945]],[\"comment/178\",[]],[\"name/179\",[105,55.053]],[\"comment/179\",[]],[\"name/180\",[2,23.135]],[\"comment/180\",[]],[\"name/181\",[106,55.053]],[\"comment/181\",[]],[\"name/182\",[107,55.053]],[\"comment/182\",[]],[\"name/183\",[66,25.609]],[\"comment/183\",[]],[\"name/184\",[63,27.973]],[\"comment/184\",[]],[\"name/185\",[96,25.609]],[\"comment/185\",[]],[\"name/186\",[108,55.053]],[\"comment/186\",[]],[\"name/187\",[2,23.135]],[\"comment/187\",[]],[\"name/188\",[66,25.609]],[\"comment/188\",[]],[\"name/189\",[63,27.973]],[\"comment/189\",[]],[\"name/190\",[96,25.609]],[\"comment/190\",[]],[\"name/191\",[109,55.053]],[\"comment/191\",[]],[\"name/192\",[2,23.135]],[\"comment/192\",[]],[\"name/193\",[66,25.609]],[\"comment/193\",[]],[\"name/194\",[63,27.973]],[\"comment/194\",[]],[\"name/195\",[96,25.609]],[\"comment/195\",[]],[\"name/196\",[110,55.053]],[\"comment/196\",[]],[\"name/197\",[2,23.135]],[\"comment/197\",[]],[\"name/198\",[66,25.609]],[\"comment/198\",[]],[\"name/199\",[63,27.973]],[\"comment/199\",[]],[\"name/200\",[96,25.609]],[\"comment/200\",[]],[\"name/201\",[111,55.053]],[\"comment/201\",[]],[\"name/202\",[2,23.135]],[\"comment/202\",[]],[\"name/203\",[66,25.609]],[\"comment/203\",[]],[\"name/204\",[63,27.973]],[\"comment/204\",[]],[\"name/205\",[96,25.609]],[\"comment/205\",[]],[\"name/206\",[112,55.053]],[\"comment/206\",[]],[\"name/207\",[96,25.609]],[\"comment/207\",[]],[\"name/208\",[2,23.135]],[\"comment/208\",[]],[\"name/209\",[63,27.973]],[\"comment/209\",[]],[\"name/210\",[66,25.609]],[\"comment/210\",[]],[\"name/211\",[96,25.609]],[\"comment/211\",[]],[\"name/212\",[113,55.053]],[\"comment/212\",[]],[\"name/213\",[96,25.609]],[\"comment/213\",[]],[\"name/214\",[2,23.135]],[\"comment/214\",[]],[\"name/215\",[63,27.973]],[\"comment/215\",[]],[\"name/216\",[66,25.609]],[\"comment/216\",[]],[\"name/217\",[96,25.609]],[\"comment/217\",[]],[\"name/218\",[114,55.053]],[\"comment/218\",[]],[\"name/219\",[96,25.609]],[\"comment/219\",[]],[\"name/220\",[2,23.135]],[\"comment/220\",[]],[\"name/221\",[63,27.973]],[\"comment/221\",[]],[\"name/222\",[66,25.609]],[\"comment/222\",[]],[\"name/223\",[96,25.609]],[\"comment/223\",[]],[\"name/224\",[115,55.053]],[\"comment/224\",[]],[\"name/225\",[96,25.609]],[\"comment/225\",[]],[\"name/226\",[2,23.135]],[\"comment/226\",[]],[\"name/227\",[63,27.973]],[\"comment/227\",[]],[\"name/228\",[66,25.609]],[\"comment/228\",[]],[\"name/229\",[96,25.609]],[\"comment/229\",[]],[\"name/230\",[116,55.053]],[\"comment/230\",[]],[\"name/231\",[2,23.135]],[\"comment/231\",[]],[\"name/232\",[66,25.609]],[\"comment/232\",[]],[\"name/233\",[63,27.973]],[\"comment/233\",[]],[\"name/234\",[96,25.609]],[\"comment/234\",[]],[\"name/235\",[117,55.053]],[\"comment/235\",[]],[\"name/236\",[2,23.135]],[\"comment/236\",[]],[\"name/237\",[66,25.609]],[\"comment/237\",[]],[\"name/238\",[63,27.973]],[\"comment/238\",[]],[\"name/239\",[96,25.609]],[\"comment/239\",[]],[\"name/240\",[118,55.053]],[\"comment/240\",[]],[\"name/241\",[2,23.135]],[\"comment/241\",[]],[\"name/242\",[66,25.609]],[\"comment/242\",[]],[\"name/243\",[63,27.973]],[\"comment/243\",[]],[\"name/244\",[96,25.609]],[\"comment/244\",[]],[\"name/245\",[119,55.053]],[\"comment/245\",[]],[\"name/246\",[2,23.135]],[\"comment/246\",[]],[\"name/247\",[66,25.609]],[\"comment/247\",[]],[\"name/248\",[63,27.973]],[\"comment/248\",[]],[\"name/249\",[96,25.609]],[\"comment/249\",[]],[\"name/250\",[120,55.053]],[\"comment/250\",[]],[\"name/251\",[121,55.053]],[\"comment/251\",[]],[\"name/252\",[122,55.053]],[\"comment/252\",[]],[\"name/253\",[123,55.053]],[\"comment/253\",[]],[\"name/254\",[124,55.053]],[\"comment/254\",[]],[\"name/255\",[125,55.053]],[\"comment/255\",[]],[\"name/256\",[126,55.053]],[\"comment/256\",[]],[\"name/257\",[127,55.053]],[\"comment/257\",[]],[\"name/258\",[128,55.053]],[\"comment/258\",[]],[\"name/259\",[129,55.053]],[\"comment/259\",[]],[\"name/260\",[130,55.053]],[\"comment/260\",[]],[\"name/261\",[131,55.053]],[\"comment/261\",[]],[\"name/262\",[132,55.053]],[\"comment/262\",[]],[\"name/263\",[133,55.053]],[\"comment/263\",[]],[\"name/264\",[134,55.053]],[\"comment/264\",[]],[\"name/265\",[135,55.053]],[\"comment/265\",[]],[\"name/266\",[136,55.053]],[\"comment/266\",[]],[\"name/267\",[137,55.053]],[\"comment/267\",[]],[\"name/268\",[138,55.053]],[\"comment/268\",[]],[\"name/269\",[139,55.053]],[\"comment/269\",[]],[\"name/270\",[140,55.053]],[\"comment/270\",[]],[\"name/271\",[141,55.053]],[\"comment/271\",[]],[\"name/272\",[142,55.053]],[\"comment/272\",[]],[\"name/273\",[143,55.053]],[\"comment/273\",[]],[\"name/274\",[2,23.135]],[\"comment/274\",[]],[\"name/275\",[144,55.053]],[\"comment/275\",[]],[\"name/276\",[145,55.053]],[\"comment/276\",[]],[\"name/277\",[146,55.053]],[\"comment/277\",[]],[\"name/278\",[147,55.053]],[\"comment/278\",[]],[\"name/279\",[148,55.053]],[\"comment/279\",[]],[\"name/280\",[149,55.053]],[\"comment/280\",[]],[\"name/281\",[150,55.053]],[\"comment/281\",[]],[\"name/282\",[151,55.053]],[\"comment/282\",[]],[\"name/283\",[152,55.053]],[\"comment/283\",[]],[\"name/284\",[153,55.053]],[\"comment/284\",[]],[\"name/285\",[154,55.053]],[\"comment/285\",[]],[\"name/286\",[155,55.053]],[\"comment/286\",[]],[\"name/287\",[156,55.053]],[\"comment/287\",[]],[\"name/288\",[157,55.053]],[\"comment/288\",[]],[\"name/289\",[158,55.053]],[\"comment/289\",[]],[\"name/290\",[159,55.053]],[\"comment/290\",[]],[\"name/291\",[160,55.053]],[\"comment/291\",[]],[\"name/292\",[161,55.053]],[\"comment/292\",[]],[\"name/293\",[162,55.053]],[\"comment/293\",[]],[\"name/294\",[163,55.053]],[\"comment/294\",[]],[\"name/295\",[2,23.135]],[\"comment/295\",[]],[\"name/296\",[164,33.851]],[\"comment/296\",[]],[\"name/297\",[165,33.851]],[\"comment/297\",[]],[\"name/298\",[166,40.39]],[\"comment/298\",[]],[\"name/299\",[167,40.39]],[\"comment/299\",[]],[\"name/300\",[168,55.053]],[\"comment/300\",[]],[\"name/301\",[2,23.135]],[\"comment/301\",[]],[\"name/302\",[169,42.06]],[\"comment/302\",[]],[\"name/303\",[164,33.851]],[\"comment/303\",[]],[\"name/304\",[165,33.851]],[\"comment/304\",[]],[\"name/305\",[166,40.39]],[\"comment/305\",[]],[\"name/306\",[167,40.39]],[\"comment/306\",[]],[\"name/307\",[170,55.053]],[\"comment/307\",[]],[\"name/308\",[2,23.135]],[\"comment/308\",[]],[\"name/309\",[169,42.06]],[\"comment/309\",[]],[\"name/310\",[4,27.538]],[\"comment/310\",[]],[\"name/311\",[164,33.851]],[\"comment/311\",[]],[\"name/312\",[165,33.851]],[\"comment/312\",[]],[\"name/313\",[166,40.39]],[\"comment/313\",[]],[\"name/314\",[167,40.39]],[\"comment/314\",[]],[\"name/315\",[171,55.053]],[\"comment/315\",[]],[\"name/316\",[2,23.135]],[\"comment/316\",[]],[\"name/317\",[169,42.06]],[\"comment/317\",[]],[\"name/318\",[164,33.851]],[\"comment/318\",[]],[\"name/319\",[165,33.851]],[\"comment/319\",[]],[\"name/320\",[166,40.39]],[\"comment/320\",[]],[\"name/321\",[167,40.39]],[\"comment/321\",[]],[\"name/322\",[172,55.053]],[\"comment/322\",[]],[\"name/323\",[2,23.135]],[\"comment/323\",[]],[\"name/324\",[169,42.06]],[\"comment/324\",[]],[\"name/325\",[4,27.538]],[\"comment/325\",[]],[\"name/326\",[164,33.851]],[\"comment/326\",[]],[\"name/327\",[165,33.851]],[\"comment/327\",[]],[\"name/328\",[166,40.39]],[\"comment/328\",[]],[\"name/329\",[167,40.39]],[\"comment/329\",[]],[\"name/330\",[173,55.053]],[\"comment/330\",[]],[\"name/331\",[2,23.135]],[\"comment/331\",[]],[\"name/332\",[169,42.06]],[\"comment/332\",[]],[\"name/333\",[164,33.851]],[\"comment/333\",[]],[\"name/334\",[165,33.851]],[\"comment/334\",[]],[\"name/335\",[166,40.39]],[\"comment/335\",[]],[\"name/336\",[167,40.39]],[\"comment/336\",[]],[\"name/337\",[174,55.053]],[\"comment/337\",[]],[\"name/338\",[175,55.053]],[\"comment/338\",[]],[\"name/339\",[2,23.135]],[\"comment/339\",[]],[\"name/340\",[164,33.851]],[\"comment/340\",[]],[\"name/341\",[165,33.851]],[\"comment/341\",[]],[\"name/342\",[66,25.609]],[\"comment/342\",[]],[\"name/343\",[176,55.053]],[\"comment/343\",[]],[\"name/344\",[2,23.135]],[\"comment/344\",[]],[\"name/345\",[66,25.609]],[\"comment/345\",[]],[\"name/346\",[164,33.851]],[\"comment/346\",[]],[\"name/347\",[165,33.851]],[\"comment/347\",[]],[\"name/348\",[177,55.053]],[\"comment/348\",[]],[\"name/349\",[2,23.135]],[\"comment/349\",[]],[\"name/350\",[66,25.609]],[\"comment/350\",[]],[\"name/351\",[164,33.851]],[\"comment/351\",[]],[\"name/352\",[165,33.851]],[\"comment/352\",[]],[\"name/353\",[178,55.053]],[\"comment/353\",[]],[\"name/354\",[2,23.135]],[\"comment/354\",[]],[\"name/355\",[66,25.609]],[\"comment/355\",[]],[\"name/356\",[164,33.851]],[\"comment/356\",[]],[\"name/357\",[165,33.851]],[\"comment/357\",[]],[\"name/358\",[179,55.053]],[\"comment/358\",[]],[\"name/359\",[2,23.135]],[\"comment/359\",[]],[\"name/360\",[66,25.609]],[\"comment/360\",[]],[\"name/361\",[164,33.851]],[\"comment/361\",[]],[\"name/362\",[165,33.851]],[\"comment/362\",[]],[\"name/363\",[15,49.945]],[\"comment/363\",[]],[\"name/364\",[2,23.135]],[\"comment/364\",[]],[\"name/365\",[66,25.609]],[\"comment/365\",[]],[\"name/366\",[164,33.851]],[\"comment/366\",[]],[\"name/367\",[165,33.851]],[\"comment/367\",[]]],\"invertedIndex\":[[\"__type\",{\"_index\":4,\"name\":{\"4\":{},\"13\":{},\"25\":{},\"34\":{},\"36\":{},\"55\":{},\"67\":{},\"69\":{},\"75\":{},\"80\":{},\"85\":{},\"90\":{},\"99\":{},\"108\":{},\"111\":{},\"113\":{},\"114\":{},\"123\":{},\"125\":{},\"128\":{},\"130\":{},\"310\":{},\"325\":{}},\"comment\":{}}],[\"_description\",{\"_index\":95,\"name\":{\"135\":{}},\"comment\":{}}],[\"_inputtype\",{\"_index\":164,\"name\":{\"296\":{},\"303\":{},\"311\":{},\"318\":{},\"326\":{},\"333\":{},\"340\":{},\"346\":{},\"351\":{},\"356\":{},\"361\":{},\"366\":{}},\"comment\":{}}],[\"_outputtype\",{\"_index\":165,\"name\":{\"297\":{},\"304\":{},\"312\":{},\"319\":{},\"327\":{},\"334\":{},\"341\":{},\"347\":{},\"352\":{},\"357\":{},\"362\":{},\"367\":{}},\"comment\":{}}],[\"activestreams\",{\"_index\":25,\"name\":{\"31\":{}},\"comment\":{}}],[\"caller\",{\"_index\":175,\"name\":{\"338\":{}},\"comment\":{}}],[\"callers\",{\"_index\":174,\"name\":{\"337\":{}},\"comment\":{}}],[\"callertypes\",{\"_index\":9,\"name\":{\"9\":{}},\"comment\":{}}],[\"cancel\",{\"_index\":78,\"name\":{\"107\":{}},\"comment\":{}}],[\"clientcaller\",{\"_index\":176,\"name\":{\"343\":{}},\"comment\":{}}],[\"clienthandler\",{\"_index\":168,\"name\":{\"300\":{}},\"comment\":{}}],[\"clienthandlerimplementation\",{\"_index\":74,\"name\":{\"103\":{}},\"comment\":{}}],[\"clientinputtransformstream\",{\"_index\":44,\"name\":{\"58\":{}},\"comment\":{}}],[\"clientmanifest\",{\"_index\":83,\"name\":{\"118\":{}},\"comment\":{}}],[\"clientoutputtransformstream\",{\"_index\":45,\"name\":{\"59\":{}},\"comment\":{}}],[\"clientstreamcaller\",{\"_index\":17,\"name\":{\"18\":{}},\"comment\":{}}],[\"code\",{\"_index\":63,\"name\":{\"91\":{},\"137\":{},\"142\":{},\"147\":{},\"153\":{},\"158\":{},\"163\":{},\"169\":{},\"174\":{},\"184\":{},\"189\":{},\"194\":{},\"199\":{},\"204\":{},\"209\":{},\"215\":{},\"221\":{},\"227\":{},\"233\":{},\"238\":{},\"243\":{},\"248\":{}},\"comment\":{}}],[\"constructor\",{\"_index\":2,\"name\":{\"2\":{},\"23\":{},\"134\":{},\"140\":{},\"145\":{},\"151\":{},\"156\":{},\"162\":{},\"167\":{},\"172\":{},\"180\":{},\"187\":{},\"192\":{},\"197\":{},\"202\":{},\"208\":{},\"214\":{},\"220\":{},\"226\":{},\"231\":{},\"236\":{},\"241\":{},\"246\":{},\"274\":{},\"295\":{},\"301\":{},\"308\":{},\"316\":{},\"323\":{},\"331\":{},\"339\":{},\"344\":{},\"349\":{},\"354\":{},\"359\":{},\"364\":{}},\"comment\":{}}],[\"container\",{\"_index\":167,\"name\":{\"299\":{},\"306\":{},\"314\":{},\"321\":{},\"329\":{},\"336\":{}},\"comment\":{}}],[\"containertype\",{\"_index\":76,\"name\":{\"105\":{}},\"comment\":{}}],[\"createrpcclient\",{\"_index\":1,\"name\":{\"1\":{}},\"comment\":{}}],[\"createrpcserver\",{\"_index\":21,\"name\":{\"22\":{}},\"comment\":{}}],[\"data\",{\"_index\":65,\"name\":{\"93\":{}},\"comment\":{}}],[\"defaulttimeoutmap\",{\"_index\":23,\"name\":{\"29\":{}},\"comment\":{}}],[\"description\",{\"_index\":96,\"name\":{\"138\":{},\"143\":{},\"148\":{},\"150\":{},\"154\":{},\"159\":{},\"161\":{},\"165\":{},\"170\":{},\"175\":{},\"177\":{},\"185\":{},\"190\":{},\"195\":{},\"200\":{},\"205\":{},\"207\":{},\"211\":{},\"213\":{},\"217\":{},\"219\":{},\"223\":{},\"225\":{},\"229\":{},\"234\":{},\"239\":{},\"244\":{},\"249\":{}},\"comment\":{}}],[\"destroy\",{\"_index\":13,\"name\":{\"14\":{},\"39\":{}},\"comment\":{}}],[\"detail\",{\"_index\":144,\"name\":{\"275\":{}},\"comment\":{}}],[\"duplexcaller\",{\"_index\":177,\"name\":{\"348\":{}},\"comment\":{}}],[\"duplexhandler\",{\"_index\":170,\"name\":{\"307\":{}},\"comment\":{}}],[\"duplexhandlerimplementation\",{\"_index\":72,\"name\":{\"101\":{}},\"comment\":{}}],[\"duplexstreamcaller\",{\"_index\":18,\"name\":{\"19\":{}},\"comment\":{}}],[\"error\",{\"_index\":61,\"name\":{\"87\":{}},\"comment\":{}}],[\"errorhandleraborted\",{\"_index\":117,\"name\":{\"235\":{}},\"comment\":{}}],[\"errormissingcaller\",{\"_index\":119,\"name\":{\"245\":{}},\"comment\":{}}],[\"errormissingheader\",{\"_index\":116,\"name\":{\"230\":{}},\"comment\":{}}],[\"errorrpc\",{\"_index\":94,\"name\":{\"133\":{}},\"comment\":{}}],[\"errorrpccallerfailed\",{\"_index\":118,\"name\":{\"240\":{}},\"comment\":{}}],[\"errorrpcconnectioninternal\",{\"_index\":115,\"name\":{\"224\":{}},\"comment\":{}}],[\"errorrpcconnectionkeepalivetimeout\",{\"_index\":114,\"name\":{\"218\":{}},\"comment\":{}}],[\"errorrpcconnectionlocal\",{\"_index\":112,\"name\":{\"206\":{}},\"comment\":{}}],[\"errorrpcconnectionpeer\",{\"_index\":113,\"name\":{\"212\":{}},\"comment\":{}}],[\"errorrpcdestroyed\",{\"_index\":97,\"name\":{\"139\":{}},\"comment\":{}}],[\"errorrpchandlerfailed\",{\"_index\":100,\"name\":{\"155\":{}},\"comment\":{}}],[\"errorrpcmessagelength\",{\"_index\":101,\"name\":{\"160\":{}},\"comment\":{}}],[\"errorrpcmethodnotimplemented\",{\"_index\":111,\"name\":{\"201\":{}},\"comment\":{}}],[\"errorrpcmissingresponse\",{\"_index\":102,\"name\":{\"166\":{}},\"comment\":{}}],[\"errorrpcoutputstreamerror\",{\"_index\":103,\"name\":{\"171\":{}},\"comment\":{}}],[\"errorrpcparse\",{\"_index\":99,\"name\":{\"149\":{}},\"comment\":{}}],[\"errorrpcremote\",{\"_index\":104,\"name\":{\"176\":{}},\"comment\":{}}],[\"errorrpcstopping\",{\"_index\":98,\"name\":{\"144\":{}},\"comment\":{}}],[\"errorrpcstreamended\",{\"_index\":108,\"name\":{\"186\":{}},\"comment\":{}}],[\"errorrpctimedout\",{\"_index\":109,\"name\":{\"191\":{}},\"comment\":{}}],[\"errors\",{\"_index\":92,\"name\":{\"131\":{}},\"comment\":{}}],[\"errorutilsundefinedbehaviour\",{\"_index\":110,\"name\":{\"196\":{}},\"comment\":{}}],[\"eventrpc\",{\"_index\":145,\"name\":{\"276\":{}},\"comment\":{}}],[\"eventrpcclient\",{\"_index\":146,\"name\":{\"277\":{}},\"comment\":{}}],[\"eventrpcclientconnect\",{\"_index\":154,\"name\":{\"285\":{}},\"comment\":{}}],[\"eventrpcclientcreate\",{\"_index\":151,\"name\":{\"282\":{}},\"comment\":{}}],[\"eventrpcclientcreated\",{\"_index\":152,\"name\":{\"283\":{}},\"comment\":{}}],[\"eventrpcclientdestroy\",{\"_index\":149,\"name\":{\"280\":{}},\"comment\":{}}],[\"eventrpcclientdestroyed\",{\"_index\":150,\"name\":{\"281\":{}},\"comment\":{}}],[\"eventrpcclienterror\",{\"_index\":153,\"name\":{\"284\":{}},\"comment\":{}}],[\"eventrpcconnection\",{\"_index\":148,\"name\":{\"279\":{}},\"comment\":{}}],[\"eventrpcconnectionerror\",{\"_index\":161,\"name\":{\"292\":{}},\"comment\":{}}],[\"eventrpcserver\",{\"_index\":147,\"name\":{\"278\":{}},\"comment\":{}}],[\"eventrpcserverconnection\",{\"_index\":155,\"name\":{\"286\":{}},\"comment\":{}}],[\"eventrpcservercreate\",{\"_index\":156,\"name\":{\"287\":{}},\"comment\":{}}],[\"eventrpcservercreated\",{\"_index\":157,\"name\":{\"288\":{}},\"comment\":{}}],[\"eventrpcserverdestroy\",{\"_index\":158,\"name\":{\"289\":{}},\"comment\":{}}],[\"eventrpcserverdestroyed\",{\"_index\":159,\"name\":{\"290\":{}},\"comment\":{}}],[\"eventrpcservererror\",{\"_index\":160,\"name\":{\"291\":{}},\"comment\":{}}],[\"events\",{\"_index\":142,\"name\":{\"272\":{}},\"comment\":{}}],[\"forward\",{\"_index\":80,\"name\":{\"115\":{}},\"comment\":{}}],[\"fromerror\",{\"_index\":27,\"name\":{\"33\":{},\"56\":{}},\"comment\":{}}],[\"fromjson\",{\"_index\":105,\"name\":{\"179\":{}},\"comment\":{}}],[\"gethandlertypes\",{\"_index\":46,\"name\":{\"60\":{}},\"comment\":{}}],[\"handle\",{\"_index\":169,\"name\":{\"302\":{},\"309\":{},\"317\":{},\"324\":{},\"332\":{}},\"comment\":{}}],[\"handler\",{\"_index\":163,\"name\":{\"294\":{}},\"comment\":{}}],[\"handleraborted\",{\"_index\":140,\"name\":{\"270\":{}},\"comment\":{}}],[\"handlerimplementation\",{\"_index\":70,\"name\":{\"98\":{}},\"comment\":{}}],[\"handlermap\",{\"_index\":22,\"name\":{\"28\":{}},\"comment\":{}}],[\"handlernotfound\",{\"_index\":126,\"name\":{\"256\":{}},\"comment\":{}}],[\"handlers\",{\"_index\":162,\"name\":{\"293\":{}},\"comment\":{}}],[\"handlertimeouttime\",{\"_index\":24,\"name\":{\"30\":{}},\"comment\":{}}],[\"handlertype\",{\"_index\":84,\"name\":{\"119\":{}},\"comment\":{}}],[\"handlestream\",{\"_index\":34,\"name\":{\"45\":{}},\"comment\":{}}],[\"id\",{\"_index\":56,\"name\":{\"73\":{},\"83\":{},\"88\":{}},\"comment\":{}}],[\"idgen\",{\"_index\":5,\"name\":{\"5\":{},\"26\":{},\"66\":{}},\"comment\":{}}],[\"internalerror\",{\"_index\":125,\"name\":{\"255\":{}},\"comment\":{}}],[\"invalidparams\",{\"_index\":124,\"name\":{\"254\":{}},\"comment\":{}}],[\"invalidrequest\",{\"_index\":122,\"name\":{\"252\":{}},\"comment\":{}}],[\"isobject\",{\"_index\":49,\"name\":{\"63\":{}},\"comment\":{}}],[\"jsonrpc\",{\"_index\":53,\"name\":{\"70\":{},\"76\":{},\"81\":{},\"86\":{}},\"comment\":{}}],[\"jsonrpcerror\",{\"_index\":62,\"name\":{\"89\":{}},\"comment\":{}}],[\"jsonrpcerrorcode\",{\"_index\":120,\"name\":{\"250\":{}},\"comment\":{}}],[\"jsonrpcmessage\",{\"_index\":69,\"name\":{\"97\":{}},\"comment\":{}}],[\"jsonrpcrequest\",{\"_index\":67,\"name\":{\"95\":{}},\"comment\":{}}],[\"jsonrpcrequestmessage\",{\"_index\":52,\"name\":{\"68\":{}},\"comment\":{}}],[\"jsonrpcrequestnotification\",{\"_index\":57,\"name\":{\"74\":{}},\"comment\":{}}],[\"jsonrpcresponse\",{\"_index\":68,\"name\":{\"96\":{}},\"comment\":{}}],[\"jsonrpcresponseerror\",{\"_index\":60,\"name\":{\"84\":{}},\"comment\":{}}],[\"jsonrpcresponseresult\",{\"_index\":58,\"name\":{\"79\":{}},\"comment\":{}}],[\"jsonvalue\",{\"_index\":86,\"name\":{\"121\":{}},\"comment\":{}}],[\"logger\",{\"_index\":6,\"name\":{\"6\":{},\"27\":{}},\"comment\":{}}],[\"mapcallers\",{\"_index\":85,\"name\":{\"120\":{}},\"comment\":{}}],[\"message\",{\"_index\":64,\"name\":{\"92\":{},\"178\":{}},\"comment\":{}}],[\"meta\",{\"_index\":79,\"name\":{\"109\":{}},\"comment\":{}}],[\"metadata\",{\"_index\":106,\"name\":{\"181\":{}},\"comment\":{}}],[\"method\",{\"_index\":54,\"name\":{\"71\":{},\"77\":{}},\"comment\":{}}],[\"methodnotfound\",{\"_index\":123,\"name\":{\"253\":{}},\"comment\":{}}],[\"methods\",{\"_index\":14,\"name\":{\"15\":{}},\"comment\":{}}],[\"methodsproxy\",{\"_index\":12,\"name\":{\"12\":{}},\"comment\":{}}],[\"middlewarefactory\",{\"_index\":8,\"name\":{\"8\":{},\"37\":{},\"112\":{}},\"comment\":{}}],[\"missingcaller\",{\"_index\":141,\"name\":{\"271\":{}},\"comment\":{}}],[\"missingheader\",{\"_index\":139,\"name\":{\"269\":{}},\"comment\":{}}],[\"never\",{\"_index\":93,\"name\":{\"132\":{}},\"comment\":{}}],[\"ontimeoutcallback\",{\"_index\":3,\"name\":{\"3\":{},\"24\":{}},\"comment\":{}}],[\"p\",{\"_index\":89,\"name\":{\"126\":{}},\"comment\":{}}],[\"params\",{\"_index\":55,\"name\":{\"72\":{},\"78\":{}},\"comment\":{}}],[\"parseerror\",{\"_index\":121,\"name\":{\"251\":{}},\"comment\":{}}],[\"parseheadstream\",{\"_index\":47,\"name\":{\"61\":{}},\"comment\":{}}],[\"parsejsonrpcmessage\",{\"_index\":42,\"name\":{\"53\":{}},\"comment\":{}}],[\"parsejsonrpcrequest\",{\"_index\":36,\"name\":{\"47\":{}},\"comment\":{}}],[\"parsejsonrpcrequestmessage\",{\"_index\":37,\"name\":{\"48\":{}},\"comment\":{}}],[\"parsejsonrpcrequestnotification\",{\"_index\":38,\"name\":{\"49\":{}},\"comment\":{}}],[\"parsejsonrpcresponse\",{\"_index\":41,\"name\":{\"52\":{}},\"comment\":{}}],[\"parsejsonrpcresponseerror\",{\"_index\":40,\"name\":{\"51\":{}},\"comment\":{}}],[\"parsejsonrpcresponseresult\",{\"_index\":39,\"name\":{\"50\":{}},\"comment\":{}}],[\"pojo\",{\"_index\":87,\"name\":{\"122\":{}},\"comment\":{}}],[\"promise\",{\"_index\":48,\"name\":{\"62\":{}},\"comment\":{}}],[\"promisedeconstructed\",{\"_index\":88,\"name\":{\"124\":{}},\"comment\":{}}],[\"rawcaller\",{\"_index\":178,\"name\":{\"353\":{}},\"comment\":{}}],[\"rawhandler\",{\"_index\":171,\"name\":{\"315\":{}},\"comment\":{}}],[\"rawhandlerimplementation\",{\"_index\":71,\"name\":{\"100\":{}},\"comment\":{}}],[\"rawstreamcaller\",{\"_index\":19,\"name\":{\"20\":{}},\"comment\":{}}],[\"registerclientstreamhandler\",{\"_index\":33,\"name\":{\"44\":{}},\"comment\":{}}],[\"registerduplexstreamhandler\",{\"_index\":30,\"name\":{\"41\":{}},\"comment\":{}}],[\"registerontimeoutcallback\",{\"_index\":10,\"name\":{\"10\":{},\"38\":{}},\"comment\":{}}],[\"registerrawstreamhandler\",{\"_index\":29,\"name\":{\"40\":{}},\"comment\":{}}],[\"registerserverstreamhandler\",{\"_index\":32,\"name\":{\"43\":{}},\"comment\":{}}],[\"registerunaryhandler\",{\"_index\":31,\"name\":{\"42\":{}},\"comment\":{}}],[\"rejectp\",{\"_index\":91,\"name\":{\"129\":{}},\"comment\":{}}],[\"replacer\",{\"_index\":28,\"name\":{\"35\":{},\"54\":{}},\"comment\":{}}],[\"resolvep\",{\"_index\":90,\"name\":{\"127\":{}},\"comment\":{}}],[\"result\",{\"_index\":59,\"name\":{\"82\":{}},\"comment\":{}}],[\"reverse\",{\"_index\":81,\"name\":{\"116\":{}},\"comment\":{}}],[\"rpcclient\",{\"_index\":0,\"name\":{\"0\":{}},\"comment\":{}}],[\"rpcconnectioninternal\",{\"_index\":138,\"name\":{\"268\":{}},\"comment\":{}}],[\"rpcconnectionkeepalivetimeout\",{\"_index\":137,\"name\":{\"267\":{}},\"comment\":{}}],[\"rpcconnectionlocal\",{\"_index\":135,\"name\":{\"265\":{}},\"comment\":{}}],[\"rpcconnectionpeer\",{\"_index\":136,\"name\":{\"266\":{}},\"comment\":{}}],[\"rpcdestroyed\",{\"_index\":128,\"name\":{\"258\":{}},\"comment\":{}}],[\"rpcerrorevent\",{\"_index\":143,\"name\":{\"273\":{}},\"comment\":{}}],[\"rpcmessagelength\",{\"_index\":129,\"name\":{\"259\":{}},\"comment\":{}}],[\"rpcmissingresponse\",{\"_index\":130,\"name\":{\"260\":{}},\"comment\":{}}],[\"rpcoutputstreamerror\",{\"_index\":131,\"name\":{\"261\":{}},\"comment\":{}}],[\"rpcremote\",{\"_index\":132,\"name\":{\"262\":{}},\"comment\":{}}],[\"rpcserver\",{\"_index\":20,\"name\":{\"21\":{}},\"comment\":{}}],[\"rpcstopping\",{\"_index\":127,\"name\":{\"257\":{}},\"comment\":{}}],[\"rpcstream\",{\"_index\":77,\"name\":{\"106\":{}},\"comment\":{}}],[\"rpcstreamended\",{\"_index\":133,\"name\":{\"263\":{}},\"comment\":{}}],[\"rpctimedout\",{\"_index\":134,\"name\":{\"264\":{}},\"comment\":{}}],[\"sensitive\",{\"_index\":26,\"name\":{\"32\":{}},\"comment\":{}}],[\"servercaller\",{\"_index\":179,\"name\":{\"358\":{}},\"comment\":{}}],[\"serverhandler\",{\"_index\":172,\"name\":{\"322\":{}},\"comment\":{}}],[\"serverhandlerimplementation\",{\"_index\":73,\"name\":{\"102\":{}},\"comment\":{}}],[\"servermanifest\",{\"_index\":82,\"name\":{\"117\":{}},\"comment\":{}}],[\"serverstreamcaller\",{\"_index\":16,\"name\":{\"17\":{}},\"comment\":{}}],[\"sleep\",{\"_index\":50,\"name\":{\"64\":{}},\"comment\":{}}],[\"streamfactory\",{\"_index\":7,\"name\":{\"7\":{},\"110\":{}},\"comment\":{}}],[\"streamkeepalivetimeouttime\",{\"_index\":11,\"name\":{\"11\":{}},\"comment\":{}}],[\"timeout\",{\"_index\":166,\"name\":{\"298\":{},\"305\":{},\"313\":{},\"320\":{},\"328\":{},\"335\":{}},\"comment\":{}}],[\"toerror\",{\"_index\":43,\"name\":{\"57\":{}},\"comment\":{}}],[\"tojson\",{\"_index\":107,\"name\":{\"182\":{}},\"comment\":{}}],[\"type\",{\"_index\":66,\"name\":{\"94\":{},\"136\":{},\"141\":{},\"146\":{},\"152\":{},\"157\":{},\"164\":{},\"168\":{},\"173\":{},\"183\":{},\"188\":{},\"193\":{},\"198\":{},\"203\":{},\"210\":{},\"216\":{},\"222\":{},\"228\":{},\"232\":{},\"237\":{},\"242\":{},\"247\":{},\"342\":{},\"345\":{},\"350\":{},\"355\":{},\"360\":{},\"365\":{}},\"comment\":{}}],[\"types\",{\"_index\":51,\"name\":{\"65\":{}},\"comment\":{}}],[\"unarycaller\",{\"_index\":15,\"name\":{\"16\":{},\"363\":{}},\"comment\":{}}],[\"unaryhandler\",{\"_index\":173,\"name\":{\"330\":{}},\"comment\":{}}],[\"unaryhandlerimplementation\",{\"_index\":75,\"name\":{\"104\":{}},\"comment\":{}}],[\"utils\",{\"_index\":35,\"name\":{\"46\":{}},\"comment\":{}}]],\"pipeline\":[]}}"); \ No newline at end of file diff --git a/docs/assets/style.css b/docs/assets/style.css new file mode 100644 index 0000000..fcb3522 --- /dev/null +++ b/docs/assets/style.css @@ -0,0 +1,1276 @@ +:root { + /* Light */ + --light-color-background: #f2f4f8; + --light-color-background-secondary: #eff0f1; + --light-color-warning-text: #222; + --light-color-background-warning: #e6e600; + --light-color-icon-background: var(--light-color-background); + --light-color-accent: #c5c7c9; + --light-color-text: #222; + --light-color-text-aside: #707070; + --light-color-link: #4da6ff; + --light-color-ts: #db1373; + --light-color-ts-interface: #139d2c; + --light-color-ts-enum: #9c891a; + --light-color-ts-class: #2484e5; + --light-color-ts-function: #572be7; + --light-color-ts-namespace: #b111c9; + --light-color-ts-private: #707070; + --light-color-ts-variable: #4d68ff; + --light-external-icon: url("data:image/svg+xml;utf8,"); + --light-color-scheme: light; + + /* Dark */ + --dark-color-background: #2b2e33; + --dark-color-background-secondary: #1e2024; + --dark-color-background-warning: #bebe00; + --dark-color-warning-text: #222; + --dark-color-icon-background: var(--dark-color-background-secondary); + --dark-color-accent: #9096a2; + --dark-color-text: #f5f5f5; + --dark-color-text-aside: #dddddd; + --dark-color-link: #00aff4; + --dark-color-ts: #ff6492; + --dark-color-ts-interface: #6cff87; + --dark-color-ts-enum: #f4d93e; + --dark-color-ts-class: #61b0ff; + --dark-color-ts-function: #9772ff; + --dark-color-ts-namespace: #e14dff; + --dark-color-ts-private: #e2e2e2; + --dark-color-ts-variable: #4d68ff; + --dark-external-icon: url("data:image/svg+xml;utf8,"); + --dark-color-scheme: dark; +} + +@media (prefers-color-scheme: light) { + :root { + --color-background: var(--light-color-background); + --color-background-secondary: var(--light-color-background-secondary); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); + --color-icon-background: var(--light-color-icon-background); + --color-accent: var(--light-color-accent); + --color-text: var(--light-color-text); + --color-text-aside: var(--light-color-text-aside); + --color-link: var(--light-color-link); + --color-ts: var(--light-color-ts); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-class: var(--light-color-ts-class); + --color-ts-function: var(--light-color-ts-function); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-private: var(--light-color-ts-private); + --color-ts-variable: var(--light-color-ts-variable); + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); + } +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--dark-color-background); + --color-background-secondary: var(--dark-color-background-secondary); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); + --color-icon-background: var(--dark-color-icon-background); + --color-accent: var(--dark-color-accent); + --color-text: var(--dark-color-text); + --color-text-aside: var(--dark-color-text-aside); + --color-link: var(--dark-color-link); + --color-ts: var(--dark-color-ts); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-private: var(--dark-color-ts-private); + --color-ts-variable: var(--dark-color-ts-variable); + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); + } +} + +html { + color-scheme: var(--color-scheme); +} + +body { + margin: 0; +} + +:root[data-theme="light"] { + --color-background: var(--light-color-background); + --color-background-secondary: var(--light-color-background-secondary); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); + --color-icon-background: var(--light-color-icon-background); + --color-accent: var(--light-color-accent); + --color-text: var(--light-color-text); + --color-text-aside: var(--light-color-text-aside); + --color-link: var(--light-color-link); + --color-ts: var(--light-color-ts); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-class: var(--light-color-ts-class); + --color-ts-function: var(--light-color-ts-function); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-private: var(--light-color-ts-private); + --color-ts-variable: var(--light-color-ts-variable); + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); +} + +:root[data-theme="dark"] { + --color-background: var(--dark-color-background); + --color-background-secondary: var(--dark-color-background-secondary); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); + --color-icon-background: var(--dark-color-icon-background); + --color-accent: var(--dark-color-accent); + --color-text: var(--dark-color-text); + --color-text-aside: var(--dark-color-text-aside); + --color-link: var(--dark-color-link); + --color-ts: var(--dark-color-ts); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-private: var(--dark-color-ts-private); + --color-ts-variable: var(--dark-color-ts-variable); + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); +} + +.always-visible, +.always-visible .tsd-signatures { + display: inherit !important; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + line-height: 1.2; +} + +h1 { + font-size: 1.875rem; + margin: 0.67rem 0; +} + +h2 { + font-size: 1.5rem; + margin: 0.83rem 0; +} + +h3 { + font-size: 1.25rem; + margin: 1rem 0; +} + +h4 { + font-size: 1.05rem; + margin: 1.33rem 0; +} + +h5 { + font-size: 1rem; + margin: 1.5rem 0; +} + +h6 { + font-size: 0.875rem; + margin: 2.33rem 0; +} + +.uppercase { + text-transform: uppercase; +} + +pre { + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} + +dl, +menu, +ol, +ul { + margin: 1em 0; +} + +dd { + margin: 0 0 0 40px; +} + +.container { + max-width: 1600px; + padding: 0 2rem; +} + +@media (min-width: 640px) { + .container { + padding: 0 4rem; + } +} +@media (min-width: 1200px) { + .container { + padding: 0 8rem; + } +} +@media (min-width: 1600px) { + .container { + padding: 0 12rem; + } +} + +/* Footer */ +.tsd-generator { + border-top: 1px solid var(--color-accent); + padding-top: 1rem; + padding-bottom: 1rem; + max-height: 3.5rem; +} + +.tsd-generator > p { + margin-top: 0; + margin-bottom: 0; + padding: 0 1rem; +} + +.container-main { + display: flex; + justify-content: space-between; + position: relative; + margin: 0 auto; +} + +.col-4, +.col-8 { + box-sizing: border-box; + float: left; + padding: 2rem 1rem; +} + +.col-4 { + flex: 0 0 25%; +} +.col-8 { + flex: 1 0; + flex-wrap: wrap; + padding-left: 0; +} + +@keyframes fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} +@keyframes fade-out { + from { + opacity: 1; + visibility: visible; + } + to { + opacity: 0; + } +} +@keyframes fade-in-delayed { + 0% { + opacity: 0; + } + 33% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +@keyframes fade-out-delayed { + 0% { + opacity: 1; + visibility: visible; + } + 66% { + opacity: 0; + } + 100% { + opacity: 0; + } +} +@keyframes shift-to-left { + from { + transform: translate(0, 0); + } + to { + transform: translate(-25%, 0); + } +} +@keyframes unshift-to-left { + from { + transform: translate(-25%, 0); + } + to { + transform: translate(0, 0); + } +} +@keyframes pop-in-from-right { + from { + transform: translate(100%, 0); + } + to { + transform: translate(0, 0); + } +} +@keyframes pop-out-to-right { + from { + transform: translate(0, 0); + visibility: visible; + } + to { + transform: translate(100%, 0); + } +} +body { + background: var(--color-background); + font-family: "Segoe UI", sans-serif; + font-size: 16px; + color: var(--color-text); +} + +a { + color: var(--color-link); + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +a.external[target="_blank"] { + background-image: var(--external-icon); + background-position: top 3px right; + background-repeat: no-repeat; + padding-right: 13px; +} + +code, +pre { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 0.2em; + margin: 0; + font-size: 0.875rem; + border-radius: 0.8em; +} + +pre { + padding: 10px; + border: 0.1em solid var(--color-accent); +} +pre code { + padding: 0; + font-size: 100%; +} + +blockquote { + margin: 1em 0; + padding-left: 1em; + border-left: 4px solid gray; +} + +.tsd-typography { + line-height: 1.333em; +} +.tsd-typography ul { + list-style: square; + padding: 0 0 0 20px; + margin: 0; +} +.tsd-typography h4, +.tsd-typography .tsd-index-panel h3, +.tsd-index-panel .tsd-typography h3, +.tsd-typography h5, +.tsd-typography h6 { + font-size: 1em; + margin: 0; +} +.tsd-typography h5, +.tsd-typography h6 { + font-weight: normal; +} +.tsd-typography p, +.tsd-typography ul, +.tsd-typography ol { + margin: 1em 0; +} + +@media (max-width: 1024px) { + html .col-content { + float: none; + max-width: 100%; + width: 100%; + padding-top: 3rem; + } + html .col-menu { + position: fixed !important; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + z-index: 1024; + top: 0 !important; + bottom: 0 !important; + left: auto !important; + right: 0 !important; + padding: 1.5rem 1.5rem 0 0; + max-width: 25rem; + visibility: hidden; + background-color: var(--color-background); + transform: translate(100%, 0); + } + html .col-menu > *:last-child { + padding-bottom: 20px; + } + html .overlay { + content: ""; + display: block; + position: fixed; + z-index: 1023; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.75); + visibility: hidden; + } + + .to-has-menu .overlay { + animation: fade-in 0.4s; + } + + .to-has-menu :is(header, footer, .col-content) { + animation: shift-to-left 0.4s; + } + + .to-has-menu .col-menu { + animation: pop-in-from-right 0.4s; + } + + .from-has-menu .overlay { + animation: fade-out 0.4s; + } + + .from-has-menu :is(header, footer, .col-content) { + animation: unshift-to-left 0.4s; + } + + .from-has-menu .col-menu { + animation: pop-out-to-right 0.4s; + } + + .has-menu body { + overflow: hidden; + } + .has-menu .overlay { + visibility: visible; + } + .has-menu :is(header, footer, .col-content) { + transform: translate(-25%, 0); + } + .has-menu .col-menu { + visibility: visible; + transform: translate(0, 0); + display: flex; + flex-direction: column; + gap: 1.5rem; + max-height: 100vh; + padding: 1rem 2rem; + } + .has-menu .tsd-navigation { + max-height: 100%; + } +} + +.tsd-breadcrumb { + margin: 0; + padding: 0; + color: var(--color-text-aside); +} +.tsd-breadcrumb a { + color: var(--color-text-aside); + text-decoration: none; +} +.tsd-breadcrumb a:hover { + text-decoration: underline; +} +.tsd-breadcrumb li { + display: inline; +} +.tsd-breadcrumb li:after { + content: " / "; +} + +.tsd-comment-tags { + display: flex; + flex-direction: column; +} +dl.tsd-comment-tag-group { + display: flex; + align-items: center; + overflow: hidden; + margin: 0.5em 0; +} +dl.tsd-comment-tag-group dt { + display: flex; + margin-right: 0.5em; + font-size: 0.875em; + font-weight: normal; +} +dl.tsd-comment-tag-group dd { + margin: 0; +} +code.tsd-tag { + padding: 0.25em 0.4em; + border: 0.1em solid var(--color-accent); + margin-right: 0.25em; + font-size: 70%; +} +h1 code.tsd-tag:first-of-type { + margin-left: 0.25em; +} + +dl.tsd-comment-tag-group dd:before, +dl.tsd-comment-tag-group dd:after { + content: " "; +} +dl.tsd-comment-tag-group dd pre, +dl.tsd-comment-tag-group dd:after { + clear: both; +} +dl.tsd-comment-tag-group p { + margin: 0; +} + +.tsd-panel.tsd-comment .lead { + font-size: 1.1em; + line-height: 1.333em; + margin-bottom: 2em; +} +.tsd-panel.tsd-comment .lead:last-child { + margin-bottom: 0; +} + +.tsd-filter-visibility h4 { + font-size: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.5rem; + margin: 0; +} +.tsd-filter-item:not(:last-child) { + margin-bottom: 0.5rem; +} +.tsd-filter-input { + display: flex; + width: fit-content; + align-items: center; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + cursor: pointer; +} +.tsd-filter-input input[type="checkbox"] { + cursor: pointer; + position: absolute; + width: 1.5em; + height: 1.5em; + opacity: 0; +} +.tsd-filter-input input[type="checkbox"]:disabled { + pointer-events: none; +} +.tsd-filter-input svg { + cursor: pointer; + width: 1.5em; + height: 1.5em; + margin-right: 0.5em; + border-radius: 0.33em; + /* Leaving this at full opacity breaks event listeners on Firefox. + Don't remove unless you know what you're doing. */ + opacity: 0.99; +} +.tsd-filter-input input[type="checkbox"]:focus + svg { + transform: scale(0.95); +} +.tsd-filter-input input[type="checkbox"]:focus:not(:focus-visible) + svg { + transform: scale(1); +} +.tsd-checkbox-background { + fill: var(--color-accent); +} +input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark { + stroke: var(--color-text); +} +.tsd-filter-input input:disabled ~ svg > .tsd-checkbox-background { + fill: var(--color-background); + stroke: var(--color-accent); + stroke-width: 0.25rem; +} +.tsd-filter-input input:disabled ~ svg > .tsd-checkbox-checkmark { + stroke: var(--color-accent); +} + +.tsd-theme-toggle { + padding-top: 0.75rem; +} +.tsd-theme-toggle > h4 { + display: inline; + vertical-align: middle; + margin-right: 0.75rem; +} + +.tsd-hierarchy { + list-style: square; + margin: 0; +} +.tsd-hierarchy .target { + font-weight: bold; +} + +.tsd-panel-group.tsd-index-group { + margin-bottom: 0; +} +.tsd-index-panel .tsd-index-list { + list-style: none; + line-height: 1.333em; + margin: 0; + padding: 0.25rem 0 0 0; + overflow: hidden; + display: grid; + grid-template-columns: repeat(3, 1fr); + column-gap: 1rem; + grid-template-rows: auto; +} +@media (max-width: 1024px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(2, 1fr); + } +} +@media (max-width: 768px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(1, 1fr); + } +} +.tsd-index-panel .tsd-index-list li { + -webkit-page-break-inside: avoid; + -moz-page-break-inside: avoid; + -ms-page-break-inside: avoid; + -o-page-break-inside: avoid; + page-break-inside: avoid; +} +.tsd-index-panel a, +.tsd-index-panel a.tsd-parent-kind-module { + color: var(--color-ts); +} +.tsd-index-panel a.tsd-parent-kind-interface { + color: var(--color-ts-interface); +} +.tsd-index-panel a.tsd-parent-kind-enum { + color: var(--color-ts-enum); +} +.tsd-index-panel a.tsd-parent-kind-class { + color: var(--color-ts-class); +} +.tsd-index-panel a.tsd-kind-module { + color: var(--color-ts-namespace); +} +.tsd-index-panel a.tsd-kind-interface { + color: var(--color-ts-interface); +} +.tsd-index-panel a.tsd-kind-enum { + color: var(--color-ts-enum); +} +.tsd-index-panel a.tsd-kind-class { + color: var(--color-ts-class); +} +.tsd-index-panel a.tsd-kind-function { + color: var(--color-ts-function); +} +.tsd-index-panel a.tsd-kind-namespace { + color: var(--color-ts-namespace); +} +.tsd-index-panel a.tsd-kind-variable { + color: var(--color-ts-variable); +} +.tsd-index-panel a.tsd-is-private { + color: var(--color-ts-private); +} + +.tsd-flag { + display: inline-block; + padding: 0.25em 0.4em; + border-radius: 4px; + text-indent: 0; + font-size: 75%; + line-height: 1; + font-weight: normal; +} + +.tsd-anchor { + position: absolute; + top: -100px; +} + +.tsd-member { + position: relative; +} +.tsd-member .tsd-anchor + h3 { + display: flex; + align-items: center; + margin-top: 0; + margin-bottom: 0; + border-bottom: none; +} +.tsd-member [data-tsd-kind] { + color: var(--color-ts); +} +.tsd-member [data-tsd-kind="Interface"] { + color: var(--color-ts-interface); +} +.tsd-member [data-tsd-kind="Enum"] { + color: var(--color-ts-enum); +} +.tsd-member [data-tsd-kind="Class"] { + color: var(--color-ts-class); +} +.tsd-member [data-tsd-kind="Private"] { + color: var(--color-ts-private); +} + +.tsd-navigation a { + display: block; + margin: 0.4rem 0; + border-left: 2px solid transparent; + color: var(--color-text); + text-decoration: none; + transition: border-left-color 0.1s; +} +.tsd-navigation a:hover { + text-decoration: underline; +} +.tsd-navigation ul { + margin: 0; + padding: 0; + list-style: none; +} +.tsd-navigation li { + padding: 0; +} + +.tsd-navigation.primary .tsd-accordion-details > ul { + margin-top: 0.75rem; +} +.tsd-navigation.primary a { + padding: 0.75rem 0.5rem; + margin: 0; +} +.tsd-navigation.primary ul li a { + margin-left: 0.5rem; +} +.tsd-navigation.primary ul li li a { + margin-left: 1.5rem; +} +.tsd-navigation.primary ul li li li a { + margin-left: 2.5rem; +} +.tsd-navigation.primary ul li li li li a { + margin-left: 3.5rem; +} +.tsd-navigation.primary ul li li li li li a { + margin-left: 4.5rem; +} +.tsd-navigation.primary ul li li li li li li a { + margin-left: 5.5rem; +} +.tsd-navigation.primary li.current > a { + border-left: 0.15rem var(--color-text) solid; +} +.tsd-navigation.primary li.selected > a { + font-weight: bold; + border-left: 0.2rem var(--color-text) solid; +} +.tsd-navigation.primary ul li a:hover { + border-left: 0.2rem var(--color-text-aside) solid; +} +.tsd-navigation.primary li.globals + li > span, +.tsd-navigation.primary li.globals + li > a { + padding-top: 20px; +} + +.tsd-navigation.secondary.tsd-navigation--toolbar-hide { + max-height: calc(100vh - 1rem); + top: 0.5rem; +} +.tsd-navigation.secondary > ul { + display: inline; + padding-right: 0.5rem; + transition: opacity 0.2s; +} +.tsd-navigation.secondary ul li a { + padding-left: 0; +} +.tsd-navigation.secondary ul li li a { + padding-left: 1.1rem; +} +.tsd-navigation.secondary ul li li li a { + padding-left: 2.2rem; +} +.tsd-navigation.secondary ul li li li li a { + padding-left: 3.3rem; +} +.tsd-navigation.secondary ul li li li li li a { + padding-left: 4.4rem; +} +.tsd-navigation.secondary ul li li li li li li a { + padding-left: 5.5rem; +} + +#tsd-sidebar-links a { + margin-top: 0; + margin-bottom: 0.5rem; + line-height: 1.25rem; +} +#tsd-sidebar-links a:last-of-type { + margin-bottom: 0; +} + +a.tsd-index-link { + margin: 0.25rem 0; + font-size: 1rem; + line-height: 1.25rem; + display: inline-flex; + align-items: center; +} +.tsd-accordion-summary > h1, +.tsd-accordion-summary > h2, +.tsd-accordion-summary > h3, +.tsd-accordion-summary > h4, +.tsd-accordion-summary > h5 { + display: inline-flex; + align-items: center; + vertical-align: middle; + margin-bottom: 0; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; +} +.tsd-accordion-summary { + display: block; + cursor: pointer; +} +.tsd-accordion-summary > * { + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; +} +.tsd-accordion-summary::-webkit-details-marker { + display: none; +} +.tsd-index-accordion .tsd-accordion-summary svg { + margin-right: 0.25rem; +} +.tsd-index-content > :not(:first-child) { + margin-top: 0.75rem; +} +.tsd-index-heading { + margin-top: 1.5rem; + margin-bottom: 0.75rem; +} + +.tsd-kind-icon { + margin-right: 0.5rem; + width: 1.25rem; + height: 1.25rem; + min-width: 1.25rem; + min-height: 1.25rem; +} +.tsd-kind-icon path { + transform-origin: center; + transform: scale(1.1); +} +.tsd-signature > .tsd-kind-icon { + margin-right: 0.8rem; +} + +@media (min-width: 1025px) { + .col-content { + margin: 2rem auto; + } + + .menu-sticky-wrap { + position: sticky; + height: calc(100vh - 2rem); + top: 4rem; + right: 0; + padding: 0 1.5rem; + padding-top: 1rem; + margin-top: 3rem; + transition: 0.3s ease-in-out; + transition-property: top, padding-top, padding, height; + overflow-y: auto; + } + .col-menu { + border-left: 1px solid var(--color-accent); + } + .col-menu--hide { + top: 1rem; + } + .col-menu .tsd-navigation:not(:last-child) { + padding-bottom: 1.75rem; + } +} + +.tsd-panel { + margin-bottom: 2.5rem; +} +.tsd-panel.tsd-member { + margin-bottom: 4rem; +} +.tsd-panel:empty { + display: none; +} +.tsd-panel > h1, +.tsd-panel > h2, +.tsd-panel > h3 { + margin: 1.5rem -1.5rem 0.75rem -1.5rem; + padding: 0 1.5rem 0.75rem 1.5rem; +} +.tsd-panel > h1.tsd-before-signature, +.tsd-panel > h2.tsd-before-signature, +.tsd-panel > h3.tsd-before-signature { + margin-bottom: 0; + border-bottom: none; +} + +.tsd-panel-group { + margin: 4rem 0; +} +.tsd-panel-group.tsd-index-group { + margin: 2rem 0; +} +.tsd-panel-group.tsd-index-group details { + margin: 2rem 0; +} + +#tsd-search { + transition: background-color 0.2s; +} +#tsd-search .title { + position: relative; + z-index: 2; +} +#tsd-search .field { + position: absolute; + left: 0; + top: 0; + right: 2.5rem; + height: 100%; +} +#tsd-search .field input { + box-sizing: border-box; + position: relative; + top: -50px; + z-index: 1; + width: 100%; + padding: 0 10px; + opacity: 0; + outline: 0; + border: 0; + background: transparent; + color: var(--color-text); +} +#tsd-search .field label { + position: absolute; + overflow: hidden; + right: -40px; +} +#tsd-search .field input, +#tsd-search .title, +#tsd-toolbar-links a { + transition: opacity 0.2s; +} +#tsd-search .results { + position: absolute; + visibility: hidden; + top: 40px; + width: 100%; + margin: 0; + padding: 0; + list-style: none; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); +} +#tsd-search .results li { + padding: 0 10px; + background-color: var(--color-background); +} +#tsd-search .results li:nth-child(even) { + background-color: var(--color-background-secondary); +} +#tsd-search .results li.state { + display: none; +} +#tsd-search .results li.current, +#tsd-search .results li:hover { + background-color: var(--color-accent); +} +#tsd-search .results a { + display: block; +} +#tsd-search .results a:before { + top: 10px; +} +#tsd-search .results span.parent { + color: var(--color-text-aside); + font-weight: normal; +} +#tsd-search.has-focus { + background-color: var(--color-accent); +} +#tsd-search.has-focus .field input { + top: 0; + opacity: 1; +} +#tsd-search.has-focus .title, +#tsd-search.has-focus #tsd-toolbar-links a { + z-index: 0; + opacity: 0; +} +#tsd-search.has-focus .results { + visibility: visible; +} +#tsd-search.loading .results li.state.loading { + display: block; +} +#tsd-search.failure .results li.state.failure { + display: block; +} + +#tsd-toolbar-links { + position: absolute; + top: 0; + right: 2rem; + height: 100%; + display: flex; + align-items: center; + justify-content: flex-end; +} +#tsd-toolbar-links a { + margin-left: 1.5rem; +} +#tsd-toolbar-links a:hover { + text-decoration: underline; +} + +.tsd-signature { + margin: 0 0 1rem 0; + padding: 1rem 0.5rem; + border: 1px solid var(--color-accent); + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + font-size: 14px; + overflow-x: auto; +} + +.tsd-signature-symbol { + color: var(--color-text-aside); + font-weight: normal; +} + +.tsd-signature-type { + font-style: italic; + font-weight: normal; +} + +.tsd-signatures { + padding: 0; + margin: 0 0 1em 0; + list-style-type: none; +} +.tsd-signatures .tsd-signature { + margin: 0; + border-color: var(--color-accent); + border-width: 1px 0; + transition: background-color 0.1s; +} +.tsd-description .tsd-signatures .tsd-signature { + border-width: 1px; +} + +ul.tsd-parameter-list, +ul.tsd-type-parameter-list { + list-style: square; + margin: 0; + padding-left: 20px; +} +ul.tsd-parameter-list > li.tsd-parameter-signature, +ul.tsd-type-parameter-list > li.tsd-parameter-signature { + list-style: none; + margin-left: -20px; +} +ul.tsd-parameter-list h5, +ul.tsd-type-parameter-list h5 { + font-size: 16px; + margin: 1em 0 0.5em 0; +} +.tsd-sources { + margin-top: 1rem; + font-size: 0.875em; +} +.tsd-sources a { + color: var(--color-text-aside); + text-decoration: underline; +} +.tsd-sources ul { + list-style: none; + padding: 0; +} + +.tsd-page-toolbar { + position: fixed; + z-index: 1; + top: 0; + left: 0; + width: 100%; + color: var(--color-text); + background: var(--color-background-secondary); + border-bottom: 1px var(--color-accent) solid; + transition: transform 0.3s ease-in-out; +} +.tsd-page-toolbar a { + color: var(--color-text); + text-decoration: none; +} +.tsd-page-toolbar a.title { + font-weight: bold; +} +.tsd-page-toolbar a.title:hover { + text-decoration: underline; +} +.tsd-page-toolbar .tsd-toolbar-contents { + display: flex; + justify-content: space-between; + height: 2.5rem; + margin: 0 auto; +} +.tsd-page-toolbar .table-cell { + position: relative; + white-space: nowrap; + line-height: 40px; +} +.tsd-page-toolbar .table-cell:first-child { + width: 100%; +} +.tsd-page-toolbar .tsd-toolbar-icon { + box-sizing: border-box; + line-height: 0; + padding: 12px 0; +} + +.tsd-page-toolbar--hide { + transform: translateY(-100%); +} + +.tsd-widget { + display: inline-block; + overflow: hidden; + opacity: 0.8; + height: 40px; + transition: opacity 0.1s, background-color 0.2s; + vertical-align: bottom; + cursor: pointer; +} +.tsd-widget:hover { + opacity: 0.9; +} +.tsd-widget.active { + opacity: 1; + background-color: var(--color-accent); +} +.tsd-widget.no-caption { + width: 40px; +} +.tsd-widget.no-caption:before { + margin: 0; +} + +.tsd-widget.options, +.tsd-widget.menu { + display: none; +} +@media (max-width: 1024px) { + .tsd-widget.options, + .tsd-widget.menu { + display: inline-block; + } +} +input[type="checkbox"] + .tsd-widget:before { + background-position: -120px 0; +} +input[type="checkbox"]:checked + .tsd-widget:before { + background-position: -160px 0; +} + +img { + max-width: 100%; +} + +.tsd-anchor-icon { + display: inline-flex; + align-items: center; + margin-left: 0.5rem; + vertical-align: middle; + color: var(--color-text); +} + +.tsd-anchor-icon svg { + width: 1em; + height: 1em; + visibility: hidden; +} + +.tsd-anchor-link:hover > .tsd-anchor-icon svg { + visibility: visible; +} + +.deprecated { + text-decoration: line-through; +} + +.warning { + padding: 1rem; + color: var(--color-warning-text); + background: var(--color-background-warning); +} + +* { + scrollbar-width: thin; + scrollbar-color: var(--color-accent) var(--color-icon-background); +} + +*::-webkit-scrollbar { + width: 0.75rem; +} + +*::-webkit-scrollbar-track { + background: var(--color-icon-background); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--color-accent); + border-radius: 999rem; + border: 0.25rem solid var(--color-icon-background); +} diff --git a/docs/classes/RPCClient.html b/docs/classes/RPCClient.html new file mode 100644 index 0000000..abd5694 --- /dev/null +++ b/docs/classes/RPCClient.html @@ -0,0 +1,634 @@ +RPCClient | js-rpc +
+
+
+ +

Class RPCClient<M>

+
+

You must provide an error handler addEventListener('error'). +Otherwise, errors will just be ignored.

+

Events:

+ +
+
+

Type Parameters

+
+
+

Hierarchy

+
    +
  • CreateDestroy +
      +
    • RPCClient
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
[initLock]: RWLockWriter
+
+ +
callerTypes: Record<string, HandlerType>
+
+ +
idGen: IdGen
+
+ +
logger: Logger
+
+ +
methodsProxy: {} = ...
+
+

Type declaration

+
    +
    + +
    middlewareFactory: MiddlewareFactory<Uint8Array, JSONRPCRequest<JSONValue>, JSONRPCResponse<JSONValue>, Uint8Array>
    +
    + +
    onTimeoutCallback?: (() => void)
    +
    +

    Type declaration

    +
      +
    • +
        +
      • (): void
      • +
      • +

        Returns void

    +
    + +
    streamFactory: StreamFactory
    +
    + +
    streamKeepAliveTimeoutTime: number
    +
    +

    Accessors

    +
    + +
      +
    • get [destroyed](): boolean
    • +
    • +

      Returns boolean

    +
    + +
      +
    • get [eventHandled](): ReadonlyWeakSet<Event>
    • +
    • +

      Returns ReadonlyWeakSet<Event>

    +
    + +
      +
    • get [eventHandlers](): ReadonlyMap<string, Set<EventHandlerInfo>>
    • +
    • +

      Returns ReadonlyMap<string, Set<EventHandlerInfo>>

    +
    + +
      +
    • get [eventTarget](): EventTarget
    • +
    • +

      Returns EventTarget

    +
    + +
      +
    • get [handleEventError](): ((evt: EventError) => void)
    • +
    • +

      Returns ((evt: EventError) => void)

      +
        +
      • +
          +
        • (evt: EventError): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            evt: EventError
          +

          Returns void

    +
    + +
      +
    • get [statusP](): Promise<Status>
    • +
    • +

      Returns Promise<Status>

    +
    + +
      +
    • get [status](): Status
    • +
    • +

      Returns Status

    +
    + +
    +
    +

    Methods

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        callback: null | EventListenerOrEventListenerObject
      • +
      • +
        Optional options: boolean | AddEventListenerOptions
      +

      Returns void

    +
    + +
      + +
    • +

      Generic caller for Client streaming RPC calls. +This returns a WritableStream for writing the input to and a Promise that +resolves when the output is received. +When finished the writable stream must be ended. Failing to do so will +hold the connection open and result in a resource leak until the +call times out.

      +
      +
      +

      Type Parameters

      +
      +
      +

      Parameters

      +
        +
      • +
        method: string
        +

        Method name of the RPC call

        +
      • +
      • +
        ctx: Partial<ContextTimedInput> = {}
        +

        ContextTimed used for timeouts and cancellation.

        +
      +

      Returns Promise<{
          output: Promise<O>;
          writable: WritableStream<I>;
      }>

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        __namedParameters: {
            errorCode?: number;
            errorMessage?: string;
            force?: boolean;
        } = {}
        +
          +
        • +
          Optional errorCode?: number
        • +
        • +
          Optional errorMessage?: string
        • +
        • +
          Optional force?: boolean
      +

      Returns Promise<void>

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        event: Event
      +

      Returns boolean

    +
    + +
      + +
    • +

      Generic caller for duplex RPC calls. +This returns a ReadableWritablePair of the types specified. No validation +is applied to these types so make sure they match the types of the handler +you are calling. +When finished the streams must be ended manually. Failing to do so will +hold the connection open and result in a resource leak until the +call times out.

      +
      +
      +

      Type Parameters

      +
      +
      +

      Parameters

      +
        +
      • +
        method: string
        +

        Method name of the RPC call

        +
      • +
      • +
        ctx: Partial<ContextTimedInput> = {}
        +

        ContextTimed used for timeouts and cancellation.

        +
      +

      Returns Promise<RPCStream<O, I, Record<string, JSONValue>>>

    +
    + +
      + +
    • +

      Generic caller for raw RPC calls. +This returns a ReadableWritablePair of the raw RPC stream. +When finished the streams must be ended manually. Failing to do so will +hold the connection open and result in a resource leak until the +call times out. +Raw streams don't support the keep alive timeout. Timeout will only apply
      to the creation of the stream.

      +
      +
      +

      Parameters

      +
        +
      • +
        method: string
        +

        Method name of the RPC call

        +
      • +
      • +
        headerParams: JSONValue
        +

        Parameters for the header message. The header is a +single RPC message that is sent to specify the method for the RPC call. +Any metadata of extra parameters is provided here.

        +
      • +
      • +
        ctx: Partial<ContextTimedInput> = {}
        +

        ContextTimed used for timeouts and cancellation.

        +
      +

      Returns Promise<RPCStream<Uint8Array, Uint8Array, Record<string, JSONValue> & {
          command: string;
          result: JSONValue;
      }>>

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        callback: (() => void)
        +
          +
        • +
            +
          • (): void
          • +
          • +

            Returns void

      +

      Returns void

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        callback: null | EventListenerOrEventListenerObject
      • +
      • +
        Optional options: boolean | EventListenerOptions
      +

      Returns void

    +
    + +
      + +
    • +

      Generic caller for server streaming RPC calls. +This returns a ReadableStream of the provided type. When finished, the +readable needs to be cleaned up, otherwise cleanup happens mostly +automatically.

      +
      +
      +

      Type Parameters

      +
      +
      +

      Parameters

      +
        +
      • +
        method: string
        +

        Method name of the RPC call

        +
      • +
      • +
        parameters: I
        +

        Parameters to be provided with the RPC message. Matches +the provided I type.

        +
      • +
      • +
        ctx: Partial<ContextTimedInput> = {}
        +

        ContextTimed used for timeouts and cancellation.

        +
      +

      Returns Promise<ReadableStream<O>>

    +
    + +
      + +
    • +

      Generic caller for unary RPC calls. +This returns the response in the provided type. No validation is done so +make sure the types match the handler types.

      +
      +
      +

      Type Parameters

      +
      +
      +

      Parameters

      +
        +
      • +
        method: string
        +

        Method name of the RPC call

        +
      • +
      • +
        parameters: I
        +

        Parameters to be provided with the RPC message. Matches +the provided I type.

        +
      • +
      • +
        ctx: Partial<ContextTimedInput> = {}
        +

        ContextTimed used for timeouts and cancellation.

        +
      +

      Returns Promise<O>

    +
    + +
      + +
    • +
      +

      Type Parameters

      +
      +
      +

      Parameters

      +
        +
      • +
        obj: {
            idGen: IdGen;
            logger?: Logger;
            manifest: M;
            middlewareFactory?: MiddlewareFactory<Uint8Array, JSONRPCRequest<JSONValue>, JSONRPCResponse<JSONValue>, Uint8Array>;
            streamFactory: StreamFactory;
            streamKeepAliveTimeoutTime?: number;
        }
        +
          +
        • +
          idGen: IdGen
        • +
        • +
          Optional logger?: Logger
        • +
        • +
          manifest: M
          +

          Client manifest that defines the types for the rpc +methods.

          +
        • +
        • +
          Optional middlewareFactory?: MiddlewareFactory<Uint8Array, JSONRPCRequest<JSONValue>, JSONRPCResponse<JSONValue>, Uint8Array>
          +

          Middleware used to process the rpc messages. +The middlewareFactory needs to be a function that creates a pair of +transform streams that convert JSONRPCRequest to Uint8Array on the forward +path and Uint8Array to JSONRPCResponse on the reverse path.

          +
        • +
        • +
          streamFactory: StreamFactory
          +

          An arrow function that when called, creates a +new stream for each rpc method call.

          +
        • +
        • +
          Optional streamKeepAliveTimeoutTime?: number
          +

          Timeout time used if no timeout timer was provided when making a call. +Defaults to 60,000 milliseconds. +for a client call.

          +
      +

      Returns Promise<RPCClient<M>>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/RPCServer.html b/docs/classes/RPCServer.html new file mode 100644 index 0000000..393d050 --- /dev/null +++ b/docs/classes/RPCServer.html @@ -0,0 +1,687 @@ +RPCServer | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class RPCServer

    +
    +

    You must provide an error handler addEventListener('error'). +Otherwise, errors will just be ignored.

    +

    Events:

    + +
    +
    +

    Hierarchy

    +
      +
    • CreateDestroy
    • +
    • EventTarget +
        +
      • RPCServer
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    [initLock]: RWLockWriter
    +
    + +
    activeStreams: Set<PromiseCancellable<void>> = ...
    +
    + +
    defaultTimeoutMap: Map<string, undefined | number> = ...
    +
    + +
    fromError: ((error: Error, sensitive?: boolean) => JSONValue)
    +
    +

    Type declaration

    +
      +
    • +
        +
      • (error: Error, sensitive?: boolean): JSONValue
      • +
      • +
        +

        Parameters

        +
          +
        • +
          error: Error
        • +
        • +
          Optional sensitive: boolean
        +

        Returns JSONValue

    +
    + +
    handlerMap: Map<string, RawHandlerImplementation> = ...
    +
    + +
    handlerTimeoutTime: number
    +
    + +
    idGen: IdGen
    +
    + +
    logger: Logger
    +
    + +
    middlewareFactory: MiddlewareFactory<JSONRPCRequest<JSONValue>, Uint8Array, Uint8Array, JSONRPCResponseResult<JSONValue>>
    +
    + +
    onTimeoutCallback?: (() => void)
    +
    +

    Type declaration

    +
      +
    • +
        +
      • (): void
      • +
      • +

        Returns void

    +
    + +
    replacer: ((key: string, value: any) => any)
    +
    +

    Type declaration

    +
      +
    • +
        +
      • (key: string, value: any): any
      • +
      • +
        +

        Parameters

        +
          +
        • +
          key: string
        • +
        • +
          value: any
        +

        Returns any

    +
    + +
    sensitive: boolean
    +
    +

    Accessors

    +
    + +
      +
    • get [destroyed](): boolean
    • +
    • +

      Returns boolean

    +
    + +
      +
    • get [eventHandled](): ReadonlyWeakSet<Event>
    • +
    • +

      Returns ReadonlyWeakSet<Event>

    +
    + +
      +
    • get [eventHandlers](): ReadonlyMap<string, Set<EventHandlerInfo>>
    • +
    • +

      Returns ReadonlyMap<string, Set<EventHandlerInfo>>

    +
    + +
      +
    • get [eventTarget](): EventTarget
    • +
    • +

      Returns EventTarget

    +
    + +
      +
    • get [handleEventError](): ((evt: EventError) => void)
    • +
    • +

      Returns ((evt: EventError) => void)

      +
        +
      • +
          +
        • (evt: EventError): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            evt: EventError
          +

          Returns void

    +
    + +
      +
    • get [statusP](): Promise<Status>
    • +
    • +

      Returns Promise<Status>

    +
    + +
      +
    • get [status](): Status
    • +
    • +

      Returns Status

    +
    +

    Methods

    +
    + +
      + +
    • +

      Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched.

      +

      The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options's capture.

      +

      When set to true, options's capture prevents callback from being invoked when the event's eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event's eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event's eventPhase attribute value is AT_TARGET.

      +

      When set to true, options's passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners.

      +

      When set to true, options's once indicates that the callback will only be invoked once after which the event listener will be removed.

      +

      If an AbortSignal is passed for options's signal, then the event listener will be removed when signal is aborted.

      +

      The event listener is appended to target's event listener list and is not appended if it has the same type, callback, and capture.

      +
      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        callback: null | EventListenerOrEventListenerObject
      • +
      • +
        Optional options: boolean | AddEventListenerOptions
      +

      Returns void

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        force: boolean = true
      +

      Returns Promise<void>

    +
    + +
      + +
    • +

      Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise.

      +
      +
      +

      Parameters

      +
        +
      • +
        event: Event
      +

      Returns boolean

    +
    + +
      + +
    • +

      ID is associated with the stream, not individual messages.

      +
      +
      +

      Parameters

      +
      +

      Returns void

    +
    + +
    +
    + +
      + +
    • +

      The ID is generated only once when the function is called and stored in the id variable. +the ID is associated with the entire stream +Every response (whether successful or an error) produced within this stream will have the +same ID, which is consistent with the originating request.

      +
      +
      +

      Type Parameters

      +
      +
      +

      Parameters

      +
      +

      Returns void

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        callback: (() => void)
        +
          +
        • +
            +
          • (): void
          • +
          • +

            Returns void

      +

      Returns void

    +
    + +
      + +
    • +

      Registers a raw stream handler. This is the basis for all handlers as +handling the streams is done with raw streams only. +The raw streams do not automatically refresh the timeout timer when +messages are sent or received.

      +
      +
      +

      Parameters

      +
      +

      Returns void

    +
    + +
    +
    + +
    +
    + +
      + +
    • +

      Removes the event listener in target's event listener list with the same type, callback, and options.

      +
      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        callback: null | EventListenerOrEventListenerObject
      • +
      • +
        Optional options: boolean | EventListenerOptions
      +

      Returns void

    +
    + +
      + +
    • +

      Creates RPC server.

      +
      +
      +

      Parameters

      +
        +
      • +
        obj: {
            fromError?: ((error: Error) => JSONValue);
            handlerTimeoutTime?: number;
            idGen: IdGen;
            logger?: Logger;
            manifest: ServerManifest;
            middlewareFactory?: MiddlewareFactory<JSONRPCRequest<JSONValue>, Uint8Array, Uint8Array, JSONRPCResponse<JSONValue>>;
            replacer?: ((key: string, value: any) => any);
            sensitive?: boolean;
        }
        +
          +
        • +
          Optional fromError?: ((error: Error) => JSONValue)
          +
        • +
        • +
          Optional handlerTimeoutTime?: number
        • +
        • +
          idGen: IdGen
        • +
        • +
          Optional logger?: Logger
        • +
        • +
          manifest: ServerManifest
          +

          Server manifest used to define the rpc method +handlers.

          +
        • +
        • +
          Optional middlewareFactory?: MiddlewareFactory<JSONRPCRequest<JSONValue>, Uint8Array, Uint8Array, JSONRPCResponse<JSONValue>>
          +

          Middleware used to process the rpc messages. +The middlewareFactory needs to be a function that creates a pair of +transform streams that convert Uint8Array to JSONRPCRequest on the forward +path and JSONRPCResponse to Uint8Array on the reverse path.

          +
        • +
        • +
          Optional replacer?: ((key: string, value: any) => any)
          +
            +
          • +
              +
            • (key: string, value: any): any
            • +
            • +
              +

              Parameters

              +
                +
              • +
                key: string
              • +
              • +
                value: any
              +

              Returns any

        • +
        • +
          Optional sensitive?: boolean
          +

          If true, sanitises any rpc error messages of any +sensitive information.

          +
      +

      Returns Promise<RPCServer>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/callers.Caller.html b/docs/classes/callers.Caller.html new file mode 100644 index 0000000..43ec3e4 --- /dev/null +++ b/docs/classes/callers.Caller.html @@ -0,0 +1,122 @@ +Caller | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class Caller<Input, Output>Abstract

    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: Input
    +
    + +
    _outputType: Output
    +
    + +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/callers.ClientCaller.html b/docs/classes/callers.ClientCaller.html new file mode 100644 index 0000000..c69439f --- /dev/null +++ b/docs/classes/callers.ClientCaller.html @@ -0,0 +1,122 @@ +ClientCaller | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ClientCaller<Input, Output>

    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
      +
    • Caller<Input, Output> +
        +
      • ClientCaller
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: Input
    +
    + +
    _outputType: Output
    +
    + +
    type: "CLIENT" = ...
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/callers.DuplexCaller.html b/docs/classes/callers.DuplexCaller.html new file mode 100644 index 0000000..e517c1f --- /dev/null +++ b/docs/classes/callers.DuplexCaller.html @@ -0,0 +1,122 @@ +DuplexCaller | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class DuplexCaller<Input, Output>

    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
      +
    • Caller<Input, Output> +
        +
      • DuplexCaller
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: Input
    +
    + +
    _outputType: Output
    +
    + +
    type: "DUPLEX" = ...
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/callers.RawCaller.html b/docs/classes/callers.RawCaller.html new file mode 100644 index 0000000..7ce39fa --- /dev/null +++ b/docs/classes/callers.RawCaller.html @@ -0,0 +1,108 @@ +RawCaller | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class RawCaller

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: JSONValue
    +
    + +
    _outputType: JSONValue
    +
    + +
    type: "RAW" = ...
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/callers.ServerCaller.html b/docs/classes/callers.ServerCaller.html new file mode 100644 index 0000000..2f4afd5 --- /dev/null +++ b/docs/classes/callers.ServerCaller.html @@ -0,0 +1,122 @@ +ServerCaller | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ServerCaller<Input, Output>

    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
      +
    • Caller<Input, Output> +
        +
      • ServerCaller
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: Input
    +
    + +
    _outputType: Output
    +
    + +
    type: "SERVER" = ...
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/callers.UnaryCaller.html b/docs/classes/callers.UnaryCaller.html new file mode 100644 index 0000000..71fe6c4 --- /dev/null +++ b/docs/classes/callers.UnaryCaller.html @@ -0,0 +1,122 @@ +UnaryCaller | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class UnaryCaller<Input, Output>

    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
      +
    • Caller<Input, Output> +
        +
      • UnaryCaller
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: Input
    +
    + +
    _outputType: Output
    +
    + +
    type: "UNARY" = ...
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorHandlerAborted.html b/docs/classes/errors.ErrorHandlerAborted.html new file mode 100644 index 0000000..73ff343 --- /dev/null +++ b/docs/classes/errors.ErrorHandlerAborted.html @@ -0,0 +1,323 @@ +ErrorHandlerAborted | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorHandlerAborted<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorMissingCaller.html b/docs/classes/errors.ErrorMissingCaller.html new file mode 100644 index 0000000..c31a78c --- /dev/null +++ b/docs/classes/errors.ErrorMissingCaller.html @@ -0,0 +1,323 @@ +ErrorMissingCaller | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorMissingCaller<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorMissingHeader.html b/docs/classes/errors.ErrorMissingHeader.html new file mode 100644 index 0000000..87b8077 --- /dev/null +++ b/docs/classes/errors.ErrorMissingHeader.html @@ -0,0 +1,323 @@ +ErrorMissingHeader | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorMissingHeader<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPC.html b/docs/classes/errors.ErrorRPC.html new file mode 100644 index 0000000..4c50917 --- /dev/null +++ b/docs/classes/errors.ErrorRPC.html @@ -0,0 +1,353 @@ +ErrorRPC | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPC<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +

    Implements

    +
      +
    • RPCError
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Type Parameters

      +
        +
      • +

        T

      +
      +

      Parameters

      +
        +
      • +
        Optional message: string
      +

      Returns ErrorRPC<T>

    +
    +

    Properties

    +
    + +
    _description: string = 'Generic Error'
    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCCallerFailed.html b/docs/classes/errors.ErrorRPCCallerFailed.html new file mode 100644 index 0000000..52aede3 --- /dev/null +++ b/docs/classes/errors.ErrorRPCCallerFailed.html @@ -0,0 +1,323 @@ +ErrorRPCCallerFailed | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCCallerFailed<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCConnectionInternal.html b/docs/classes/errors.ErrorRPCConnectionInternal.html new file mode 100644 index 0000000..8884702 --- /dev/null +++ b/docs/classes/errors.ErrorRPCConnectionInternal.html @@ -0,0 +1,318 @@ +ErrorRPCConnectionInternal | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCConnectionInternal<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
      +
    • ErrorRPC<T> +
        +
      • ErrorRPCConnectionInternal
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: JSONRPCErrorCode = JSONRPCErrorCode.RPCConnectionInternal
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string = 'RPC Connection internal error'
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCConnectionKeepAliveTimeOut.html b/docs/classes/errors.ErrorRPCConnectionKeepAliveTimeOut.html new file mode 100644 index 0000000..396533b --- /dev/null +++ b/docs/classes/errors.ErrorRPCConnectionKeepAliveTimeOut.html @@ -0,0 +1,318 @@ +ErrorRPCConnectionKeepAliveTimeOut | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCConnectionKeepAliveTimeOut<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
      +
    • ErrorRPC<T> +
        +
      • ErrorRPCConnectionKeepAliveTimeOut
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: JSONRPCErrorCode = JSONRPCErrorCode.RPCConnectionKeepAliveTimeOut
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string = 'RPC Connection keep alive timeout'
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCConnectionLocal.html b/docs/classes/errors.ErrorRPCConnectionLocal.html new file mode 100644 index 0000000..dee730b --- /dev/null +++ b/docs/classes/errors.ErrorRPCConnectionLocal.html @@ -0,0 +1,318 @@ +ErrorRPCConnectionLocal | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCConnectionLocal<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
      +
    • ErrorRPC<T> +
        +
      • ErrorRPCConnectionLocal
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: JSONRPCErrorCode = JSONRPCErrorCode.RPCConnectionLocal
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string = 'RPC Connection local error'
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCConnectionPeer.html b/docs/classes/errors.ErrorRPCConnectionPeer.html new file mode 100644 index 0000000..9a7e0dd --- /dev/null +++ b/docs/classes/errors.ErrorRPCConnectionPeer.html @@ -0,0 +1,318 @@ +ErrorRPCConnectionPeer | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCConnectionPeer<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: JSONRPCErrorCode = JSONRPCErrorCode.RPCConnectionPeer
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string = 'RPC Connection peer error'
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCDestroyed.html b/docs/classes/errors.ErrorRPCDestroyed.html new file mode 100644 index 0000000..14cdc41 --- /dev/null +++ b/docs/classes/errors.ErrorRPCDestroyed.html @@ -0,0 +1,318 @@ +ErrorRPCDestroyed | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCDestroyed<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCHandlerFailed.html b/docs/classes/errors.ErrorRPCHandlerFailed.html new file mode 100644 index 0000000..60be7b8 --- /dev/null +++ b/docs/classes/errors.ErrorRPCHandlerFailed.html @@ -0,0 +1,326 @@ +ErrorRPCHandlerFailed | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCHandlerFailed<T>

    +
    +

    This is an internal error, it should not reach the top level.

    +
    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCMessageLength.html b/docs/classes/errors.ErrorRPCMessageLength.html new file mode 100644 index 0000000..03bc895 --- /dev/null +++ b/docs/classes/errors.ErrorRPCMessageLength.html @@ -0,0 +1,318 @@ +ErrorRPCMessageLength | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCMessageLength<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: JSONRPCErrorCode = JSONRPCErrorCode.RPCMessageLength
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string = 'RPC Message exceeds maximum size'
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCMethodNotImplemented.html b/docs/classes/errors.ErrorRPCMethodNotImplemented.html new file mode 100644 index 0000000..c2a7dbb --- /dev/null +++ b/docs/classes/errors.ErrorRPCMethodNotImplemented.html @@ -0,0 +1,318 @@ +ErrorRPCMethodNotImplemented | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCMethodNotImplemented<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
      +
    • ErrorRPC<T> +
        +
      • ErrorRPCMethodNotImplemented
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCMissingResponse.html b/docs/classes/errors.ErrorRPCMissingResponse.html new file mode 100644 index 0000000..803a3d8 --- /dev/null +++ b/docs/classes/errors.ErrorRPCMissingResponse.html @@ -0,0 +1,318 @@ +ErrorRPCMissingResponse | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCMissingResponse<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
      +
    • ErrorRPC<T> +
        +
      • ErrorRPCMissingResponse
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCOutputStreamError.html b/docs/classes/errors.ErrorRPCOutputStreamError.html new file mode 100644 index 0000000..1b989b9 --- /dev/null +++ b/docs/classes/errors.ErrorRPCOutputStreamError.html @@ -0,0 +1,320 @@ +ErrorRPCOutputStreamError | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCOutputStreamError<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
      +
    • ErrorRPC<T> +
        +
      • ErrorRPCOutputStreamError
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCParse.html b/docs/classes/errors.ErrorRPCParse.html new file mode 100644 index 0000000..0977d34 --- /dev/null +++ b/docs/classes/errors.ErrorRPCParse.html @@ -0,0 +1,323 @@ +ErrorRPCParse | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCParse<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Type Parameters

      +
        +
      • +

        T

      +
      +

      Parameters

      +
        +
      • +
        Optional message: string
      • +
      • +
        Optional options: {
            cause: Error;
        }
        +
          +
        • +
          cause: Error
      +

      Returns ErrorRPCParse<T>

    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string = 'Failed to parse Buffer stream'
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCRemote.html b/docs/classes/errors.ErrorRPCRemote.html new file mode 100644 index 0000000..138c07a --- /dev/null +++ b/docs/classes/errors.ErrorRPCRemote.html @@ -0,0 +1,336 @@ +ErrorRPCRemote | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCRemote<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    metadata: JSONValue
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string = 'Remote error from RPC call'
    +

    Static description of exception

    +
    +
    + +
    message: string = 'The server responded with an error'
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCStopping.html b/docs/classes/errors.ErrorRPCStopping.html new file mode 100644 index 0000000..46c36c8 --- /dev/null +++ b/docs/classes/errors.ErrorRPCStopping.html @@ -0,0 +1,318 @@ +ErrorRPCStopping | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCStopping<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCStreamEnded.html b/docs/classes/errors.ErrorRPCStreamEnded.html new file mode 100644 index 0000000..01f85f5 --- /dev/null +++ b/docs/classes/errors.ErrorRPCStreamEnded.html @@ -0,0 +1,323 @@ +ErrorRPCStreamEnded | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCStreamEnded<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorRPCTimedOut.html b/docs/classes/errors.ErrorRPCTimedOut.html new file mode 100644 index 0000000..b33e6e2 --- /dev/null +++ b/docs/classes/errors.ErrorRPCTimedOut.html @@ -0,0 +1,323 @@ +ErrorRPCTimedOut | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorRPCTimedOut<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/errors.ErrorUtilsUndefinedBehaviour.html b/docs/classes/errors.ErrorUtilsUndefinedBehaviour.html new file mode 100644 index 0000000..8676fa6 --- /dev/null +++ b/docs/classes/errors.ErrorUtilsUndefinedBehaviour.html @@ -0,0 +1,318 @@ +ErrorUtilsUndefinedBehaviour | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ErrorUtilsUndefinedBehaviour<T>

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Hierarchy

    +
      +
    • ErrorRPC<T> +
        +
      • ErrorUtilsUndefinedBehaviour
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Accessors

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    cause: T
    +

    Causation of the exception +Can be used to know what caused this exception

    +
    +
    + +
    code: number
    +
    + +
    data: POJO
    +

    Arbitrary data

    +
    +
    + +
    message: string
    +
    + +
    name: string
    +
    + +
    stack?: string
    +
    + +
    timestamp: Date
    +

    Timestamp when exception was constructed in milliseconds +Guaranteed to be weakly monotonic

    +
    +
    + +
    type: string
    +
    + +
    description: string
    +

    Static description of exception

    +
    +
    + +
    prepareStackTrace?: ((err: Error, stackTraces: CallSite[]) => any)
    +
    +

    Type declaration

    +
    +
    + +
    stackTraceLimit: number
    +
    +

    Accessors

    +
    + +
      +
    • get description(): string
    • +
    • +

      Returns string

    • +
    • set description(value: string): void
    • +
    • +
      +

      Parameters

      +
        +
      • +
        value: string
      +

      Returns void

    +
    +

    Methods

    +
    + +
      + +
    • +

      Encoding to JSON pojo +When overriding this, you can use super.toJSON +The replacer will:

      +
        +
      • delete undefined values in objects
      • +
      • replace undefined values for null in arrays
      • +
      +
      +

      Returns any

    +
    + +
      + +
    • +

      Create .stack property on a target object

      +
      +
      +

      Parameters

      +
        +
      • +
        targetObject: object
      • +
      • +
        Optional constructorOpt: Function
      +

      Returns void

    +
    + +
      + +
    • +

      Runtime decoding of JSON POJO to exception instance +When overriding this, you cannot use super.fromJSON +You must write it fully, and use the same type-hacks +to support polymorphic this in static methods +https://github.com/microsoft/TypeScript/issues/5863

      +
      +
      +

      Type Parameters

      +
        +
      • +

        T extends Class<any>

      +
      +

      Parameters

      +
        +
      • +
        this: T
      • +
      • +
        json: any
      +

      Returns InstanceType<T>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPC.html b/docs/classes/events.EventRPC.html new file mode 100644 index 0000000..5e8214a --- /dev/null +++ b/docs/classes/events.EventRPC.html @@ -0,0 +1,427 @@ +EventRPC | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPC<T>Abstract

    +
    +

    Type Parameters

    +
      +
    • +

      T = null

    +
    +

    Hierarchy

    +
      +
    • AbstractEvent<T> +
        +
      • EventRPC
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Type Parameters

      +
        +
      • +

        T = null

      +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<T>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPC<T>

    • + +
    • +
      +

      Type Parameters

      +
        +
      • +

        T = null

      +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<T>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPC<T>

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: T
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPC<T>

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCClient.html b/docs/classes/events.EventRPCClient.html new file mode 100644 index 0000000..66781d6 --- /dev/null +++ b/docs/classes/events.EventRPCClient.html @@ -0,0 +1,434 @@ +EventRPCClient | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCClient<T>Abstract

    +
    +

    Type Parameters

    +
      +
    • +

      T = null

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Type Parameters

      +
        +
      • +

        T = null

      +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<T>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClient<T>

    • + +
    • +
      +

      Type Parameters

      +
        +
      • +

        T = null

      +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<T>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClient<T>

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: T
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCClient<T>

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCClientConnect.html b/docs/classes/events.EventRPCClientConnect.html new file mode 100644 index 0000000..d80c6e5 --- /dev/null +++ b/docs/classes/events.EventRPCClientConnect.html @@ -0,0 +1,412 @@ +EventRPCClientConnect | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCClientConnect

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientConnect

    • + +
    • +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientConnect

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: null
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCClientConnect

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCClientCreate.html b/docs/classes/events.EventRPCClientCreate.html new file mode 100644 index 0000000..442b0a6 --- /dev/null +++ b/docs/classes/events.EventRPCClientCreate.html @@ -0,0 +1,412 @@ +EventRPCClientCreate | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCClientCreate

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientCreate

    • + +
    • +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientCreate

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: null
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCClientCreate

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCClientCreated.html b/docs/classes/events.EventRPCClientCreated.html new file mode 100644 index 0000000..397e826 --- /dev/null +++ b/docs/classes/events.EventRPCClientCreated.html @@ -0,0 +1,412 @@ +EventRPCClientCreated | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCClientCreated

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientCreated

    • + +
    • +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientCreated

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: null
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCClientCreated

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCClientDestroy.html b/docs/classes/events.EventRPCClientDestroy.html new file mode 100644 index 0000000..401a661 --- /dev/null +++ b/docs/classes/events.EventRPCClientDestroy.html @@ -0,0 +1,412 @@ +EventRPCClientDestroy | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCClientDestroy

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientDestroy

    • + +
    • +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientDestroy

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: null
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCClientDestroy

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCClientDestroyed.html b/docs/classes/events.EventRPCClientDestroyed.html new file mode 100644 index 0000000..bb03655 --- /dev/null +++ b/docs/classes/events.EventRPCClientDestroyed.html @@ -0,0 +1,412 @@ +EventRPCClientDestroyed | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCClientDestroyed

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientDestroyed

    • + +
    • +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientDestroyed

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: null
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCClientDestroyed

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCClientError.html b/docs/classes/events.EventRPCClientError.html new file mode 100644 index 0000000..f66a681 --- /dev/null +++ b/docs/classes/events.EventRPCClientError.html @@ -0,0 +1,412 @@ +EventRPCClientError | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCClientError

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<Error>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientError

    • + +
    • +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<Error>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCClientError

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: Error
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCClientError

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCConnection.html b/docs/classes/events.EventRPCConnection.html new file mode 100644 index 0000000..7784b12 --- /dev/null +++ b/docs/classes/events.EventRPCConnection.html @@ -0,0 +1,429 @@ +EventRPCConnection | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCConnection<T>Abstract

    +
    +

    Type Parameters

    +
      +
    • +

      T = null

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Type Parameters

      +
        +
      • +

        T = null

      +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<T>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCConnection<T>

    • + +
    • +
      +

      Type Parameters

      +
        +
      • +

        T = null

      +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<T>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCConnection<T>

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: T
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCConnection<T>

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCConnectionError.html b/docs/classes/events.EventRPCConnectionError.html new file mode 100644 index 0000000..e9b2e0e --- /dev/null +++ b/docs/classes/events.EventRPCConnectionError.html @@ -0,0 +1,412 @@ +EventRPCConnectionError | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCConnectionError

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCConnectionError

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCServer.html b/docs/classes/events.EventRPCServer.html new file mode 100644 index 0000000..70a778b --- /dev/null +++ b/docs/classes/events.EventRPCServer.html @@ -0,0 +1,434 @@ +EventRPCServer | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCServer<T>Abstract

    +
    +

    Type Parameters

    +
      +
    • +

      T = null

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Type Parameters

      +
        +
      • +

        T = null

      +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<T>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServer<T>

    • + +
    • +
      +

      Type Parameters

      +
        +
      • +

        T = null

      +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<T>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServer<T>

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: T
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCServer<T>

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCServerConnection.html b/docs/classes/events.EventRPCServerConnection.html new file mode 100644 index 0000000..0e27934 --- /dev/null +++ b/docs/classes/events.EventRPCServerConnection.html @@ -0,0 +1,412 @@ +EventRPCServerConnection | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCServerConnection

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: RPCServer
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCServerConnection

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCServerCreate.html b/docs/classes/events.EventRPCServerCreate.html new file mode 100644 index 0000000..e55d0ec --- /dev/null +++ b/docs/classes/events.EventRPCServerCreate.html @@ -0,0 +1,412 @@ +EventRPCServerCreate | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCServerCreate

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServerCreate

    • + +
    • +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServerCreate

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: null
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCServerCreate

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCServerCreated.html b/docs/classes/events.EventRPCServerCreated.html new file mode 100644 index 0000000..d1a17be --- /dev/null +++ b/docs/classes/events.EventRPCServerCreated.html @@ -0,0 +1,412 @@ +EventRPCServerCreated | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCServerCreated

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServerCreated

    • + +
    • +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServerCreated

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: null
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCServerCreated

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCServerDestroy.html b/docs/classes/events.EventRPCServerDestroy.html new file mode 100644 index 0000000..0f11673 --- /dev/null +++ b/docs/classes/events.EventRPCServerDestroy.html @@ -0,0 +1,412 @@ +EventRPCServerDestroy | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCServerDestroy

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServerDestroy

    • + +
    • +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServerDestroy

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: null
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCServerDestroy

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCServerDestroyed.html b/docs/classes/events.EventRPCServerDestroyed.html new file mode 100644 index 0000000..c8c98aa --- /dev/null +++ b/docs/classes/events.EventRPCServerDestroyed.html @@ -0,0 +1,412 @@ +EventRPCServerDestroyed | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCServerDestroyed

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServerDestroyed

    • + +
    • +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<null>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServerDestroyed

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: null
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCServerDestroyed

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.EventRPCServerError.html b/docs/classes/events.EventRPCServerError.html new file mode 100644 index 0000000..c345681 --- /dev/null +++ b/docs/classes/events.EventRPCServerError.html @@ -0,0 +1,412 @@ +EventRPCServerError | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class EventRPCServerError

    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        Optional type: string
      • +
      • +
        Optional options: CustomEventInit<Error>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServerError

    • + +
    • +
      +

      Parameters

      +
        +
      • +
        options: CustomEventInit<Error>
      • +
      • +
        Optional constructorParams: IArguments
      +

      Returns EventRPCServerError

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    constructorParams: IArguments
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: Error
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Events cannot be re-dispatched. This was probably to prevent infinite +loops. So instead of re-dispatching the same instance, we re-dispatch +a clone of the instance.

      +
      +

      Returns EventRPCServerError

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/events.RPCErrorEvent.html b/docs/classes/events.RPCErrorEvent.html new file mode 100644 index 0000000..a13d3a7 --- /dev/null +++ b/docs/classes/events.RPCErrorEvent.html @@ -0,0 +1,371 @@ +RPCErrorEvent | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class RPCErrorEvent

    +
    +

    Hierarchy

    +
      +
    • Event +
        +
      • RPCErrorEvent
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        options: EventInit & {
            detail: Error;
        }
      +

      Returns RPCErrorEvent

    +
    +

    Properties

    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    + +
    bubbles: boolean
    +

    Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.

    +
    +
    + +
    cancelBubble: boolean
    +
    +

    Deprecated

    +
    + +
    cancelable: boolean
    +

    Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.

    +
    +
    + +
    composed: boolean
    +

    Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.

    +
    +
    + +
    currentTarget: null | EventTarget
    +

    Returns the object whose event listener's callback is currently being invoked.

    +
    +
    + +
    defaultPrevented: boolean
    +

    Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.

    +
    +
    + +
    detail: Error
    +
    + +
    eventPhase: number
    +

    Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.

    +
    +
    + +
    isTrusted: boolean
    +

    Returns true if event was dispatched by the user agent, and false otherwise.

    +
    +
    + +
    returnValue: boolean
    +
    +

    Deprecated

    +
    + +
    srcElement: null | EventTarget
    +
    +

    Deprecated

    +
    + +
    target: null | EventTarget
    +

    Returns the object to which event is dispatched (its target).

    +
    +
    + +
    timeStamp: number
    +

    Returns the event's timestamp as the number of milliseconds measured relative to the time origin.

    +
    +
    + +
    type: string
    +

    Returns the type of event, e.g. "click", "hashchange", or "submit".

    +
    +
    + +
    AT_TARGET: number
    +
    + +
    BUBBLING_PHASE: number
    +
    + +
    CAPTURING_PHASE: number
    +
    + +
    NONE: number
    +
    +

    Methods

    +
    + +
      + +
    • +

      Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget.

      +
      +

      Returns EventTarget[]

    +
    + +
      + +
    • +
      +

      Deprecated

      +
      +

      Parameters

      +
        +
      • +
        type: string
      • +
      • +
        Optional bubbles: boolean
      • +
      • +
        Optional cancelable: boolean
      +

      Returns void

    +
    + +
      + +
    • +

      If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.

      +
      +

      Returns void

    +
    + +
      + +
    • +

      When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.

      +
      +

      Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/handlers.ClientHandler.html b/docs/classes/handlers.ClientHandler.html new file mode 100644 index 0000000..a6fbeed --- /dev/null +++ b/docs/classes/handlers.ClientHandler.html @@ -0,0 +1,181 @@ +ClientHandler | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ClientHandler<Container, Input, Output>Abstract

    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
      +
    • Handler<Container, Input, Output> +
        +
      • ClientHandler
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: Input
    +
    + +
    _outputType: Output
    +
    + +
    container: Container
    +
    + +
    timeout?: number
    +

    This is the timeout used for the handler. +If it is not set then the default timeout time for the RPCServer is used.

    +
    +
    +

    Methods

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        input: AsyncIterableIterator<Input>
      • +
      • +
        cancel: ((reason?: any) => void)
        +
          +
        • +
            +
          • (reason?: any): void
          • +
          • +
            +

            Parameters

            +
              +
            • +
              Optional reason: any
            +

            Returns void

      • +
      • +
        meta: undefined | Record<string, JSONValue>
      • +
      • +
        ctx: ContextTimed
      +

      Returns Promise<Output>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/handlers.DuplexHandler.html b/docs/classes/handlers.DuplexHandler.html new file mode 100644 index 0000000..0a610d1 --- /dev/null +++ b/docs/classes/handlers.DuplexHandler.html @@ -0,0 +1,185 @@ +DuplexHandler | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class DuplexHandler<Container, Input, Output>Abstract

    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
      +
    • Handler<Container, Input, Output> +
        +
      • DuplexHandler
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: Input
    +
    + +
    _outputType: Output
    +
    + +
    container: Container
    +
    + +
    handle: ((input: AsyncIterableIterator<Input>, cancel: ((reason?: any) => void), meta: undefined | Record<string, JSONValue>, ctx: ContextTimed) => AsyncIterableIterator<Output>) = ...
    +
    +

    Type declaration

    +
      +
    • +
        +
      • (input: AsyncIterableIterator<Input>, cancel: ((reason?: any) => void), meta: undefined | Record<string, JSONValue>, ctx: ContextTimed): AsyncIterableIterator<Output>
      • +
      • +

        Note that if the output has an error, the handler will not see this as an +error. If you need to handle any clean up it should be handled in a +finally block and check the abort signal for potential errors.

        +
        +
        +

        Parameters

        +
          +
        • +
          input: AsyncIterableIterator<Input>
        • +
        • +
          cancel: ((reason?: any) => void)
          +
            +
          • +
              +
            • (reason?: any): void
            • +
            • +
              +

              Parameters

              +
                +
              • +
                Optional reason: any
              +

              Returns void

        • +
        • +
          meta: undefined | Record<string, JSONValue>
        • +
        • +
          ctx: ContextTimed
        +

        Returns AsyncIterableIterator<Output>

    +
    + +
    timeout?: number
    +

    This is the timeout used for the handler. +If it is not set then the default timeout time for the RPCServer is used.

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/handlers.Handler.html b/docs/classes/handlers.Handler.html new file mode 100644 index 0000000..4554370 --- /dev/null +++ b/docs/classes/handlers.Handler.html @@ -0,0 +1,143 @@ +Handler | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class Handler<Container, Input, Output>Abstract

    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: Input
    +
    + +
    _outputType: Output
    +
    + +
    container: Container
    +
    + +
    timeout?: number
    +

    This is the timeout used for the handler. +If it is not set then the default timeout time for the RPCServer is used.

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/handlers.RawHandler.html b/docs/classes/handlers.RawHandler.html new file mode 100644 index 0000000..ff6d352 --- /dev/null +++ b/docs/classes/handlers.RawHandler.html @@ -0,0 +1,173 @@ +RawHandler | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class RawHandler<Container>Abstract

    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: JSONValue
    +
    + +
    _outputType: JSONValue
    +
    + +
    container: Container
    +
    + +
    timeout?: number
    +

    This is the timeout used for the handler. +If it is not set then the default timeout time for the RPCServer is used.

    +
    +
    +

    Methods

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        input: [JSONRPCRequest<JSONValue>, ReadableStream<Uint8Array>]
      • +
      • +
        cancel: ((reason?: any) => void)
        +
          +
        • +
            +
          • (reason?: any): void
          • +
          • +
            +

            Parameters

            +
              +
            • +
              Optional reason: any
            +

            Returns void

      • +
      • +
        meta: undefined | Record<string, JSONValue>
      • +
      • +
        ctx: ContextTimed
      +

      Returns Promise<[JSONValue, ReadableStream<Uint8Array>]>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/handlers.ServerHandler.html b/docs/classes/handlers.ServerHandler.html new file mode 100644 index 0000000..923d661 --- /dev/null +++ b/docs/classes/handlers.ServerHandler.html @@ -0,0 +1,181 @@ +ServerHandler | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class ServerHandler<Container, Input, Output>Abstract

    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
      +
    • Handler<Container, Input, Output> +
        +
      • ServerHandler
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: Input
    +
    + +
    _outputType: Output
    +
    + +
    container: Container
    +
    + +
    handle: ((input: Input, cancel: ((reason?: any) => void), meta: undefined | Record<string, JSONValue>, ctx: ContextTimed) => AsyncIterableIterator<Output>) = ...
    +
    +

    Type declaration

    +
      +
    • +
        +
      • (input: Input, cancel: ((reason?: any) => void), meta: undefined | Record<string, JSONValue>, ctx: ContextTimed): AsyncIterableIterator<Output>
      • +
      • +
        +

        Parameters

        +
          +
        • +
          input: Input
        • +
        • +
          cancel: ((reason?: any) => void)
          +
            +
          • +
              +
            • (reason?: any): void
            • +
            • +
              +

              Parameters

              +
                +
              • +
                Optional reason: any
              +

              Returns void

        • +
        • +
          meta: undefined | Record<string, JSONValue>
        • +
        • +
          ctx: ContextTimed
        +

        Returns AsyncIterableIterator<Output>

    +
    + +
    timeout?: number
    +

    This is the timeout used for the handler. +If it is not set then the default timeout time for the RPCServer is used.

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/classes/handlers.UnaryHandler.html b/docs/classes/handlers.UnaryHandler.html new file mode 100644 index 0000000..0741a59 --- /dev/null +++ b/docs/classes/handlers.UnaryHandler.html @@ -0,0 +1,181 @@ +UnaryHandler | js-rpc
    +
    + +
    +
    +
    +
    + +

    Class UnaryHandler<Container, Input, Output>Abstract

    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
      +
    • Handler<Container, Input, Output> +
        +
      • UnaryHandler
    +
    +
    +
    + +
    +
    +

    Constructors

    +
    +
    +

    Properties

    +
    +
    +

    Methods

    +
    +
    +

    Constructors

    +
    + +
    +
    +

    Properties

    +
    + +
    _inputType: Input
    +
    + +
    _outputType: Output
    +
    + +
    container: Container
    +
    + +
    timeout?: number
    +

    This is the timeout used for the handler. +If it is not set then the default timeout time for the RPCServer is used.

    +
    +
    +

    Methods

    +
    + +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        input: Input
      • +
      • +
        cancel: ((reason?: any) => void)
        +
          +
        • +
            +
          • (reason?: any): void
          • +
          • +
            +

            Parameters

            +
              +
            • +
              Optional reason: any
            +

            Returns void

      • +
      • +
        meta: undefined | Record<string, JSONValue>
      • +
      • +
        ctx: ContextTimed
      +

      Returns Promise<Output>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/enums/errors.JSONRPCErrorCode.html b/docs/enums/errors.JSONRPCErrorCode.html new file mode 100644 index 0000000..7dd30bd --- /dev/null +++ b/docs/enums/errors.JSONRPCErrorCode.html @@ -0,0 +1,211 @@ +JSONRPCErrorCode | js-rpc
    +
    + +
    +
    +
    +
    + +

    Enumeration JSONRPCErrorCodeConst

    +
    +
    +
    + +
    +
    +

    Enumeration Members

    +
    + +
    HandlerAborted: -32015
    +
    + +
    HandlerNotFound: -32000
    +
    + +
    InternalError: -32603
    +
    + +
    InvalidParams: -32602
    +
    + +
    InvalidRequest: -32600
    +
    + +
    MethodNotFound: -32601
    +
    + +
    MissingCaller: -32016
    +
    + +
    MissingHeader: -32014
    +
    + +
    ParseError: -32700
    +
    + +
    RPCConnectionInternal: -32013
    +
    + +
    RPCConnectionKeepAliveTimeOut: -32012
    +
    + +
    RPCConnectionLocal: -32010
    +
    + +
    RPCConnectionPeer: -32011
    +
    + +
    RPCDestroyed: -32002
    +
    + +
    RPCMessageLength: -32003
    +
    + +
    RPCMissingResponse: -32004
    +
    + +
    RPCOutputStreamError: -32005
    +
    + +
    RPCRemote: -32006
    +
    + +
    RPCStopping: -32001
    +
    + +
    RPCStreamEnded: -32007
    +
    + +
    RPCTimedOut: -32008
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/errors.never.html b/docs/functions/errors.never.html new file mode 100644 index 0000000..510689f --- /dev/null +++ b/docs/functions/errors.never.html @@ -0,0 +1,80 @@ +never | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.clientInputTransformStream.html b/docs/functions/utils.clientInputTransformStream.html new file mode 100644 index 0000000..1ec147f --- /dev/null +++ b/docs/functions/utils.clientInputTransformStream.html @@ -0,0 +1,95 @@ +clientInputTransformStream | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function clientInputTransformStream

    +
    +
      + +
    • +

      This constructs a transformation stream that converts any input into a +JSONRCPRequest message. It also refreshes a timer each time a message is processed if +one is provided.

      +
      +
      +

      Type Parameters

      +
      +
      +

      Parameters

      +
        +
      • +
        method: string
        +

        Name of the method that was called, used to select the +server side.

        +
      • +
      • +
        Optional timer: Timer<void>
        +

        Timer that gets refreshed each time a message is provided.

        +
      +

      Returns TransformStream<I, JSONRPCRequest>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.clientOutputTransformStream.html b/docs/functions/utils.clientOutputTransformStream.html new file mode 100644 index 0000000..dee26a8 --- /dev/null +++ b/docs/functions/utils.clientOutputTransformStream.html @@ -0,0 +1,95 @@ +clientOutputTransformStream | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function clientOutputTransformStream

    +
    +
      + +
    • +

      This constructs a transformation stream that converts any error messages +into errors. It also refreshes a timer each time a message is processed if +one is provided.

      +
      +
      +

      Type Parameters

      +
      +
      +

      Parameters

      +
        +
      • +
        Optional clientMetadata: JSONValue
        +

        Metadata that is attached to an error when one is +created.

        +
      • +
      • +
        Optional timer: Timer<void>
        +

        Timer that gets refreshed each time a message is provided.

        +
      +

      Returns TransformStream<JSONRPCResponse<O>, O>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.fromError.html b/docs/functions/utils.fromError.html new file mode 100644 index 0000000..4030258 --- /dev/null +++ b/docs/functions/utils.fromError.html @@ -0,0 +1,89 @@ +fromError | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function fromError

    +
    +
      + +
    • +

      Serializes an ErrorRPC instance into a JSONValue object suitable for RPC.

      + +

      Returns

      The serialized ErrorRPC instance.

      +
      +
      +

      Parameters

      +
        +
      • +
        error: ErrorRPC<any>
        +

        The ErrorRPC instance to serialize.

        +
      • +
      • +
        Optional id: any
        +

        Optional id for the error object in the RPC response.

        +
      +

      Returns JSONValue

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.getHandlerTypes.html b/docs/functions/utils.getHandlerTypes.html new file mode 100644 index 0000000..94419f5 --- /dev/null +++ b/docs/functions/utils.getHandlerTypes.html @@ -0,0 +1,79 @@ +getHandlerTypes | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function getHandlerTypes

    +
    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.isObject.html b/docs/functions/utils.isObject.html new file mode 100644 index 0000000..12bd680 --- /dev/null +++ b/docs/functions/utils.isObject.html @@ -0,0 +1,79 @@ +isObject | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function isObject

    +
    +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        o: unknown
      +

      Returns o is object

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.parseHeadStream.html b/docs/functions/utils.parseHeadStream.html new file mode 100644 index 0000000..ef89654 --- /dev/null +++ b/docs/functions/utils.parseHeadStream.html @@ -0,0 +1,108 @@ +parseHeadStream | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function parseHeadStream

    +
    +
      + +
    • +

      This function is a factory to create a TransformStream that will +transform a Uint8Array stream to a JSONRPC message stream. +The parsed messages will be validated with the provided messageParser, this +also infers the type of the stream output.

      +
      +
      +

      Type Parameters

      +
      +
      +

      Parameters

      +
        +
      • +
        messageParser: ((message: unknown) => T)
        +

        Validates the JSONRPC messages, so you can select for a + specific type of message

        +
        +
          +
        • +
            +
          • (message: unknown): T
          • +
          • +
            +

            Parameters

            +
              +
            • +
              message: unknown
            +

            Returns T

      • +
      • +
        bufferByteLimit: number = ...
        +

        sets the number of bytes buffered before throwing an + error. This is used to avoid infinitely buffering the input.

        +
      +

      Returns TransformStream<Uint8Array, T | Uint8Array>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.parseJSONRPCMessage.html b/docs/functions/utils.parseJSONRPCMessage.html new file mode 100644 index 0000000..3da1da5 --- /dev/null +++ b/docs/functions/utils.parseJSONRPCMessage.html @@ -0,0 +1,84 @@ +parseJSONRPCMessage | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function parseJSONRPCMessage

    +
    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.parseJSONRPCRequest.html b/docs/functions/utils.parseJSONRPCRequest.html new file mode 100644 index 0000000..ddf40db --- /dev/null +++ b/docs/functions/utils.parseJSONRPCRequest.html @@ -0,0 +1,84 @@ +parseJSONRPCRequest | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function parseJSONRPCRequest

    +
    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.parseJSONRPCRequestMessage.html b/docs/functions/utils.parseJSONRPCRequestMessage.html new file mode 100644 index 0000000..58541b4 --- /dev/null +++ b/docs/functions/utils.parseJSONRPCRequestMessage.html @@ -0,0 +1,84 @@ +parseJSONRPCRequestMessage | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function parseJSONRPCRequestMessage

    +
    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.parseJSONRPCRequestNotification.html b/docs/functions/utils.parseJSONRPCRequestNotification.html new file mode 100644 index 0000000..c29c52c --- /dev/null +++ b/docs/functions/utils.parseJSONRPCRequestNotification.html @@ -0,0 +1,84 @@ +parseJSONRPCRequestNotification | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function parseJSONRPCRequestNotification

    +
    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.parseJSONRPCResponse.html b/docs/functions/utils.parseJSONRPCResponse.html new file mode 100644 index 0000000..1599a40 --- /dev/null +++ b/docs/functions/utils.parseJSONRPCResponse.html @@ -0,0 +1,84 @@ +parseJSONRPCResponse | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function parseJSONRPCResponse

    +
    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.parseJSONRPCResponseError.html b/docs/functions/utils.parseJSONRPCResponseError.html new file mode 100644 index 0000000..d7baa6e --- /dev/null +++ b/docs/functions/utils.parseJSONRPCResponseError.html @@ -0,0 +1,79 @@ +parseJSONRPCResponseError | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function parseJSONRPCResponseError

    +
    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.parseJSONRPCResponseResult.html b/docs/functions/utils.parseJSONRPCResponseResult.html new file mode 100644 index 0000000..1f5bb11 --- /dev/null +++ b/docs/functions/utils.parseJSONRPCResponseResult.html @@ -0,0 +1,84 @@ +parseJSONRPCResponseResult | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function parseJSONRPCResponseResult

    +
    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.promise.html b/docs/functions/utils.promise.html new file mode 100644 index 0000000..9c5bc01 --- /dev/null +++ b/docs/functions/utils.promise.html @@ -0,0 +1,79 @@ +promise | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function promise

    +
    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.replacer.html b/docs/functions/utils.replacer.html new file mode 100644 index 0000000..034cdc5 --- /dev/null +++ b/docs/functions/utils.replacer.html @@ -0,0 +1,94 @@ +replacer | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function replacer

    +
    +
      + +
    • +

      The replacer function to customize the serialization process.

      +
      +
      +

      Parameters

      +
        +
      • +
        keyToRemove: any
      +

      Returns ((key: any, value: any) => any)

      +
        +
      • +
          +
        • (key: any, value: any): any
        • +
        • +
          +

          Parameters

          +
            +
          • +
            key: any
          • +
          • +
            value: any
          +

          Returns any

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.sleep.html b/docs/functions/utils.sleep.html new file mode 100644 index 0000000..f12ee57 --- /dev/null +++ b/docs/functions/utils.sleep.html @@ -0,0 +1,79 @@ +sleep | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function sleep

    +
    +
      + +
    • +
      +

      Parameters

      +
        +
      • +
        ms: number
      +

      Returns Promise<void>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/functions/utils.toError.html b/docs/functions/utils.toError.html new file mode 100644 index 0000000..c9f3581 --- /dev/null +++ b/docs/functions/utils.toError.html @@ -0,0 +1,91 @@ +toError | js-rpc
    +
    + +
    +
    +
    +
    + +

    Function toError

    +
    +
      + +
    • +

      Deserializes an error response object into an ErrorRPCRemote instance.

      + +

      Returns

      The deserialized ErrorRPCRemote instance.

      + +

      Throws

      If the errorResponse object is invalid.

      +
      +
      +

      Parameters

      +
        +
      • +
        errorResponse: any
        +

        The error response object.

        +
      • +
      • +
        Optional metadata: any
        +

        Optional metadata for the deserialized error.

        +
      +

      Returns ErrorRPCRemote<any>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..56393b2 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,91 @@ +js-rpc
    +
    + +
    +
    +
    +
    +

    js-rpc

    +
    + +

    js-rpc

    +
    +

    staging:pipeline status +master:pipeline status

    + + +

    Installation

    +
    +
    npm install --save @matrixai/rpc
    +
    + + +

    Development

    +
    +

    Run nix-shell, and once you're inside, you can use:

    +
    # install (or reinstall packages from package.json)
    npm install
    # build the dist
    npm run build
    # run the repl (this allows you to import from ./src)
    npm run ts-node
    # run the tests
    npm run test
    # lint the source code
    npm run lint
    # automatically fix the source
    npm run lintfix +
    + + +

    Docs Generation

    +
    +
    npm run docs
    +
    +

    See the docs at: https://matrixai.github.io/js-rpc/

    + + +

    Publishing

    +
    +

    Publishing is handled automatically by the staging pipeline.

    +

    Prerelease:

    +
    # npm login
    npm version prepatch --preid alpha # premajor/preminor/prepatch
    git push --follow-tags +
    +

    Release:

    +
    # npm login
    npm version patch # major/minor/patch
    git push --follow-tags +
    +

    Manually:

    +
    # npm login
    npm version patch # major/minor/patch
    npm run build
    npm publish --access public
    git push
    git push --tags +
    +

    Domains Diagram: +diagram_encapuslated.svg

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/interfaces/types.RPCStream.html b/docs/interfaces/types.RPCStream.html new file mode 100644 index 0000000..04765ef --- /dev/null +++ b/docs/interfaces/types.RPCStream.html @@ -0,0 +1,135 @@ +RPCStream | js-rpc
    +
    + +
    +
    +
    +
    + +

    Interface RPCStream<R, W, M>

    +
    +

    This interface extends the ReadableWritablePair with a method to cancel +the connection. It also includes some optional generic metadata. This is +mainly used as the return type for the StreamFactory. But the interface +can be propagated across the RPC system.

    +
    +
    +

    Type Parameters

    +
    +
    +

    Hierarchy

    +
      +
    • ReadableWritablePair<R, W> +
        +
      • RPCStream
    +
    +
    +
    + +
    +
    +

    Properties

    +
    +
    +

    Properties

    +
    + +
    cancel: ((reason?: any) => void)
    +
    +

    Type declaration

    +
      +
    • +
        +
      • (reason?: any): void
      • +
      • +
        +

        Parameters

        +
          +
        • +
          Optional reason: any
        +

        Returns void

    +
    + +
    meta?: M
    +
    + +
    readable: ReadableStream<R>
    +
    + +
    writable: WritableStream<W>
    +

    Provides a convenient, chainable way of piping this readable stream +through a transform stream (or any other { writable, readable } +pair). It simply pipes the stream into the writable side of the +supplied pair, and returns the readable side for further use.

    +

    Piping a stream will lock it for the duration of the pipe, preventing +any other consumer from acquiring a reader.

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/modules.html b/docs/modules.html new file mode 100644 index 0000000..a33aa21 --- /dev/null +++ b/docs/modules.html @@ -0,0 +1,65 @@ +js-rpc
    +
    + +
    +
    +
    +
    +

    js-rpc

    +
    +
    +

    Index

    +
    +

    Namespaces

    +
    +
    +

    Classes

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/modules/callers.html b/docs/modules/callers.html new file mode 100644 index 0000000..ed2a813 --- /dev/null +++ b/docs/modules/callers.html @@ -0,0 +1,69 @@ +callers | js-rpc
    +
    + +
    +
    +
    +
    + +

    Namespace callers

    +
    +
    +

    Index

    +
    +

    Classes

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/modules/errors.html b/docs/modules/errors.html new file mode 100644 index 0000000..792d256 --- /dev/null +++ b/docs/modules/errors.html @@ -0,0 +1,109 @@ +errors | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/modules/events.html b/docs/modules/events.html new file mode 100644 index 0000000..ab56070 --- /dev/null +++ b/docs/modules/events.html @@ -0,0 +1,93 @@ +events | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/modules/handlers.html b/docs/modules/handlers.html new file mode 100644 index 0000000..e533996 --- /dev/null +++ b/docs/modules/handlers.html @@ -0,0 +1,69 @@ +handlers | js-rpc
    +
    + +
    +
    +
    +
    + +

    Namespace handlers

    +
    +
    +

    Index

    +
    +

    Classes

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/modules/types.html b/docs/modules/types.html new file mode 100644 index 0000000..c93c650 --- /dev/null +++ b/docs/modules/types.html @@ -0,0 +1,112 @@ +types | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/modules/utils.html b/docs/modules/utils.html new file mode 100644 index 0000000..63a8371 --- /dev/null +++ b/docs/modules/utils.html @@ -0,0 +1,91 @@ +utils | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.ClientHandlerImplementation.html b/docs/types/types.ClientHandlerImplementation.html new file mode 100644 index 0000000..1c89f3f --- /dev/null +++ b/docs/types/types.ClientHandlerImplementation.html @@ -0,0 +1,86 @@ +ClientHandlerImplementation | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.ClientManifest.html b/docs/types/types.ClientManifest.html new file mode 100644 index 0000000..49c23e9 --- /dev/null +++ b/docs/types/types.ClientManifest.html @@ -0,0 +1,81 @@ +ClientManifest | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias ClientManifest

    +
    ClientManifest: Record<string, Caller>
    +

    Contains the Caller classes that defines the types for the client callers.

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.ContainerType.html b/docs/types/types.ContainerType.html new file mode 100644 index 0000000..326e773 --- /dev/null +++ b/docs/types/types.ContainerType.html @@ -0,0 +1,79 @@ +ContainerType | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.DuplexHandlerImplementation.html b/docs/types/types.DuplexHandlerImplementation.html new file mode 100644 index 0000000..cc5741f --- /dev/null +++ b/docs/types/types.DuplexHandlerImplementation.html @@ -0,0 +1,86 @@ +DuplexHandlerImplementation | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias DuplexHandlerImplementation<I, O>

    +
    DuplexHandlerImplementation<I, O>: HandlerImplementation<AsyncIterable<I>, AsyncIterable<O>>
    +
    +

    Type Parameters

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.HandlerImplementation.html b/docs/types/types.HandlerImplementation.html new file mode 100644 index 0000000..209adaa --- /dev/null +++ b/docs/types/types.HandlerImplementation.html @@ -0,0 +1,116 @@ +HandlerImplementation | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias HandlerImplementation<I, O>

    +
    HandlerImplementation<I, O>: ((input: I, cancel: ((reason?: any) => void), meta: Record<string, JSONValue> | undefined, ctx: ContextTimed) => O)
    +
    +

    Type Parameters

    +
      +
    • +

      I

    • +
    • +

      O

    +
    +

    Type declaration

    +
      +
    • +
        +
      • (input: I, cancel: ((reason?: any) => void), meta: Record<string, JSONValue> | undefined, ctx: ContextTimed): O
      • +
      • +
        +

        Parameters

        +
          +
        • +
          input: I
        • +
        • +
          cancel: ((reason?: any) => void)
          +
            +
          • +
              +
            • (reason?: any): void
            • +
            • +
              +

              Parameters

              +
                +
              • +
                Optional reason: any
              +

              Returns void

        • +
        • +
          meta: Record<string, JSONValue> | undefined
        • +
        • +
          ctx: ContextTimed
        +

        Returns O

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.HandlerType.html b/docs/types/types.HandlerType.html new file mode 100644 index 0000000..ea11a18 --- /dev/null +++ b/docs/types/types.HandlerType.html @@ -0,0 +1,79 @@ +HandlerType | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.IdGen.html b/docs/types/types.IdGen.html new file mode 100644 index 0000000..28661ad --- /dev/null +++ b/docs/types/types.IdGen.html @@ -0,0 +1,89 @@ +IdGen | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias IdGen

    +
    IdGen: (() => PromiseLike<string | number | null>)
    +
    +

    Type declaration

    +
      +
    • +
        +
      • (): PromiseLike<string | number | null>
      • +
      • +

        This is the type for the IdGenFunction. It is used to generate the request

        +
        +

        Returns PromiseLike<string | number | null>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.JSONRPCError.html b/docs/types/types.JSONRPCError.html new file mode 100644 index 0000000..2f9b384 --- /dev/null +++ b/docs/types/types.JSONRPCError.html @@ -0,0 +1,102 @@ +JSONRPCError | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias JSONRPCError

    +
    JSONRPCError: {
        code: number;
        data?: JSONValue;
        message: string;
        type: string | ErrorRPC<any>;
    }
    +

    This is a JSON RPC error object, it encodes the error data for the JSONRPCResponseError object.

    +
    +
    +

    Type declaration

    +
      +
    • +
      code: number
      +

      A Number that indicates the error type that occurred. + This MUST be an integer.

      +
    • +
    • +
      Optional data?: JSONValue
      +

      A Primitive or Structured value that contains additional information about the error. + This may be omitted. + The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.).

      +
    • +
    • +
      message: string
      +

      A String providing a short description of the error. + The message SHOULD be limited to a concise single sentence.

      +
    • +
    • +
      type: string | ErrorRPC<any>
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.JSONRPCMessage.html b/docs/types/types.JSONRPCMessage.html new file mode 100644 index 0000000..18f8870 --- /dev/null +++ b/docs/types/types.JSONRPCMessage.html @@ -0,0 +1,87 @@ +JSONRPCMessage | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias JSONRPCMessage<T>

    +
    JSONRPCMessage<T>: JSONRPCRequest<T> | JSONRPCResponse<T>
    +

    This is a JSON RPC Message object. This is top level and can be any kind of +message.

    +
    +
    +

    Type Parameters

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.JSONRPCRequest.html b/docs/types/types.JSONRPCRequest.html new file mode 100644 index 0000000..6bc279f --- /dev/null +++ b/docs/types/types.JSONRPCRequest.html @@ -0,0 +1,87 @@ +JSONRPCRequest | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias JSONRPCRequest<T>

    + +

    This is the JSON RPC Request object. It can be a request message or +notification.

    +
    +
    +

    Type Parameters

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.JSONRPCRequestMessage.html b/docs/types/types.JSONRPCRequestMessage.html new file mode 100644 index 0000000..7c8bd11 --- /dev/null +++ b/docs/types/types.JSONRPCRequestMessage.html @@ -0,0 +1,110 @@ +JSONRPCRequestMessage | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias JSONRPCRequestMessage<T>

    +
    JSONRPCRequestMessage<T>: {
        id: string | number | null;
        jsonrpc: "2.0";
        method: string;
        params?: T;
    }
    +

    This is the JSON RPC request object. this is the generic message type used for the RPC.

    +
    +
    +

    Type Parameters

    +
    +
    +

    Type declaration

    +
      +
    • +
      id: string | number | null
      +

      An identifier established by the Client that MUST contain a String, Number, or NULL value if included. + If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers + SHOULD NOT contain fractional parts [2]

      +
    • +
    • +
      jsonrpc: "2.0"
      +

      A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0"

      +
    • +
    • +
      method: string
      +

      A String containing the name of the method to be invoked. Method names that begin with the word rpc followed by a + period character (U+002E or ASCII 46) are reserved for rpc-internal methods and extensions and MUST NOT be used + for anything else.

      +
    • +
    • +
      Optional params?: T
      +

      A Structured value that holds the parameter values to be used during the invocation of the method. + This member MAY be omitted.

      +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.JSONRPCRequestNotification.html b/docs/types/types.JSONRPCRequestNotification.html new file mode 100644 index 0000000..20739d2 --- /dev/null +++ b/docs/types/types.JSONRPCRequestNotification.html @@ -0,0 +1,105 @@ +JSONRPCRequestNotification | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias JSONRPCRequestNotification<T>

    +
    JSONRPCRequestNotification<T>: {
        jsonrpc: "2.0";
        method: string;
        params?: T;
    }
    +

    This is the JSON RPC notification object. this is used for a request that +doesn't expect a response.

    +
    +
    +

    Type Parameters

    +
    +
    +

    Type declaration

    +
      +
    • +
      jsonrpc: "2.0"
      +

      A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0"

      +
    • +
    • +
      method: string
      +

      A String containing the name of the method to be invoked. Method names that begin with the word rpc followed by a + period character (U+002E or ASCII 46) are reserved for rpc-internal methods and extensions and MUST NOT be used + for anything else.

      +
    • +
    • +
      Optional params?: T
      +

      A Structured value that holds the parameter values to be used during the invocation of the method. + This member MAY be omitted.

      +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.JSONRPCResponse.html b/docs/types/types.JSONRPCResponse.html new file mode 100644 index 0000000..5d17c1b --- /dev/null +++ b/docs/types/types.JSONRPCResponse.html @@ -0,0 +1,86 @@ +JSONRPCResponse | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias JSONRPCResponse<T>

    + +

    This is a JSON RPC response object. It can be a response result or error.

    +
    +
    +

    Type Parameters

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.JSONRPCResponseError.html b/docs/types/types.JSONRPCResponseError.html new file mode 100644 index 0000000..de3d80d --- /dev/null +++ b/docs/types/types.JSONRPCResponseError.html @@ -0,0 +1,102 @@ +JSONRPCResponseError | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias JSONRPCResponseError

    +
    JSONRPCResponseError: {
        error: JSONRPCError;
        id: string | number | null;
        jsonrpc: "2.0";
    }
    +

    This is the JSON RPC response Error object. It contains any errors that have +occurred when responding to a request.

    +
    +
    +

    Type declaration

    +
      +
    • +
      error: JSONRPCError
      +

      This member is REQUIRED on error. + This member MUST NOT exist if there was no error triggered during invocation. + The value for this member MUST be an Object as defined in section 5.1.

      +
    • +
    • +
      id: string | number | null
      +

      This member is REQUIRED. + It MUST be the same as the value of the id member in the Request Object. + If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request), + it MUST be Null.

      +
    • +
    • +
      jsonrpc: "2.0"
      +

      A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0".

      +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.JSONRPCResponseResult.html b/docs/types/types.JSONRPCResponseResult.html new file mode 100644 index 0000000..dda30fe --- /dev/null +++ b/docs/types/types.JSONRPCResponseResult.html @@ -0,0 +1,107 @@ +JSONRPCResponseResult | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias JSONRPCResponseResult<T>

    +
    JSONRPCResponseResult<T>: {
        id: string | number | null;
        jsonrpc: "2.0";
        result: T;
    }
    +

    This is the JSON RPC response result object. It contains the response data for a +corresponding request.

    +
    +
    +

    Type Parameters

    +
    +
    +

    Type declaration

    +
      +
    • +
      id: string | number | null
      +

      This member is REQUIRED. + It MUST be the same as the value of the id member in the Request Object. + If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request), + it MUST be Null.

      +
    • +
    • +
      jsonrpc: "2.0"
      +

      A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0".

      +
    • +
    • +
      result: T
      +

      This member is REQUIRED on success. + This member MUST NOT exist if there was an error invoking the method. + The value of this member is determined by the method invoked on the Server.

      +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.JSONValue.html b/docs/types/types.JSONValue.html new file mode 100644 index 0000000..7e82619 --- /dev/null +++ b/docs/types/types.JSONValue.html @@ -0,0 +1,79 @@ +JSONValue | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias JSONValue

    +
    JSONValue: {
        [key: string]: JSONValue | undefined;
    } | JSONValue[] | string | number | boolean | null | undefined
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.MapCallers.html b/docs/types/types.MapCallers.html new file mode 100644 index 0000000..9d2fa3d --- /dev/null +++ b/docs/types/types.MapCallers.html @@ -0,0 +1,84 @@ +MapCallers | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.MiddlewareFactory.html b/docs/types/types.MiddlewareFactory.html new file mode 100644 index 0000000..0fc5850 --- /dev/null +++ b/docs/types/types.MiddlewareFactory.html @@ -0,0 +1,133 @@ +MiddlewareFactory | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias MiddlewareFactory<FR, FW, RR, RW>

    +
    MiddlewareFactory<FR, FW, RR, RW>: ((ctx: ContextTimed, cancel: ((reason?: any) => void), meta: Record<string, JSONValue> | undefined) => {
        forward: ReadableWritablePair<FR, FW>;
        reverse: ReadableWritablePair<RR, RW>;
    })
    +
    +

    Type Parameters

    +
      +
    • +

      FR

    • +
    • +

      FW

    • +
    • +

      RR

    • +
    • +

      RW

    +
    +

    Type declaration

    +
      +
    • +
        +
      • (ctx: ContextTimed, cancel: ((reason?: any) => void), meta: Record<string, JSONValue> | undefined): {
            forward: ReadableWritablePair<FR, FW>;
            reverse: ReadableWritablePair<RR, RW>;
        }
      • +
      • +

        Middleware factory creates middlewares. +Each middleware is a pair of forward and reverse. +Each forward and reverse is a ReadableWritablePair. +The forward pair is used transform input from client to server. +The reverse pair is used to transform output from server to client. +FR, FW is the readable and writable types of the forward pair. +RR, RW is the readable and writable types of the reverse pair. +FW -> FR is the direction of data flow from client to server. +RW -> RR is the direction of data flow from server to client.

        +
        +
        +

        Parameters

        +
          +
        • +
          ctx: ContextTimed
        • +
        • +
          cancel: ((reason?: any) => void)
          +
            +
          • +
              +
            • (reason?: any): void
            • +
            • +
              +

              Parameters

              +
                +
              • +
                Optional reason: any
              +

              Returns void

        • +
        • +
          meta: Record<string, JSONValue> | undefined
        +

        Returns {
            forward: ReadableWritablePair<FR, FW>;
            reverse: ReadableWritablePair<RR, RW>;
        }

        +
          +
        • +
          forward: ReadableWritablePair<FR, FW>
        • +
        • +
          reverse: ReadableWritablePair<RR, RW>
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.POJO.html b/docs/types/types.POJO.html new file mode 100644 index 0000000..da4789e --- /dev/null +++ b/docs/types/types.POJO.html @@ -0,0 +1,84 @@ +POJO | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.PromiseDeconstructed.html b/docs/types/types.PromiseDeconstructed.html new file mode 100644 index 0000000..0519f66 --- /dev/null +++ b/docs/types/types.PromiseDeconstructed.html @@ -0,0 +1,115 @@ +PromiseDeconstructed | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias PromiseDeconstructed<T>

    +
    PromiseDeconstructed<T>: {
        p: Promise<T>;
        rejectP: ((reason?: any) => void);
        resolveP: ((value: T | PromiseLike<T>) => void);
    }
    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Type declaration

    +
      +
    • +
      p: Promise<T>
    • +
    • +
      rejectP: ((reason?: any) => void)
      +
        +
      • +
          +
        • (reason?: any): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Optional reason: any
          +

          Returns void

    • +
    • +
      resolveP: ((value: T | PromiseLike<T>) => void)
      +
        +
      • +
          +
        • (value: T | PromiseLike<T>): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            value: T | PromiseLike<T>
          +

          Returns void

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.RawHandlerImplementation.html b/docs/types/types.RawHandlerImplementation.html new file mode 100644 index 0000000..834562e --- /dev/null +++ b/docs/types/types.RawHandlerImplementation.html @@ -0,0 +1,79 @@ +RawHandlerImplementation | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.ServerHandlerImplementation.html b/docs/types/types.ServerHandlerImplementation.html new file mode 100644 index 0000000..c798344 --- /dev/null +++ b/docs/types/types.ServerHandlerImplementation.html @@ -0,0 +1,86 @@ +ServerHandlerImplementation | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.ServerManifest.html b/docs/types/types.ServerManifest.html new file mode 100644 index 0000000..7f70dee --- /dev/null +++ b/docs/types/types.ServerManifest.html @@ -0,0 +1,81 @@ +ServerManifest | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias ServerManifest

    +
    ServerManifest: Record<string, Handler>
    +

    Contains the handler Classes that defines the handling logic and types for the server handlers.

    +
    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.StreamFactory.html b/docs/types/types.StreamFactory.html new file mode 100644 index 0000000..7a45deb --- /dev/null +++ b/docs/types/types.StreamFactory.html @@ -0,0 +1,97 @@ +StreamFactory | js-rpc
    +
    + +
    +
    +
    +
    + +

    Type alias StreamFactory

    +
    StreamFactory: ((ctx: ContextTimed) => PromiseLike<RPCStream<Uint8Array, Uint8Array>>)
    +
    +

    Type declaration

    +
      +
    • +
        +
      • (ctx: ContextTimed): PromiseLike<RPCStream<Uint8Array, Uint8Array>>
      • +
      • +

        This is a factory for creating a RPCStream when making a RPC call. +The transport mechanism is a black box to the RPC system. So long as it is +provided as a RPCStream the RPC system should function. It is assumed that +the RPCStream communicates with an RPCServer.

        +
        +
        +

        Parameters

        +
          +
        • +
          ctx: ContextTimed
        +

        Returns PromiseLike<RPCStream<Uint8Array, Uint8Array>>

    +
    +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/docs/types/types.UnaryHandlerImplementation.html b/docs/types/types.UnaryHandlerImplementation.html new file mode 100644 index 0000000..ea799de --- /dev/null +++ b/docs/types/types.UnaryHandlerImplementation.html @@ -0,0 +1,86 @@ +UnaryHandlerImplementation | js-rpc
    +
    + +
    + +
    +

    Generated using TypeDoc

    +
    \ No newline at end of file diff --git a/package.json b/package.json index f9303d9..03921f1 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,16 @@ { - "name": "@matrixai/rpc", - "version": "0.0.1", + "name": "js-rpc", + "version": "0.1.0", "author": "Matrix AI", "contributors": [ - { - "name": "Aditya V" - }, - { - "name": "Roger Qiu" - } + "Aditya V", + "Roger Qiu" ], "description": "RPC for TypeScript/JavaScript Applications", "license": "Apache-2.0", "repository": { "type": "git", - "url": "https://github.com/MatrixAI/js-rpc.git" + "url": "git+https://github.com/MatrixAI/js-rpc.git" }, "main": "dist/index.js", "types": "dist/index.d.ts", @@ -31,6 +27,7 @@ "bench": "shx rm -rf ./benches/results && ts-node ./benches" }, "devDependencies": { + "@fast-check/jest": "^1.1.0", "@swc/core": "^1.3.62", "@swc/jest": "^0.2.26", "@types/jest": "^28.1.3", @@ -53,16 +50,27 @@ "ts-node": "^10.9.1", "tsconfig-paths": "^3.9.0", "typedoc": "^0.23.21", - "typescript": "^4.9.3", - "@fast-check/jest": "^1.1.0" + "typescript": "^4.9.3" }, "dependencies": { "@matrixai/async-init": "^1.9.4", "@matrixai/contexts": "^1.2.0", - "@matrixai/logger": "^3.1.0", "@matrixai/errors": "^1.2.0", "@matrixai/events": "^3.2.0", + "@matrixai/logger": "^3.1.0", "@streamparser/json": "^0.0.17", - "ix": "^5.0.0" - } + "ix": "^5.0.0", + "my-package": "^0.0.0" + }, + "bugs": { + "url": "https://github.com/MatrixAI/js-rpc/issues" + }, + "homepage": "https://github.com/MatrixAI/js-rpc#readme", + "directories": { + "doc": "docs", + "test": "tests" + }, + "keywords": [ + "rpc" + ] } From 33162c802164a711f7c078fa2fb66a0804da1603 Mon Sep 17 00:00:00 2001 From: Aditya <38064122+bettercallav@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:16:17 +1000 Subject: [PATCH 11/12] fix: think I mightve messed something up in last push --- package.json | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 03921f1..f9303d9 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,20 @@ { - "name": "js-rpc", - "version": "0.1.0", + "name": "@matrixai/rpc", + "version": "0.0.1", "author": "Matrix AI", "contributors": [ - "Aditya V", - "Roger Qiu" + { + "name": "Aditya V" + }, + { + "name": "Roger Qiu" + } ], "description": "RPC for TypeScript/JavaScript Applications", "license": "Apache-2.0", "repository": { "type": "git", - "url": "git+https://github.com/MatrixAI/js-rpc.git" + "url": "https://github.com/MatrixAI/js-rpc.git" }, "main": "dist/index.js", "types": "dist/index.d.ts", @@ -27,7 +31,6 @@ "bench": "shx rm -rf ./benches/results && ts-node ./benches" }, "devDependencies": { - "@fast-check/jest": "^1.1.0", "@swc/core": "^1.3.62", "@swc/jest": "^0.2.26", "@types/jest": "^28.1.3", @@ -50,27 +53,16 @@ "ts-node": "^10.9.1", "tsconfig-paths": "^3.9.0", "typedoc": "^0.23.21", - "typescript": "^4.9.3" + "typescript": "^4.9.3", + "@fast-check/jest": "^1.1.0" }, "dependencies": { "@matrixai/async-init": "^1.9.4", "@matrixai/contexts": "^1.2.0", + "@matrixai/logger": "^3.1.0", "@matrixai/errors": "^1.2.0", "@matrixai/events": "^3.2.0", - "@matrixai/logger": "^3.1.0", "@streamparser/json": "^0.0.17", - "ix": "^5.0.0", - "my-package": "^0.0.0" - }, - "bugs": { - "url": "https://github.com/MatrixAI/js-rpc/issues" - }, - "homepage": "https://github.com/MatrixAI/js-rpc#readme", - "directories": { - "doc": "docs", - "test": "tests" - }, - "keywords": [ - "rpc" - ] + "ix": "^5.0.0" + } } From 112578369ae5297b5cd1dbc2c4bae0b78aa10501 Mon Sep 17 00:00:00 2001 From: Aditya <38064122+bettercallav@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:31:02 +1000 Subject: [PATCH 12/12] fix: windows pipeline fix --- .gitlab-ci.yml | 2 ++ scripts/choco-install.ps1 | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d450e97..75b28bb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -165,6 +165,8 @@ build:windows: - windows before_script: - mkdir -Force "$CI_PROJECT_DIR/tmp" + - Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 # Added line + script: - .\scripts\choco-install.ps1 - refreshenv diff --git a/scripts/choco-install.ps1 b/scripts/choco-install.ps1 index afe9ba4..68a7cbe 100755 --- a/scripts/choco-install.ps1 +++ b/scripts/choco-install.ps1 @@ -22,7 +22,7 @@ New-Item -Path "${PSScriptRoot}\..\tmp\chocolatey" -ItemType "directory" -ErrorA choco source add --name="cache" --source="${PSScriptRoot}\..\tmp\chocolatey" --priority=1 # Install nodejs v20.5.1 (will use cache if exists) -$nodejs = "nodejs.install" +$nodejs = "nodejs" choco install "$nodejs" --version="20.5.1" --require-checksums -y # Internalise nodejs to cache if doesn't exist if ( -not (Test-Path -Path "${PSScriptRoot}\..\tmp\chocolatey\$nodejs\$nodejs.20.5.1.nupkg" -PathType Leaf) ) {
    +